def test_simple_tuplet_reverse(self): print('test simple tuplet reverse') a = Note(DiatonicPitch(3, 'a'), Duration(1, 8)) b = Note(DiatonicPitch(3, 'b'), Duration(1, 8)) c = Note(DiatonicPitch(3, 'c'), Duration(1, 8)) d = Note(DiatonicPitch(3, 'd'), Duration(1, 8)) tuplet = Tuplet(Duration(1, 8), 3, [a, b, c, d]) print(tuplet) tuplet.reverse() print(tuplet) notes = tuplet.get_all_notes() assert notes is not None assert len(notes) == 4 assert notes[0].diatonic_pitch == DiatonicPitch(3, 'd') assert notes[1].diatonic_pitch == DiatonicPitch(3, 'c') assert notes[2].diatonic_pitch == DiatonicPitch(3, 'b') assert notes[3].diatonic_pitch == DiatonicPitch(3, 'a') assert notes[0].relative_position == Offset(0) assert notes[1].relative_position == Offset(3, 32) assert notes[2].relative_position == Offset(3, 16) assert notes[3].relative_position == Offset(9, 32)
def test_line_structures(self): print('----- test line structures -----') source_instance_expression = '{<C-Major:I> iC:4 D E F G A B C:5 D E F G} }' lge = LineGrammarExecutor() source_instance_line, source_instance_hct = lge.parse(source_instance_expression) notes = source_instance_line.get_all_notes() line = Line() line.pin(notes[0], Offset(Fraction(1, 2))) line.pin(notes[1], Offset(Fraction(3, 4))) line1 = Line() line1.pin(notes[3], Offset(Fraction(1, 4))) line1.pin(notes[4], Offset(Fraction(1, 2))) line.pin(line1, Offset(Fraction(2))) lite_score = TestTDilation.create_score_1(line, source_instance_hct, 'piano', (4, 4, 'swww')) trans = TDilation(lite_score) new_score = trans.apply(Fraction(2), False, True) all_notes = new_score.line.get_all_notes() assert all_notes[2].get_absolute_position().position == Fraction(9, 2) print(line) print(new_score.line)
def test_add_note_at_lower_level(self): print('start test_add_note_at_lower_level') sub_beam = Beam([ Note(DiatonicPitch(2, 'c'), Duration(1, 8)), Note(DiatonicPitch(2, 'd'), Duration(1, 8)) ]) beam = Beam([ Note(DiatonicPitch(3, 'c'), Duration(1, 8)), sub_beam, Note(DiatonicPitch(3, 'd'), Duration(1, 8)) ]) AbstractNote.print_structure(beam) notes = beam.get_all_notes() assert len(notes) == 4 assert beam.sub_notes[1].duration == Duration(1, 8) assert beam.sub_notes[1].relative_position == Offset(1, 8) assert beam.sub_notes[1].sub_notes[1].duration == Duration(1, 16) assert beam.sub_notes[1].sub_notes[1].relative_position == Offset( 1, 16) sub_beam.add(Note(DiatonicPitch(2, 'c'), Duration(1, 8)), 1) AbstractNote.print_structure(beam) assert beam.sub_notes[1].duration == Duration(3, 16) assert beam.sub_notes[1].relative_position == Offset(1, 8) assert beam.sub_notes[1].sub_notes[1].duration == Duration(1, 16) assert beam.sub_notes[1].sub_notes[1].relative_position == Offset( 1, 16)
def test_book_example(self): print('----- book_example -----') voice_line = Line() melody_line = Line() melody_1 = Line( [Note(DiatonicPitch(4, y), Duration(1, 8)) for y in 'aceg']) melody_2 = Line( [Note(DiatonicPitch(4, y), Duration(1, 8)) for y in 'cadg']) base_line = Line( [Note(DiatonicPitch(4, y), Duration(1, 4)) for y in 'dddddddd']) melody_line.pin(melody_1, Offset(1, 8)) melody_line.pin(melody_2, Offset(1, 4)) voice_line.pin(melody_line) voice_line.pin(base_line) print(voice_line) all_notes = voice_line.get_all_notes() print('... pinned notes ...') for n in all_notes: print('({0}) : {1}'.format(n.get_absolute_position(), n.diatonic_pitch)) print('... end pinned notes ...') print('End test_pin')
def test_simple_beam_reverse(self): print('test simple beam reverse') a = Note(DiatonicPitch(3, 'a'), Duration(1, 8)) b = Note(DiatonicPitch(3, 'b'), Duration(1, 8)) c = Note(DiatonicPitch(3, 'c'), Duration(1, 8)) d = Note(DiatonicPitch(3, 'd'), Duration(1, 8)) beam = Beam([a, b, c, d]) print(beam) beam.reverse() print(beam) notes = beam.get_all_notes() assert notes is not None assert len(notes) == 4 assert notes[0].diatonic_pitch == DiatonicPitch(3, 'd') assert notes[1].diatonic_pitch == DiatonicPitch(3, 'c') assert notes[2].diatonic_pitch == DiatonicPitch(3, 'b') assert notes[3].diatonic_pitch == DiatonicPitch(3, 'a') assert notes[0].relative_position == Offset(0) assert notes[1].relative_position == Offset(1, 8) assert notes[2].relative_position == Offset(1, 4) assert notes[3].relative_position == Offset(3, 8)
def test_nested_notes(self): note1 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'e'), Duration(1, 16)) sub_beam = Beam([note1, note2, note3]) beam = Beam() beam.append(Note(DiatonicPitch(4, 'f'), Duration(1, 8))) beam.append(sub_beam) beam.append(Note(DiatonicPitch(4, 'g'), Duration(1, 8))) print(beam) notes = beam.get_all_notes() assert len(notes) == 5 assert notes[0].diatonic_pitch == DiatonicPitch(4, 'f') assert notes[1].diatonic_pitch == DiatonicPitch(4, 'c') assert notes[2].diatonic_pitch == DiatonicPitch(4, 'd') assert notes[3].diatonic_pitch == DiatonicPitch(4, 'e') assert notes[4].diatonic_pitch == DiatonicPitch(4, 'g') assert notes[0].relative_position == Offset(0) assert notes[1].relative_position == Offset(0) assert notes[2].relative_position == Offset(1, 16) assert notes[3].relative_position == Offset(1, 8) assert notes[4].relative_position == Offset(9, 32) TestBeam.print_all_notes(notes) notes = sub_beam.get_all_notes() TestBeam.print_all_notes(notes) b = Beam() b.append(beam) notes = sub_beam.get_all_notes() TestBeam.print_all_notes(notes) assert notes[0].duration == Duration(1, 32) assert str(notes[0].diatonic_pitch) == 'C:4' sub_beam_prime = sub_beam.clone() notes = sub_beam_prime.get_all_notes() TestBeam.print_all_notes(notes) assert notes[0].duration == Duration(1, 8) assert str(notes[0].diatonic_pitch) == 'C:4' beam_prime = beam.clone() notes = beam_prime.get_all_notes() TestBeam.print_all_notes(notes) assert notes[0].duration == Duration(1, 8) assert str(notes[0].diatonic_pitch) == 'F:4' b_prime = b.clone() notes = b_prime.get_all_notes() TestBeam.print_all_notes(notes) assert notes[0].duration == Duration(1, 16) assert str(notes[0].diatonic_pitch) == 'F:4'
def test_two_voices(self): print('test two voices') c = InstrumentCatalog.instance() violin = c.get_instrument("violin") note0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) note1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) tuplet = Tuplet(Duration(1, 8), 2, [note0, note1, note2]) note3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) note4 = Note(DiatonicPitch(4, 'e'), Duration(1, 8)) subbeam = Beam([note3, note4]) beam = Beam(subbeam) line1 = Line([tuplet, beam]) print(line1) notee0 = Note(DiatonicPitch(5, 'a'), Duration(1, 8)) notee1 = Note(DiatonicPitch(5, 'b'), Duration(1, 8), 1) notee2 = Note(DiatonicPitch(5, 'c'), Duration(1, 8)) notee3 = Note(DiatonicPitch(5, 'd'), Duration(1, 16)) line2 = Line([notee0, notee1, notee2]) line2.pin(notee3, Offset(1, 2)) print(line2) voice = Voice(violin) voice.pin(line1, Offset(1, 4)) voice.pin(line2, Offset(0, 1)) print(voice) interval = Interval(Position(1, 2), Position(1)) notes = voice.get_notes_by_interval(interval) assert len(notes) == 3 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('D:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('E:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('D:5')) interval = Interval(Position(1, 4), Position(7, 16)) notes = voice.get_notes_by_interval(interval) assert len(notes) == 5 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('C:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:5')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('C:5'))
def convert_line(line, tempo=Tempo(60, Duration(1, 4)), time_signature=TimeSignature(4, Duration(1, 4)), channel_assignments=None, fps=42100): """ Static method to convert a Line to a midi file Args: :param line: Class Line object :param tempo: Tempo for playback, default is 60 BPM tempo beat = quarter note :param time_signature: TimeSiganture on playback, default is 4 quarter notes :param channel_assignments: :param fps: frames per second setting """ score = Score() tempo_sequence = score.tempo_sequence tempo_sequence.add(TempoEvent(tempo, Position(0))) ts_sequence = score.time_signature_sequence ts_sequence.add(TimeSignatureEvent(time_signature, Position(0))) c = InstrumentCatalog.instance() piano = c.get_instrument("piano") piano_instrument_voice = InstrumentVoice(piano, 1) piano_voice = piano_instrument_voice.voice(0) piano_voice.pin(line, Offset(0)) score.add_instrument_voice(piano_instrument_voice) return ScoreToVstMidiConverter.convert_score(score, channel_assignments, fps)
def pin(self, note_structure, offset=Offset(0)): """ Given a note_structure (Line, Note, Tuplet, Beam), make it an immediate child to this line. If it is a list, the members are added in note sequence, with offset being adjusted appropriately. Args: note_structure: (List of Line, Note, Tuplet, Beam) to add offset: (Offset), of the first in list or given structure. """ if not isinstance(offset, Offset): raise Exception( 'Offset parameter in pin() must be of type Offset, not \'{0}\'.' .format(type(offset))) if isinstance(note_structure, list): for n in note_structure: self._append_note(n, offset) offset += n.duration else: self._append_note(note_structure, offset) # sort by relative offset Pins can happen any where, this helps maintains some sequential order to the line sorted(self.sub_notes, key=lambda n1: n1.relative_position) self.update(Line.LINE_NOTES_ADDED_EVENT, None, note_structure)
def upward_forward_reloc_layout(self, abstract_note): """ Called by Beam on Beam content alteration, it climbs the tree upward and to the right. making relative position adjustments along the way. It stops when it hits either a null parent or a tuplet. Since tuplets will not change size, there is no need to proceed higher up the tree. However, at that top tuplet level, it is appropriate to call Tuplet.rescale() as the lower contents have changed and can affect the tuplet's rescaling factor. Args: abstract_note: the affected child note of self.sub_notes which causes the relocataion layout. """ from structure.tuplet import Tuplet try: index = self.sub_notes.index(abstract_note) except ValueError: raise Exception('Could note location index for {0} in {1}'.format( abstract_note, type(self))) current_position = Offset(0) if index == 0 else \ self.sub_notes[index - 1].relative_position + self.sub_notes[index - 1].duration for i in range(index, len(self.sub_notes)): self.sub_notes[i].relative_position = current_position current_position += self.sub_notes[i].duration # Once size no longer changes, no need to propagate if self.parent is not None and not isinstance(self.parent, Tuplet): self.parent.upward_forward_reloc_layout(self) if self.parent is not None and isinstance(self.parent, Tuplet): self.parent.rescale()
def test_pin(self): print('----- test_pin -----') l1_notes = [Note(DiatonicPitch(4, y), Duration(1, 8)) for y in 'abcd'] l2_notes = [Note(DiatonicPitch(4, y), Duration(1, 8)) for y in 'efgab'] line = Line() line.pin(Line(l1_notes), Offset(1, 8)) line.pin(Line(l2_notes), Offset(1, 4)) all_notes = line.get_all_notes() print('... pinned notes ...') for n in all_notes: print('({0}) : {1}'.format(n.get_absolute_position(), n.diatonic_pitch)) print('... end pinned notes ...') print('End test_pin')
def test_multi_notes(self): note0 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note1 = Note(DiatonicPitch(4, 'd'), Duration(1, 8), 1) note2 = Note(DiatonicPitch(4, 'e'), Duration(1, 16)) beam = Beam([note0, note1, note2]) print(beam) assert beam.cardinality() == 3 notes = beam.get_all_notes() assert notes[0].diatonic_pitch == DiatonicPitch(4, 'c') assert notes[1].diatonic_pitch == DiatonicPitch(4, 'd') assert notes[2].diatonic_pitch == DiatonicPitch(4, 'e') assert beam.duration == Duration(3, 8) assert notes[0].relative_position == Offset(0) assert notes[1].relative_position == Offset(1, 8) assert notes[2].relative_position == Offset(5, 16) assert len(notes) == 3 TestBeam.print_all_notes(notes)
def test_simple_motif(self): line = Line() notes = [ Note(DiatonicPitch.parse('C:4'), Duration(1, 4)), Note(DiatonicPitch.parse('D:4'), Duration(1, 8)), Note(DiatonicPitch.parse('E:4'), Duration(1, 8)), Note(DiatonicPitch.parse('F#:4'), Duration(1, 2)), ] line.pin(notes) c = [ EqualPitchConstraint([notes[0], notes[2]]), NotEqualPitchConstraint([notes[1], notes[3]]) ] nm = Phrase(notes, c, 'B') print(nm) assert nm.name == 'B' actors = nm.actors assert len(actors) == 4 cc = nm.constraints assert isinstance(cc[0], EqualPitchConstraint) cc_a = cc[0].actors assert len(cc_a) == 2 assert cc_a[0] == actors[0] assert cc_a[1] == actors[2] assert isinstance(cc[1], NotEqualPitchConstraint) cc_b = cc[1].actors assert len(cc_a) == 2 assert cc_b[0] == actors[1] assert cc_b[1] == actors[3] assert 'F#:4' == str(actors[3].diatonic_pitch) # More notes for copy to: first_note = Note(DiatonicPitch.parse('C:3'), Duration(1, 4)) notes1 = [ first_note, Note(DiatonicPitch.parse('D:3'), Duration(1, 8)), Note(DiatonicPitch.parse('E:3'), Duration(1, 8)), Note(DiatonicPitch.parse('F#:3'), Duration(1, 2)), ] line.pin(notes1, Offset(2)) nm_clone = nm.copy_to(first_note) assert isinstance(nm_clone, Phrase) assert nm_clone.name == 'B' c_actors = nm_clone.actors assert len(c_actors) == 4 assert 'F#:3' == str(c_actors[3].diatonic_pitch)
def test_overlap_vs_start(self): c = InstrumentCatalog.instance() violin = c.get_instrument("violin") note0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) note1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) line = Line() line.pin(note0, Offset(1, 4)) line.pin(note1, Offset(3, 8)) line.pin(note2, Offset(1, 2)) line.pin(note3, Offset(5, 8)) voice = Voice(violin) voice.pin(line, Offset(0)) interval = Interval(Position(5, 16), Position(5, 8)) notes = voice.get_notes_by_interval(interval) assert len(notes) == 3 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('C:4')) notes = voice.get_notes_starting_in_interval(interval) assert len(notes) == 2 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('C:4')) notee0 = Note(DiatonicPitch(5, 'a'), Duration(1, 2)) notee1 = Note(DiatonicPitch(5, 'b'), Duration(1, 2)) line1 = Line() line1.pin([notee0, notee1], Offset(0)) voice.pin(line1, Offset(1, 4)) notes = voice.get_notes_by_interval(interval) assert len(notes) == 4 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('C:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:5')) notes = voice.get_notes_by_interval(interval, line1) assert len(notes) == 1 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:5')) notes = voice.get_notes_starting_in_interval(interval) assert len(notes) == 2 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('C:4')) notes = voice.get_notes_starting_in_interval( Interval(Position(1, 8), Position(3, 8)), line1) assert len(notes) == 1 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:5'))
def unpin(self, line): if not isinstance(line, Line): raise Exception('Voice can only unpin Line\'s, {0} received'.format(type(line))) if line not in self.__lines: raise Exception('Voice can only unpin lines it owns') self.__lines.remove(line) line.relative_position = Offset(0) line.deregister(self) self._remove_notes_from_tree(line.get_all_notes())
def test_add_notes_to_tuplet(self): c = InstrumentCatalog.instance() violin = c.get_instrument("violin") note0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) note1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) beam = Beam([note0, note1]) line = Line() line.pin(beam, Offset(1, 2)) voice = Voice(violin) voice.pin(line, Offset(0)) tuplet = Tuplet(Duration(1, 8), 3, [note2, note3]) beam.append(tuplet) notee0 = Note(DiatonicPitch(5, 'a'), Duration(1, 8)) tuplet.append(notee0) print(voice) notes = voice.get_notes_starting_in_interval( Interval(Position(1, 2), Position(5, 4))) assert len(notes) == 5 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:5')) beam_prime = beam.clone() notes = beam_prime.get_all_notes() AbstractNote.print_structure(beam_prime) assert notes[0].duration == Duration(1, 8) assert str(notes[0].diatonic_pitch) == 'A:4' line_prime = line.clone() notes = line_prime.get_all_notes() AbstractNote.print_structure(line_prime) assert notes[0].duration == Duration(1, 8) assert str(notes[0].diatonic_pitch) == 'A:4' assert notes[2].duration == Duration(1, 8) assert str(notes[2].diatonic_pitch) == 'C:4'
def test_tuplet_with_nested_beam(self): note1 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) n_list = [ Note(DiatonicPitch(3, 'c'), Duration(1, 8)), Note(DiatonicPitch(3, 'd'), Duration(1, 8)) ] add_beam = Beam(n_list) tuplet = Tuplet(Duration(1, 8), 2, [note1, add_beam, note2]) print(tuplet) AbstractNote.print_structure(tuplet) notes = tuplet.get_all_notes() assert len(notes) == 4 assert tuplet.sub_notes[0].duration == Duration(1, 16) assert tuplet.sub_notes[0].relative_position == Offset(0) assert tuplet.sub_notes[1].duration == Duration(1, 8) assert tuplet.sub_notes[1].relative_position == Offset(1, 16) assert tuplet.sub_notes[2].duration == Duration(1, 16) assert tuplet.sub_notes[2].relative_position == Offset(3, 16) assert notes[1].duration == Duration(1, 16) assert notes[1].relative_position == Offset(0) assert notes[2].duration == Duration(1, 16) assert notes[2].relative_position == Offset(1, 16) add_beam_prime = add_beam.clone() notes = add_beam_prime.get_all_notes() AbstractNote.print_structure(add_beam_prime) assert notes[0].duration == Duration(1, 8) assert str(notes[0].diatonic_pitch) == 'C:3' tuplet_prime = tuplet.clone() notes = tuplet_prime.get_all_notes() AbstractNote.print_structure(tuplet_prime) assert notes[0].duration == Duration(1, 16) assert str(notes[0].diatonic_pitch) == 'C:4' assert notes[1].duration == Duration(1, 16)
def tempo(self, position, next_event_position): """ Compute the tempo at a given position (re: TempoEventSequence) Args: position: The absolute position (Position) to evaluate at next_event_position: The position (Position) of the starting of the next event. Can be None is none exists. Returns: tempo numeric as bpm based on tempo beat """ return self.object.tempo(Offset(position.position - self.time.position), next_event_position - self.time if next_event_position else Duration(1))
def test_simple_tuplet(self): note1 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'e'), Duration(1, 8)) tuplet = Tuplet(Duration(1, 8), 2, [note1, note2, note3]) print(tuplet) AbstractNote.print_structure(tuplet) notes = tuplet.get_all_notes() assert len(notes) == 3 assert notes[0].diatonic_pitch == DiatonicPitch(4, 'c') assert notes[1].diatonic_pitch == DiatonicPitch(4, 'd') assert notes[2].diatonic_pitch == DiatonicPitch(4, 'e') assert notes[0].duration == Duration(1, 12) assert notes[1].duration == Duration(1, 12) assert notes[2].duration == Duration(1, 12) assert notes[0].relative_position == Offset(0) assert notes[1].relative_position == Offset(1, 12) assert notes[2].relative_position == Offset(1, 6)
def velocity(self, position, next_event_position): """ Compute the velocity at a given position (re: DynamicsEventSequence) Args: position: The absolute position (Position) to evaluate at next_event_position: The position (Position) of the starting of the next event. Can be None is none exists. Returns: velocity as numerics [0-127] typically """ return self.object.velocity(Offset(position.position - self.time.position), next_event_position - self.time if next_event_position else Duration(1))
def test_add_notes_to_line(self): c = InstrumentCatalog.instance() violin = c.get_instrument("violin") note0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) note1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) line = Line() line.pin(note0, Offset(1, 4)) line.pin(note1, Offset(3, 8)) line.pin(note2, Offset(1, 2)) line.pin(note3, Offset(5, 8)) voice = Voice(violin) voice.pin(line, Offset(0)) notee0 = Note(DiatonicPitch(5, 'a'), Duration(1, 8)) notee1 = Note(DiatonicPitch(5, 'b'), Duration(1, 8)) line.pin([notee0, notee1], Offset(3, 4)) notes = voice.get_notes_starting_in_interval( Interval(Position(5, 8), Position(2, 1))) assert len(notes) == 3 assert TestVoice.has_pitch(notes, DiatonicPitch.parse('D:4')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('A:5')) assert TestVoice.has_pitch(notes, DiatonicPitch.parse('B:5'))
def test_add_notes_to_two_level_line(self): score = Score() catalogue = InstrumentCatalog.instance() score.add_instrument_voice( InstrumentVoice(catalogue.get_instrument("violin"))) # 1 beat == 1 sec, 3/4 TS + 60 beats per minute, score.tempo_sequence.add(TempoEvent(Tempo(60), Position(0))) score.time_signature_sequence.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4)), Position(0))) violin_voice = score.get_instrument_voice("violin")[0] top_line = Line( [Note(DiatonicPitch(4, y), Duration(1, 8)) for y in 'afdecd']) violin_voice.voice(0).pin(top_line, Offset(0)) level1_line = Line( [Note(DiatonicPitch(5, y), Duration(1, 8)) for y in 'af']) top_line.pin(level1_line, Offset(2)) level2_line = Line( [Note(DiatonicPitch(6, y), Duration(1, 8)) for y in 'de']) level1_line.pin(level2_line, Offset(1))
def test_TBB_layers(self): print('start test_TBB_layers') sub_sub_beam = Beam([ Note(DiatonicPitch(2, 'c'), Duration(1, 8)), Note(DiatonicPitch(2, 'd'), Duration(1, 8)) ]) sub_beam = Beam([ Note(DiatonicPitch(3, 'c'), Duration(1, 8)), sub_sub_beam, Note(DiatonicPitch(3, 'd'), Duration(1, 8)) ]) AbstractNote.print_structure(sub_beam) note1 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) print('-----------') tuplet = Tuplet(Duration(1, 8), 2, [note1, sub_beam, note2]) AbstractNote.print_structure(tuplet) notes = tuplet.get_all_notes() assert len(notes) == 6 assert tuplet.sub_notes[1].duration == Duration(3, 20) assert tuplet.sub_notes[1].relative_position == Offset(1, 20) assert tuplet.sub_notes[1].sub_notes[1].duration == Duration(1, 20) assert tuplet.sub_notes[1].sub_notes[1].relative_position == Offset( 1, 20) sub_sub_beam.add(Note(DiatonicPitch(2, 'c'), Duration(1, 8)), 1) AbstractNote.print_structure(tuplet) assert tuplet.sub_notes[1].duration == Duration(7, 44) assert tuplet.sub_notes[1].relative_position == Offset(1, 22) assert tuplet.sub_notes[1].sub_notes[1].duration == Duration(3, 44) assert tuplet.sub_notes[1].sub_notes[1].relative_position == Offset( 1, 22) print('end test_TBB_layers')
def test_compute_with_minor_key(self): print('-- test_compute_with_minor_key ---') line = Line() f = GenericUnivariatePitchFunction( TestFitPitchToFunctionConstraint.sinasoidal, Position(0), Position(2)) v_notes = [ Note(DiatonicPitch.parse('A:4'), Duration(1, 16)) for _ in range(0, 33) ] for i in range(0, 33): line.pin(v_notes[i], Offset(i, 16)) constraint, lower_policy_context = \ TestFitPitchToFunctionConstraint.build_simple_constraint(v_notes[0], f, ModalityType.NaturalMinor, 'C', 'tV') constraints = list() constraints.append(constraint) for i in range(1, 33): c, _ = \ TestFitPitchToFunctionConstraint.build_simple_constraint(v_notes[i], f, ModalityType.NaturalMinor, 'C', 'tV') constraints.append(c) p_map = PMap() p_map[v_notes[0]] = ContextualNote(lower_policy_context) results = constraint.values(p_map, v_notes[0]) assert results is not None assert len(results) == 1 print(next(iter(results)).diatonic_pitch) assert 'C:4' == str(next(iter(results)).diatonic_pitch) result_pitches = [] for i in range(0, 33): p_map = PMap() p_map[v_notes[i]] = ContextualNote(lower_policy_context) results = constraints[i].values(p_map, v_notes[i]) result_pitches.append(next(iter(results)).diatonic_pitch) assert len(result_pitches) == 33 for i in range(0, 33): print('[{0}] {1}'.format(i, str(result_pitches[i]))) checks = [ 'C:4', 'G:4', 'D:5', 'F:5', 'G:5', 'F:5', 'D:5', 'G:4', 'C:4' ] for i in range(0, len(checks)): assert checks[i] == str(result_pitches[i])
def test_multi_track(self): c = InstrumentCatalog.instance() score = Score() score.time_signature_sequence.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4)), Position(0))) score.tempo_sequence.add( TempoEvent(Tempo(60, Duration(1, 4)), Position(0))) violin = c.get_instrument("violin") piano = c.get_instrument("piano") note0 = Note(DiatonicPitch(4, 'a'), Duration(1, 4)) note1 = Note(DiatonicPitch(4, 'b'), Duration(1, 4)) note2 = Note(DiatonicPitch(4, 'c'), Duration(1, 4)) note3 = Note(DiatonicPitch(4, 'd'), Duration(1, 4)) note4 = Note(DiatonicPitch(5, 'g'), Duration(1, 4)) note5 = Note(DiatonicPitch(5, 'f'), Duration(1, 4)) note6 = Note(DiatonicPitch(5, 'e'), Duration(1, 4)) note7 = Note(DiatonicPitch(5, 'd'), Duration(1, 4)) violin_instrument_voice = InstrumentVoice(violin, 1) violin_voice = violin_instrument_voice.voice(0) assert violin_voice vline = Line([note0, note1, note2, note3]) violin_voice.pin(vline) score.add_instrument_voice(violin_instrument_voice) piano_instrument_voice = InstrumentVoice(piano, 1) piano_voice = piano_instrument_voice.voice(0) assert piano_voice pline = Line([note4, note5, note6, note7]) piano_voice.pin(pline, Offset(1, 8)) score.add_instrument_voice(piano_instrument_voice) violin_voice.dynamics_sequence.add( DynamicsEvent(Dynamics(Dynamics.F), Position(0))) piano_voice.dynamics_sequence.add( DynamicsEvent(Dynamics(Dynamics.P), Position(0))) smc = ScoreToMidiConverter(score) smc.create('score_multi_trackoutput_file.mid') TestScoreToMidiConverter.read_midi_file( 'score_multi_trackoutput_file.mid')
def test_remove_notes(self): c = InstrumentCatalog.instance() violin = c.get_instrument("violin") note0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) note1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) line = Line() line.pin(note0, Offset(1, 4)) line.pin(note1, Offset(3, 8)) line.pin(note2, Offset(1, 2)) line.pin(note3, Offset(5, 8)) voice = Voice(violin) voice.pin(line, Offset(0)) line.unpin([note1, note2]) notes = voice.get_all_notes() assert len(notes) == 2 assert note0 in notes assert note3 in notes assert note1 not in notes assert note2 not in notes notes = voice.get_notes_starting_in_interval( Interval(Position(0), Position(2, 1))) assert len(notes) == 2 line.clear() notes = voice.get_all_notes() assert len(notes) == 0 notes = voice.get_notes_starting_in_interval( Interval(Position(0), Position(2, 1))) assert len(notes) == 0
def test_compute_simple_function_tone(self): print('--- test_compute_simple_function_tone ---') line = Line() f = GenericUnivariatePitchFunction( TestFitPitchToFunctionConstraint.sinasoidal, Position(0), Position(2)) v_note = Note(DiatonicPitch.parse('A:4'), Duration(1, 32)) line.pin(v_note, Offset(0)) constraint, lower_policy_context = TestFitPitchToFunctionConstraint.build_simple_constraint( v_note, f, ModalityType.Major, 'G', 'tV') p_map = PMap() p_map[v_note] = ContextualNote(lower_policy_context) results = constraint.values(p_map, v_note) assert results is not None assert len(results) == 1 print(next(iter(results)).diatonic_pitch) assert 'C:4' == str(next(iter(results)).diatonic_pitch) v_note = Note(DiatonicPitch.parse('A:4'), Duration(1, 32)) line.pin(v_note, Offset(1, 32)) constraint, lower_policy_context = TestFitPitchToFunctionConstraint.build_simple_constraint( v_note, f, ModalityType.Major, 'G', 'tV') p_map = PMap() p_map[v_note] = ContextualNote(lower_policy_context) results = constraint.values(p_map, v_note) assert results is not None assert len(results) == 1 print(next(iter(results)).diatonic_pitch) assert 'E:4' == str(next(iter(results)).diatonic_pitch) p_map[v_note].note = next(iter(results)) assert constraint.verify(p_map)
def sub_line(self, sub_line_range=None): """ Take a sub-range (time) of this line, and build a new line with notes that begins within that range :param sub_line_range: numeric interval to check for inclusion. :return: (sub-line, onset of original (Position), duration of sub-line) Note: The sub_line is not guaranteed to have the same length as the line, as sub_line is constructed only of the notes contained withing sub_line_range, starting with the first note found. """ sub_line_range = Interval( Fraction(0), self.duration.duration ) if sub_line_range is None else sub_line_range new_line = Line(None, self.instrument) first_position = None for s in self.sub_notes: s_excluded = Line._all_start_in(s, sub_line_range) if s_excluded == 1: if first_position is not None: offset = Offset(s.get_absolute_position().position - first_position) else: first_position = s.get_absolute_position().position offset = Offset(0) s_prime = s.clone() new_line.pin(s_prime, offset) else: if s_excluded == -1: raise Exception( "Line range {0} must fully enclose sub-structures: {1}." .format(sub_line_range, s)) return new_line, Position( first_position) if first_position is not None else Position( 0), new_line.duration
def test_insert_notes(self): print('test_insert_notes') # same as test_nested_notes note1 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) note2 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) note3 = Note(DiatonicPitch(4, 'e'), Duration(1, 16)) sub_beam = Beam([note1, note2, note3]) beam = Beam() beam.append(Note(DiatonicPitch(4, 'f'), Duration(1, 8))) beam.append(sub_beam) beam.append(Note(DiatonicPitch(4, 'g'), Duration(1, 8))) AbstractNote.print_structure(beam) # add a beam n_list = [ Note(DiatonicPitch(3, 'c'), Duration(1, 8)), Note(DiatonicPitch(3, 'd'), Duration(1, 8)) ] add_beam = Beam(n_list) sub_beam.add(add_beam, 1) print(beam) AbstractNote.print_structure(beam) notes = beam.get_all_notes() assert len(notes) == 7 TestBeam.print_all_notes(notes) assert notes[0].diatonic_pitch == DiatonicPitch(4, 'f') assert notes[1].diatonic_pitch == DiatonicPitch(4, 'c') assert notes[2].diatonic_pitch == DiatonicPitch(3, 'c') assert notes[3].diatonic_pitch == DiatonicPitch(3, 'd') assert notes[4].diatonic_pitch == DiatonicPitch(4, 'd') assert notes[5].diatonic_pitch == DiatonicPitch(4, 'e') assert notes[6].diatonic_pitch == DiatonicPitch(4, 'g') assert notes[0].relative_position == Offset(0) assert notes[1].relative_position == Offset(0) assert notes[2].relative_position == Offset(0) assert notes[3].relative_position == Offset(1, 32) assert notes[4].relative_position == Offset(1, 8) assert notes[5].relative_position == Offset(3, 16) assert notes[6].relative_position == Offset(11, 32)
def downward_refactor_layout(self, incremental_factor): """ Called by Tuplet, this method applies the incremental factor down the tree, adjusting note duration accordingly. At a Note, it calls apply_factor to make durational adjustments. Otherwise, it calls recursively. The method also rescales the relative positions of abstract notes. Args: incremental_factor: the multiplicative factor to apply downward. """ from structure.note import Note self.contextual_reduction_factor *= incremental_factor relpos = Offset(0) for n in self.sub_notes: if isinstance(n, Note): n.apply_factor(incremental_factor) else: n.downward_refactor_layout(incremental_factor) n.relative_position = relpos relpos += n.duration