def testJoinPartStaffsE(self): ''' Measure numbers existing only in certain PartStaffs: don't collapse together ''' from music21 import corpus from music21 import layout sch = corpus.parse('schoenberg/opus19', 2) s = stream.Score() ps1 = stream.PartStaff() ps2 = stream.PartStaff() s.append(ps1) s.append(ps2) s.insert(0, layout.StaffGroup([ps1, ps2])) m1 = sch.parts[0].measure(1) # RH m2 = sch.parts[1].measure(2) # LH m3 = sch.parts[0].measure(3) # RH ps1.append(m1) ps1.append(m3) ps2.insert(m1.offset, m2) root = self.getET(s) m1tag, m2tag, m3tag = root.findall('part/measure') self.assertEqual({staff.text for staff in m1tag.findall('note/staff')}, {'1'}) self.assertEqual({staff.text for staff in m2tag.findall('note/staff')}, {'2'}) self.assertEqual({staff.text for staff in m3tag.findall('note/staff')}, {'1'})
def testMultipleInstrumentsPiano(self): ps1 = stream.PartStaff([ stream.Measure( [instrument.ElectricPiano(), note.Note(type='whole')]), stream.Measure( [instrument.ElectricOrgan(), note.Note(type='whole')]), stream.Measure([instrument.Piano(), note.Note(type='whole')]), ]) ps2 = stream.PartStaff([ stream.Measure([instrument.Vocalist(), note.Note(type='whole')]), stream.Measure([note.Note(type='whole')]), stream.Measure([note.Note(type='whole')]), ]) sg = layout.StaffGroup([ps1, ps2]) s = stream.Score([ps1, ps2, sg]) scEx = ScoreExporter(s) tree = scEx.parse() self.assertEqual( [el.text for el in tree.findall('.//instrument-name')], ['Electric Piano', 'Voice', 'Electric Organ', 'Piano']) self.assertEqual(len(tree.findall('.//measure/note/instrument')), 6)
def testJoinPartStaffsB(self): ''' Gapful first PartStaff, ensure <backup> in second PartStaff correct ''' from music21 import layout from music21 import note s = stream.Score() ps1 = stream.PartStaff() ps1.insert(0, note.Note()) # Gap ps1.insert(3, note.Note()) ps2 = stream.PartStaff() ps2.insert(0, note.Note()) s.append(ps1) s.append(ps2) s.insert(0, layout.StaffGroup([ps1, ps2])) root = self.getET(s) notes = root.findall('.//note') forward = root.find('.//forward') backup = root.find('.//backup') amountToBackup = ( int(notes[0].find('duration').text) + int(forward.find('duration').text) + int(notes[1].find('duration').text) ) self.assertEqual(int(backup.find('duration').text), amountToBackup)
def testJoinPartStaffsH(self): ''' Overlapping PartStaffs cannot be guaranteed to export correctly, so they fall back to the old export paradigm (no joinable groups). ''' from music21 import musicxml ps1 = stream.PartStaff(stream.Measure()) ps2 = stream.PartStaff(stream.Measure()) ps3 = stream.PartStaff(stream.Measure()) sg1 = StaffGroup([ps1, ps2]) sg2 = StaffGroup([ps1, ps3]) s = stream.Score([ps1, ps2, ps3, sg1, sg2]) SX = musicxml.m21ToXml.ScoreExporter(s) SX.scorePreliminaries() with self.assertWarns(MusicXMLWarning): SX.parsePartlikeScore() self.assertEqual(SX.joinableGroups(), [])
def testJoinPartStaffsC(self): ''' First PartStaff longer than second ''' from music21 import layout from music21 import note s = stream.Score() ps1 = stream.PartStaff() ps1.repeatAppend(note.Note(), 8) ps1.makeNotation(inPlace=True) # makeNotation to freeze notation s.insert(0, ps1) ps2 = stream.PartStaff() ps2.repeatAppend(note.Note(), 4) ps2.makeNotation(inPlace=True) # makeNotation to freeze notation s.insert(0, ps2) s.insert(0, layout.StaffGroup([ps1, ps2])) root = self.getET(s) measures = root.findall('.//measure') notes = root.findall('.//note') self.assertEqual(len(measures), 2) self.assertEqual(len(notes), 12)
def testMeterChanges(self): from music21 import layout from music21 import meter from music21 import note ps1 = stream.PartStaff() ps2 = stream.PartStaff() sg = layout.StaffGroup([ps1, ps2]) s = stream.Score([ps1, ps2, sg]) for ps in ps1, ps2: ps.insert(0, meter.TimeSignature('3/1')) ps.repeatAppend(note.Note(type='whole'), 6) ps.makeNotation(inPlace=True) # makes measures ps[stream.Measure][1].insert(meter.TimeSignature('4/1')) root = self.getET(s) # Just two <attributes> tags, a 3/1 in measure 1 and a 4/1 in measure 2 self.assertEqual(len(root.findall('part/measure/attributes/time')), 2) # Edge cases -- no expectation of correctness, just don't crash ps1[stream.Measure].last().number = 0 # was measure 2 root = self.getET(s) self.assertEqual(len(root.findall('part/measure/attributes/time')), 3)
def testJoinPartStaffsD(self): ''' Same example as testJoinPartStaffsC but switch the hands: second PartStaff longer than first ''' from music21 import layout from music21 import note s = stream.Score() ps1 = stream.PartStaff() ps1.repeatAppend(note.Note(), 8) ps1.makeNotation(inPlace=True) # makeNotation to freeze notation ps2 = stream.PartStaff() ps2.repeatAppend(note.Note(), 4) ps2.makeNotation(inPlace=True) # makeNotation to freeze notation s.insert(0, ps2) s.insert(0, ps1) s.insert(0, layout.StaffGroup([ps2, ps1])) root = self.getET(s) measures = root.findall('.//measure') notes = root.findall('.//note') # from music21.musicxml.helpers import dump # dump(root) self.assertEqual(len(measures), 2) self.assertEqual(len(notes), 12)
def realize(self): # Would make sense to insert parts in __init__ but breaks music21 when writing for _i in range(2): self.insert(0, stream.PartStaff()) halfnote_chances = { len(self.possible_chords) - 1: 0.9, len(self.possible_chords) - 2: 0.65, len(self.possible_chords) - 3: 0.65, } past_halfnotes = 0 for i, poss_chord in enumerate( self.possible_chords): # For each chord in the composition b = choice(poss_chord.b_pitches) t = choice(poss_chord.filter_t(b)) a = choice(poss_chord.filter_a(b, t)) s = choice(poss_chord.filter_s(b, t, a)) current_chord_treb = chord.Chord([a, s]) current_chord_bass = chord.Chord([b, t]) # Calculate duration offset from beginneing b/c Stream.append() cannot always get it right extra_offset_treb = extra_offset_bass = 0 + past_halfnotes if i in halfnote_chances: # If the current chord may become a half note if random() < halfnote_chances[i]: current_chord_bass.duration.type = "half" current_chord_treb.duration.type = "half" past_halfnotes += 1 elif random( ) < 0.2 and i > 0: # If this chord is not a potential half note dotted-quarter/eigth current_chord_treb.duration.quarterLength -= 0.5 self.elements[0][i - 1].duration.quarterLength += 0.5 extra_offset_treb += 0.5 # elif random() < 0.15 and i > 0: # Bass eigth/dotted-quarter # current_chord_bass.duration.quarterLength += 0.5 # self.elements[1][i-1].duration.quarterLength -= 0.5 # extra_offset_bass -= 0.5 self.elements[0].insert(i + extra_offset_treb, current_chord_treb) self.elements[1].insert(i + extra_offset_bass, current_chord_bass)