#!/usr/bin/env python ### spianostaff.py -- """\ StevePianoStaff -- Spreads notes of a single melody over two staves. """ from abjad import * def sum_durations( measure ): """\ Add the "duration.written" of all the notes, rests, skips in a measure. It looks like there's an Abjad call for not only this, but also for what I *should have* done. """ return sum( item.duration.written for item in measure ) def voice_measures_append( voice, meter, item ): """\ Add item to last measure in voice, adding a measure if necessary. voice actually only need be a Container, but it must contain measures. """ if len( voice ) == 0: last_measure_fullness = meter.duration else: last_measure_fullness = sum_durations( voice[ -1 ] ) if last_measure_fullness == meter.duration: voice.append( AnonymousMeasure( ) ) voice[ -1 ].append( item ) class StevePianoStaff: """\ Contains a PianoStaff with treble and bass cleffs, with a fixed meter (time signature), and a single melody line that moves between the staves, or at least looks as if it does. """ def __init__( self, meter, notes ): self.meter = Meter( meter ) self.voices = [ Voice( [ RigidMeasure(meter) ] ) for i in range(2) ] self.p = PianoStaff( [ Staff( [v] ) for v in self.voices ] ) self.p[1].clef.forced = Clef('bass') self.notes = [] self.midc = Pitch( 0 ) self.extend( notes ) self.currently_bottom = False def extend( self, notes ): for note in notes: self.append( note ) def append( self, note ): skip = Skip( note.duration.written ) if note.pitch < self.midc or note.pitch == self.midc and self.currently_bottom: self.append_top_bottom( [ skip, note ] ) self.currently_bottom = True else: self.append_top_bottom( [ note, skip ] ) self.currently_bottom = False self.notes.append( note ) def append_top_bottom( self, items ): for voice, item in zip( self.voices, items ): voice_measures_append( voice, self.meter, item ) def show( self, **kwargs ): show( self.p, **kwargs ) def play( self, **kwargs ): play( self.p, **kwargs ) def demo_StevePianoStaff(): length = 128 sp = StevePianoStaff( (4,4), [ Note( randint( -19, 19 ), (1,8) ) for i in range( length ) ] ) sp.show( title="Random Melody" ) # sp.play( ) if __name__ == "__main__": from random import * demo_StevePianoStaff()