def apply(self, step_increment=0, temporal_extent=None, secondary_shift_type=None): """ Do an apply action for this transform. :param step_increment: The number of scalar steps to do. :param secondary_shift_type: If not None, overrides the default setting of secondary_shift_type. :param temporal_extent: The temporal extent over which to transform :return: A new score line and new score hct reflecting the transform changes in the extent. """ if step_increment is None or not isinstance(step_increment, int): raise Exception('Increment must be specified and be an integer.') self.step_increment = step_increment self.__secondary_shift_type = secondary_shift_type if secondary_shift_type is not None \ else self.__default_secondary_shift_type # If temporal_extent is None, use the whole range of hct. self.temporal_extent = temporal_extent if temporal_extent is not None else \ Interval(Fraction(0), self.source_hct.duration.duration) self.pre_extent = None if self.temporal_extent.lower == 0 else Interval(0, self.temporal_extent.lower) self.post_extent = None if self.temporal_extent.upper >= self.source_line.duration else \ Interval(self.temporal_extent.upper, self.source_line.duration.duration) self.hc_step_pitch_function_map = dict() score_hct = self._rebuild_hct(self.source_hct) score_line = self._reset_pitches(score_hct) return score_line, score_hct
def test_delete_node(self): print('Delete node test') tree = IntervalTree() for i in range(1, 4): tree.put(Interval(i, i + 3), MyObject(i)) print(tree) result = tree.query_point(3.5) assert result assert len(result) == 3 print(', '.join(('[' + str(w.value.idd) + '] ' + str(w) for w in result))) assert sum(x.value.idd for x in result) == 6 print('Deleting [{0}] {1}'.format(result[0].value.idd, result[0])) tree.delete(result[0]) print(tree) result = tree.query_point(3.5) assert result assert len(result) == 2 # single node delete test print('Single node delete test') tree = IntervalTree() tree.put(Interval(3, 5), MyObject(5)) print(tree) result = tree.query_point(3) assert len(result) == 1 tree.delete(result[0]) print(tree) result = tree.query_point(3) assert len(result) == 0
def apply(self, temporal_extent=None, cue_pitch=None, flip_type=None, as_copy=True): """ Apply the TFlip transform to a tempoaral extent. :param temporal_extent: misc.Interval :param cue_pitch: Possible override of the cue pitch. :param flip_type: Ref. FlipType on how cue pitch is used in reflection. :param as_copy: True means to return copys of line, hct as source_line, source_hct would be modified otherwise. :return: modified line and hct (as objects, the same as passed in.) """ # If temporal_extent is None, use the whole range of hct. self.temporal_extent = temporal_extent if temporal_extent is not None else \ Interval(Fraction(0), self.source_hct.duration.duration) self.cue_pitch = self.default_cue_pitch if cue_pitch is None else cue_pitch self.flip_type = self.default_flip_type if flip_type is None else flip_type self.pre_extent = None if self.temporal_extent.lower == 0 else Interval( 0, self.temporal_extent.lower) self.post_extent = None if self.temporal_extent.upper >= self.source_line.duration else\ Interval(self.temporal_extent.upper, self.source_line.duration.duration) score_line = self._reset_pitches(as_copy) score_hct = self._rebuild_hct(self.source_hct, as_copy) return score_line, score_hct
def test_sub_line(self): print('----- test_sub_line -----') source_instance_expression = '{<C-Major:I> qC:4 D E F <:v> [iD:5 B:4 A G] qC:5 D <:I> G:4 iF E hC}' lge = LineGrammarExecutor() source_instance_line, source_instance_hct = lge.parse( source_instance_expression) sub_line, start, duration = source_instance_line.sub_line( Interval(Fraction(1, 2), Fraction(2))) print(str(source_instance_line)) print(str(sub_line)) notes = sub_line.get_all_notes() assert notes is not None assert len(notes) == 8 assert 'E:4' == str(notes[0].diatonic_pitch) assert 'F:4' == str(notes[1].diatonic_pitch) with self.assertRaises(Exception) as context: source_instance_line.sub_line(Interval(Fraction(1), Fraction(5, 4))) self.assertTrue('This is broken' in str(context.exception)) sub_line, start, duration = source_instance_line.sub_line() print(str(source_instance_line)) print(str(sub_line)) assert sub_line.duration.duration == Fraction(3)
def test_simple_equals(self): int_interval = Interval(5, 9) assert int_interval == Interval(5, 9) assert int_interval != Interval(5, 9, BoundaryPolicy.Closed) assert int_interval == Interval(5, 9, BoundaryPolicy.HI_Open) assert int_interval != Interval(4, 7)
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 test_problem_interval(self): print('test problem interval') tree = IntervalTree() tree.put(Interval(0.0, .5), MyObject(1)) print(tree) print('---') tree.put(Interval(.5, 1.0), MyObject(1)) print(tree) print('---') tree.put(Interval(1.0, 1.25), MyObject(1)) print('Tree for test problem interval') print(tree)
def test_duplicate_interval(self): print('test duplicate interval') tree = IntervalTree() tree.put(Interval(4.0, 7.0), MyObject(1)) tree.put(Interval(4.0, 7.0), MyObject(1)) # We want two results - same (equals) interval, two different objects. result = tree.query_point(5.9) assert result assert len(result) == 2 assert result[0].interval == Interval(4.0, 7.0) assert result[1].interval == Interval(4.0, 7.0) assert result[0].value != result[1].value print(tree)
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 test_hct_rebuild_perfect_overlap(self): print('----- test_hct_rebuild_perfect_overlap -----') line_str = '{<C-Major: I> hA:5 <:IV> B qC G <:VI> hD}' lge = LineGrammarExecutor() target_line, target_hct = lge.parse(line_str) print('--- before transformation ---') TestTChromaticFlip.print_notes(target_line) TestTChromaticFlip.print_hct(target_hct) cue = DiatonicPitch(5, 'c') f = TChromaticReflection(target_line, target_hct, cue) temporal_extent = Interval(Fraction(1, 2), Fraction(3, 2)) score_line, score_hct = f.apply(temporal_extent, cue) print('--- after transformation ---') TestTChromaticFlip.print_notes(score_line) TestTChromaticFlip.print_hct(score_hct) print('--- transformation ---') TestTChromaticFlip.print_function(f, target_hct) notes = score_line.get_all_notes() assert 'Db:4' == str(notes[1].diatonic_pitch) assert 'C:5' == str(notes[2].diatonic_pitch) assert 'F:4' == str(notes[3].diatonic_pitch) hc_list = score_hct.hc_list() assert len(hc_list) == 3 assert hc_list[1].chord.chord_template.scale_degree == 1 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'G', 'C', 'Eb'} assert hc_list[1].chord.chord_template.inversion == 3
def get_notes_by_bp_interval(self, interval): conversion = TimeConversion(self.tempo_sequence, self.time_signature_sequence, Position(self.duration.duration)) wnt_interval = Interval(conversion.bp_to_position(interval.lower), conversion.bp_to_position(interval.upper)) return self.get_notes_by_wnt_interval(wnt_interval)
def test_hct_simple_shift(self): print('----- test_hct_simple_shift -----') line_str = '{<C-Major: I> C:4 E F D <:IV> F A <:V> G D <:VI> a c b a}' lge = LineGrammarExecutor() target_line, target_hct = lge.parse(line_str) root_shift_interval = TonalInterval.create_interval('C:4', 'G:4') tshift = TShift(target_line, target_hct, root_shift_interval) temporal_extent = Interval(Fraction(1, 1), Fraction(2, 1)) tshift.apply(temporal_extent, as_copy=False) TestTShift.print_notes(target_line) TestTShift.print_hct(target_hct) notes = target_line.get_all_notes() assert 12 == len(notes) assert 'C:5' == str(notes[4].diatonic_pitch) assert 'E:5' == str(notes[5].diatonic_pitch) assert 'D:5' == str(notes[6].diatonic_pitch) assert 'A:4' == str(notes[7].diatonic_pitch) hc_list = target_hct.hc_list() assert len(hc_list) == 4 assert hc_list[1].chord.chord_template.scale_degree == 4 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'C', 'E', 'G'} assert hc_list[1].chord.chord_template.inversion == 1 assert hc_list[1].tonality.modal_index == 0 assert hc_list[1].tonality.basis_tone.diatonic_symbol == 'G' assert hc_list[1].tonality.root_tone.diatonic_symbol == 'G' assert hc_list[1].tonality.modality_type == ModalityType.Major assert hc_list[1].chord.chord_type.value == TertianChordType.Maj
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_simple_interval(self): int_interval = Interval(5, 9) assert int_interval.contains(7) assert int_interval.contains(6) assert Interval.intersects(int_interval, Interval(7, 10)) assert int_interval.intersection(Interval(7, 10)) == Interval( 7, 9).intersection(int_interval)
def test_secondary_chord(self): print('----- test_secondary_tonality -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chort_t_i = TertianChordTemplate.parse('tI') chord_i = chort_t_i.create_chord(diatonic_tonality) chord_v_ii = SecondaryChordTemplate.parse('V/ii').create_chord( diatonic_tonality) chord_vi_v = SecondaryChordTemplate.parse('vi/V').create_chord( diatonic_tonality) chord_t_ii = TertianChordTemplate.parse('tii') chord_ii = chord_t_ii.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord_i, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_v_ii, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_vi_v, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_ii, Duration(1))) TestTFlip.print_hct(hc_track) tune = [('C:5', (1, 1)), ('E:5', (1, 1)), ('E:5', (1, 1)), ('G:5', (1, 1))] line = TestTFlip.build_line(tune) cue = DiatonicPitch(5, 'd') tflip = TDiatonicReflection(line, hc_track, cue) temporal_extent = Interval(Fraction(0), Fraction(4)) score_line, score_hct = tflip.apply(temporal_extent, cue) TestTFlip.print_notes(score_line) TestTFlip.print_hct(score_hct) notes = score_line.get_all_notes() assert len(notes) == 4 assert str(notes[0].diatonic_pitch) == 'E:5' assert str(notes[1].diatonic_pitch) == 'C#:5' assert str(notes[2].diatonic_pitch) == 'C:5' assert str(notes[3].diatonic_pitch) == 'A:4' hc_list = score_hct.hc_list() assert len(hc_list) == 4 assert hc_list[1].chord.primary_chord.chord_template.scale_degree == 7 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'C#', 'E', 'G'} assert hc_list[1].chord.primary_chord.chord_template.inversion == 3 assert hc_list[2].chord.primary_chord.chord_template.scale_degree == 7 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'C', 'F#', 'A'} assert hc_list[2].chord.primary_chord.chord_template.inversion == 3
def test_overlapping_stair(self): tree = IntervalTree() for i in range(1, 4): tree.put(Interval(i, i + 3), MyObject(i)) print('Tree for test overlapping stair') print(tree) result = tree.query_point(1.5) assert result assert len(result) == 1 assert sum(x.value.idd for x in result) == 1 result = tree.query_point(2.5) assert result assert len(result) == 2 assert sum(x.value.idd for x in result) == 3 result = tree.query_point(3.5) assert result assert len(result) == 3 assert sum(x.value.idd for x in result) == 6 result = tree.query_point(4.5) assert result assert len(result) == 2 assert sum(x.value.idd for x in result) == 5 result = tree.query_point(5.5) assert result assert len(result) == 1 assert sum(x.value.idd for x in result) == 3 result = tree.query_point(6.5) assert len(result) == 0 result = tree.query_interval(Interval(2, 3)) assert len(result) == 2 assert sum(w.value.idd for w in result) == 3 print(', '.join((str(w) for w in result))) result = tree.query_interval(Interval(3, 4)) assert len(result) == 3 assert sum(w.value.idd for w in result) == 6 print(', '.join((str(w) for w in result)))
def apply(self, temporal_extent=None, root_shift_interval=None, modal_index=None, range_modality_type=None, as_copy=True): """ Apply transform to a temporal extent. :param temporal_extent: numerical interval indicating start/end offsets on line to apply shift. Interval from misc.interval :param root_shift_interval: root tone shift. :param modal_index: modal index for the new key. :param range_modality_type: modality type for the new key. :param as_copy: True means to return copys of line, hct as source_line, source_hct would be modified otherwise. :return: modified line and hct (as objects, the same as passed in.) """ # If temporal_extent is None, use the whole range of hct. self.temporal_extent = temporal_extent if temporal_extent is not None else \ Interval(Fraction(0), self.source_hct.duration.duration) self.pre_extent = None if self.temporal_extent.lower == 0 else Interval( 0, self.temporal_extent.lower) self.post_extent = None if self.temporal_extent.upper >= self.source_line.duration else \ Interval(self.temporal_extent.upper, self.source_line.duration.duration) self.root_shift_interval = self.default_root_shift_interval if root_shift_interval is None \ else root_shift_interval self.modal_index = self.default_modal_index if modal_index is None else modal_index if range_modality_type is not None and isinstance( range_modality_type, int): range_modality_type = ModalityType(range_modality_type) self.range_modality_type = self.default_range_modality_type if range_modality_type is None \ else range_modality_type self.hc_pitch_function_map = dict() score_line = self._reset_pitches(as_copy) score_hct = self._rebuild_hct(self.source_hct, as_copy) return score_line, score_hct
def _add_notes_to_tree(self, notes): for note in notes: # check of note is in range of the voice's instrument.. if note.diatonic_pitch.chromatic_distance < self.instrument.sounding_low.chromatic_distance or \ note.diatonic_pitch.chromatic_distance > self.instrument.sounding_high.chromatic_distance: raise Exception('Note {0} not in instrument {1} sounding range'.format(note, self.instrument)) interval = Interval(note.get_absolute_position(), note.get_absolute_position() + note.duration) self.interval_tree.put(interval, note)
def get_notes_starting_in_bp_interval(self, interval): """ Get all notes starting in the score by an interval based on beat position: Return dict structure as follows: instrument_voice --> {voice_index --> [notes]} """ conversion = TimeConversion(self.tempo_sequence, self.time_signature_sequence, Position(self.duration.duration)) wnt_interval = Interval(conversion.bp_to_position(interval.lower), conversion.bp_to_position(interval.upper)) return self.get_notes_starting_in_wnt_interval(wnt_interval)
def _remove_notes_from_tree(self, notes): # remove all intervals from the old line for note in notes: interval = Interval(note.get_absolute_position().position, note.get_absolute_position().position + note.duration.duration) result = self.interval_tree.find_exact_interval(interval) for interval_info in result: if interval_info.value == note: self.interval_tree.delete(interval_info) if note in self.articulation_map: del self.articulation_map[note]
def test_delete_with_one_child(self): print('Test delete with one child') tree = IntervalTree() tree.put(Interval(15, 30), MyObject(1)) tree.put(Interval(5, 10), MyObject(2)) tree.put(Interval(16, 30), MyObject(3)) tree.put(Interval(18, 25), MyObject(5)) tree.put(Interval(20, 40), MyObject(4)) tree.put(Interval(23, 50), MyObject(6)) # 20 should have a right node only print(tree) result = tree.query_point(20) f = None for r in result: if r.rb_node.key == 20: f = r break assert f assert f.rb_node.left == tree.nil assert f.rb_node.right != tree.nil tree.delete(f) print(tree) result = tree.query_point(20) f = None for r in result: if r.rb_node.key == 20: f = r break assert not f
def test_delete_min_max(self): print('Test delete min max') tree = IntervalTree() tree.put(Interval(15, 30), MyObject(1)) tree.put(Interval(5, 10), MyObject(2)) tree.put(Interval(16, 30), MyObject(3)) tree.put(Interval(18, 25), MyObject(5)) tree.put(Interval(20, 40), MyObject(4)) tree.put(Interval(23, 50), MyObject(6)) # 23 span is 23-50 print(tree) result = tree.query_point(23) f = None for r in result: if r.rb_node.key == 23: f = r break assert f assert f.rb_node.key == 23 tree.delete(f) print(tree) assert tree.root.max == 40
def test_delete_with_two_child(self): print('Test delete with two children') tree = IntervalTree() tree.put(Interval(15, 30), MyObject(1)) tree.put(Interval(5, 10), MyObject(2)) tree.put(Interval(16, 30), MyObject(3)) tree.put(Interval(18, 25), MyObject(5)) tree.put(Interval(20, 40), MyObject(4)) tree.put(Interval(23, 50), MyObject(6)) # 18 should have left and right print(tree) result = tree.query_point(18) f = None for r in result: if r.rb_node.key == 18: f = r break assert f assert f.rb_node.left != tree.nil assert f.rb_node.right != tree.nil tree.delete(f) print(tree) result = tree.query_point(18) f = None for r in result: if r.rb_node.key == 18: f = r break assert not f
def get_notes(self, start_position, end_position, line=None): """ Get all notes in explicit interval given as lower/upper bounds, [) Args: start_position: Position of the start of the interval (inclusive) end_position: Position of the end of the interval (non-inclusive) line: Optionsl Line to restrict search to: Returns: List of notes satisfying query """ return self.get_notes_by_interval(Interval(start_position, end_position), line)
def sub_hct(self, sub_track_interval=None): """ Take a sub_track of this hct. :param sub_track_interval: NmericInterval. If none, the entire hct. :return: """ sub_track_interval = NumericInterval(Fraction(0), self.duration.duration) if sub_track_interval is None else \ sub_track_interval new_track = HarmonicContextTrack() for hc in self.hc_list(): hc_interval = NumericInterval( hc.position.position, hc.position.position + hc.duration.duration) hc_intersect = hc_interval.intersection(sub_track_interval) if hc_intersect is not None: new_hc = HarmonicContext(hc.tonality, hc.chord, Duration(hc_intersect.length()), Position(hc_intersect.lower)) new_track.append(new_hc) return new_track
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_hct_rebuild_perfect_overlap(self): print('----- test_hct_rebuild_perfect_overlap -----') line_str = '{<C-Major: I> hA:5 <:IV> B qC G <:VI> hD}' lge = LineGrammarExecutor() target_line, target_hct = lge.parse(line_str) TestTFlip.print_hct(target_hct) cue = DiatonicPitch(5, 'd') tflip = TDiatonicReflection(target_line, target_hct, cue) temporal_extent = Interval(Fraction(1, 2), Fraction(3, 2)) score_line, score_hct = tflip.apply(temporal_extent, cue) TestTFlip.print_notes(score_line) TestTFlip.print_hct(score_hct) hc_list = score_hct.hc_list() assert hc_list[0].position == Position(0) assert hc_list[0].duration == Duration(1, 2) assert hc_list[0].chord.chord_type == TertianChordType( TertianChordType.Maj) assert hc_list[0].chord.chord_template.scale_degree == 1 assert {t[0].diatonic_symbol for t in hc_list[0].chord.tones} == {'C', 'E', 'G'} assert hc_list[0].chord.chord_template.inversion == 1 assert hc_list[1].position == Position(1, 2) assert hc_list[1].duration == Duration(1) assert hc_list[1].chord.chord_type == TertianChordType( TertianChordType.Min) assert hc_list[1].chord.chord_template.scale_degree == 3 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'G', 'B', 'E'} assert hc_list[1].chord.chord_template.inversion == 3 assert hc_list[2].position == Position(3, 2) assert hc_list[2].duration == Duration(1, 2) assert hc_list[2].chord.chord_type == TertianChordType( TertianChordType.Min) assert hc_list[2].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'A', 'C', 'E'} assert hc_list[2].chord.chord_template.inversion == 1 notes = score_line.get_all_notes() assert str(notes[1].diatonic_pitch) == "F:4" assert str(notes[2].diatonic_pitch) == "E:5" assert str(notes[3].diatonic_pitch) == "A:4"
def test_access(self): mock = MagicMock(spec=IntervalTree) interval = Interval(2, 4) value = Fraction(2, 5) node = RBNode(interval, value, mock) assert node.interval == interval assert node.key == interval.lower assert node.value == value assert node.min == 2 assert node.max == 4 assert not node.parent assert node.left == node.nil assert node.right == node.nil
def test_match_interval_book(self): print('Test match interval - book') tree = IntervalTree() tree.put(Interval(15, 30), MyObject(1)) tree.put(Interval(16, 30), MyObject(3)) tree.put(Interval(18, 25), MyObject(5)) tree.put(Interval(20, 40), MyObject(4)) tree.put(Interval(23, 50), MyObject(6)) tree.put(Interval(5, 10), MyObject(2)) result = tree.find_exact_interval(Interval(16, 30)) assert result is not None assert len(result) == 1 assert result[0].interval == Interval(16, 30) print(tree)
def test_book_example(self): # Default is HI_Open f_interval = Interval(Fraction(1, 4), Fraction(3, 5)) print(f_interval) assert f_interval.contains(Fraction(1, 4)) assert not f_interval.contains(Fraction(3, 5)) # Intervals can be constructed with integer ranges. Note the resulting boundary policy. interval = Interval(1, 5, BoundaryPolicy.Closed).intersection( Interval(4, 6, BoundaryPolicy.Open)) assert interval.policy == BoundaryPolicy.LO_Open print(interval)