def create_track(chords, tonality): hc_track = HarmonicContextTrack() for c in chords: chord_t = ChordTemplate.generic_chord_template_parse(c[0]) chord = chord_t.create_chord(tonality) duration = Duration(c[1]) if isinstance(c[1], int) else Duration(c[1][0], c[1][1]) hc_track.append(HarmonicContext(tonality, chord, duration)) return hc_track
def dilate_hct(self, hct): new_hct = HarmonicContextTrack() for hc in hct.hc_list(): new_hc = HarmonicContext( hc.tonality, hc.chord, hc.duration * self.dilation_factor if self.apply_to_notes else hc.duration) new_hct.append(new_hc) return new_hct
def _build_target_hct(self, source_instance_hct): target_hct = HarmonicContextTrack() source_pat_hc_list = source_instance_hct.hc_list() target_pat_hc_list = self.substitution_pattern.target_pattern_hct.hc_list( ) for hc_expr, target_pat_hc in zip( self.substitution_pattern.target_hc_exprs, target_pat_hc_list): hc = hc_expr.interpret(source_pat_hc_list, target_pat_hc.duration) target_hct.append(hc) return target_hct
def test_basic_setup(self): c = InstrumentCatalog.instance() violin = c.get_instrument("violin") # Add notes to the score vnote0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) vnote1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) vnote2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) vnote3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) vnote4 = Note(DiatonicPitch(4, 'e'), Duration(1, 8)) vnote5 = Note(DiatonicPitch(4, 'f'), Duration(1, 8)) # Set up a violin voice with 6 8th notes vline = Line([vnote0, vnote1, vnote2, vnote3, vnote4, vnote5]) tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4), 'sww'), Position(0))) hc_track = HarmonicContextTrack() diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track.append(HarmonicContext(diatonic_tonality, chord, Duration(2))) score = LiteScore(vline, hc_track, violin, tempo_seq, ts_seq) bp = score.beat_position(Position(0)) print(bp) assert bp.beat_number == 0 bp = score.beat_position(Position(5, 8)) print(bp) assert bp.measure_number == 0 assert bp.beat_number == Fraction(5, 2) assert int(bp.beat_number) == 2 assert bp.beat_number - bp.beat == Fraction(1, 2) tse = score.time_signature_sequence.floor_event(Position(5, 8)) assert tse is not None print(tse.object.beat_type(bp.beat)) assert tse.object.beat_type(bp.beat) == BeatType.Weak assert bp.beat_fraction == Fraction(1, 2) bp = score.beat_position(Position(1, 16)) print(bp) tse = score.time_signature_sequence.floor_event(Position(1, 16)) print(tse.object.beat_type(bp.beat)) assert tse.object.beat_type(bp.beat) == BeatType.Strong
def build_hct(hc_expressed_list): parse_str = '{' for t in hc_expressed_list: parse_str += '<' + t[0] + '> qC:4 ' parse_str += '}' lge = LineGrammarExecutor() _, hct = lge.parse(parse_str) new_hct = HarmonicContextTrack() for hc, t in zip(hct.hc_list(), hc_expressed_list): new_hc = HarmonicContext(hc.tonality, hc.chord, t[1]) new_hct.append(new_hc) return new_hct
def build_harmonic_context_track(self): # Prune superfluous harmonic tags. new_tag_list = [tag for tag in self.harmonic_tag_list if tag.first_note is not None] self.harmonic_tag_list = new_tag_list hct = HarmonicContextTrack() for i in range(0, len(self.harmonic_tag_list)): harmonic_tag = self.harmonic_tag_list[i] duration = (self.harmonic_tag_list[i + 1].first_note.get_absolute_position() if i < len(self.harmonic_tag_list) - 1 else Position(self.__line.duration)) - \ self.harmonic_tag_list[i].first_note.get_absolute_position() harmonic_context = HarmonicContext(harmonic_tag.tonality, harmonic_tag.chord, duration, harmonic_tag.first_note.get_absolute_position()) hct.append(harmonic_context) return hct
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 build_vst_midi_list(): """ :return: """ c = InstrumentCatalog.instance() # Add notes to the score vnote0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) vnote1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) vnote2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) vnote3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) vnote4 = Note(DiatonicPitch(4, 'e'), Duration(1, 8)) vnote5 = Note(DiatonicPitch(4, 'f'), Duration(1, 8)) # Set up a violin voice with 6 8th notes vline = Line([vnote0, vnote1, vnote2, vnote3, vnote4, vnote5]) tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4), 'sww'), Position(0))) hc_track = HarmonicContextTrack() diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track.append(HarmonicContext(diatonic_tonality, chord, Duration(2))) score = Score() score.tempo_sequence.add(TempoEvent(Tempo(60), Position(0))) score.time_signature_sequence.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4)), Position(0))) violin = c.get_instrument("violin") violin_instrument_voice = InstrumentVoice(violin, 1) score.add_instrument_voice(violin_instrument_voice) violin_instrument_voice.voice(0).pin(vline) return ScoreToVstMidiConverter.convert_score(score, {0: 0}), score
def test_insert(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 3))) hc_track.insert( Position(1, 2), HarmonicContext(diatonic_tonality, chord, Duration(1, 4))) assert len(hc_track) == 3 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 4) assert hc_track[Position(3, 4)].duration == Duration(1, 3) hc_track = HarmonicContextTrack() hc_track.insert( Position(0), HarmonicContext(diatonic_tonality, chord, Duration(1, 4))) hc_track.insert( Position(0), HarmonicContext(diatonic_tonality, chord, Duration(1, 3))) hc_track.insert( Position(0), HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) assert len(hc_track) == 3 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 3) assert hc_track[Position(5, 6)].duration == Duration(1, 4) assert len(hc_track) == 3
def _rebuild_hct(self, orig_hct, as_copy): hc_list = orig_hct.hc_list() if not as_copy: orig_hct.clear() new_hct = HarmonicContextTrack() if as_copy else orig_hct next_index = 0 position = Position(0) if self.pre_extent is not None: for hc in hc_list: intersect = hc.extent.intersection(self.pre_extent) if intersect is None: break duration = Duration( min(intersect.length(), hc.duration.duration)) new_hc = HarmonicContext(hc.tonality, hc.chord, duration, hc.position) new_hct.append(new_hc) position += new_hc.duration if hc.extent.upper > self.pre_extent.upper: break next_index += 1 for hc in islice(hc_list, next_index, None): intersect = hc.extent.intersection(self.temporal_extent) if intersect is None: break duration = Duration(intersect.length()) if self.keep_hct: new_hc = HarmonicContext(hc.tonality, hc.chord, duration, position) else: f = self.__hc_flip_map[hc] if hc in self.__hc_flip_map.keys() else \ ChromaticPitchReflectionFunction(hc.tonality, self.cue_pitch, self.domain_pitch_range) new_hc = HarmonicContext(f.range_tonality, self.remap_chord(hc), duration, position) new_hct.append(new_hc) position += new_hc.duration if hc.extent.upper > self.temporal_extent.upper: break next_index += 1 if self.post_extent is not None: for hc in islice(hc_list, next_index, None): intersect = hc.extent.intersection(self.post_extent) if intersect is None: break duration = Duration(intersect.length()) new_hc = HarmonicContext(hc.tonality, hc.chord, duration, position) new_hct.append(new_hc) position += new_hc.duration return new_hct
def _rebuild_hct(self, orig_hct, as_copy): hc_list = orig_hct.hc_list() if not as_copy: orig_hct.clear() new_hct = HarmonicContextTrack() if as_copy else orig_hct next_index = 0 position = Position(0) if self.pre_extent is not None: for hc in hc_list: intersect = hc.extent.intersection(self.pre_extent) if intersect is None: break duration = Duration( min(intersect.length(), hc.duration.duration)) new_hc = HarmonicContext(hc.tonality, hc.chord, duration, hc.position) new_hct.append(new_hc) position += new_hc.duration if hc.extent.upper > self.pre_extent.upper: break next_index += 1 for hc in islice(hc_list, next_index, None): intersect = hc.extent.intersection(self.temporal_extent) if intersect is None: break duration = Duration(intersect.length()) if self.keep_hct: new_hc = HarmonicContext(hc.tonality, hc.chord, duration, position) else: f, range_tonality = self._build_shift_function(hc) # TODO: the range tonality below is incorrect. new_hc = HarmonicContext( range_tonality, self.remap_chord(hc, f.range_tonality), duration, position) new_hct.append(new_hc) position += new_hc.duration if hc.extent.upper > self.temporal_extent.upper: break next_index += 1 if self.post_extent is not None: for hc in islice(hc_list, next_index, None): intersect = hc.extent.intersection(self.post_extent) if intersect is None: break duration = Duration(intersect.length()) new_hc = HarmonicContext(hc.tonality, hc.chord, duration, position) new_hct.append(new_hc) position += new_hc.duration return new_hct
def test_secondary_chord(self): print('----- test_secondary_tonality -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicFoundation.get_tone("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))) TestTChromaticFlip.print_hct(hc_track) tune = [('C:5', (1, 1)), ('E:5', (1, 1)), ('E:5', (1, 1)), ('G:5', (1, 1))] line = TestTChromaticFlip.build_line(tune) cue = DiatonicPitch(5, 'd') tflip = TChromaticReflection(line, hc_track, cue) score_line, score_hct = tflip.apply() TestTChromaticFlip.print_notes(score_line) TestTChromaticFlip.print_hct(score_hct)
def _rebuild_hct(self, orig_hct): hc_list = orig_hct.hc_list() new_hct = HarmonicContextTrack() next_index = 0 position = Position(0) if self.pre_extent is not None: for hc in hc_list: intersect = hc.extent.intersection(self.pre_extent) if intersect is None: break duration = Duration(min(intersect.length(), hc.duration.duration)) new_hc = HarmonicContext(hc.tonality, hc.chord, duration, hc.position) new_hct.append(new_hc) position += new_hc.duration if hc.extent.upper > self.pre_extent.upper: break next_index += 1 for hc in islice(hc_list, next_index, None): intersect = hc.extent.intersection(self.temporal_extent) if intersect is None: break duration = Duration(intersect.length()) new_hc = self.rebuild_hc(hc, position, duration) new_hct.append(new_hc) # TODO: this has to be called, but not sure what side effects are necessary. self._build_step_shift_function(new_hc, hc) position += new_hc.duration if hc.extent.upper > self.temporal_extent.upper: break next_index += 1 if self.post_extent is not None: for hc in islice(hc_list, next_index, None): intersect = hc.extent.intersection(self.post_extent) if intersect is None: break duration = Duration(intersect.length()) new_hc = HarmonicContext(hc.tonality, hc.chord, duration, position) new_hct.append(new_hc) position += new_hc.duration return new_hct
def test_remove(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 4))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 3))) remove_item = hc_track[Position(1, 2)] hc_track.remove(remove_item) assert len(hc_track) == 2 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 3)
def test_append(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord1 = chord_t.create_chord(diatonic_tonality) chord_t = TertianChordTemplate.parse('tV') chord2 = chord_t.create_chord(diatonic_tonality) chord_t = TertianChordTemplate.parse('tVI') chord3 = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord1, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord2, Duration(1, 4))) hc_track.append( HarmonicContext(diatonic_tonality, chord3, Duration(1, 3))) assert len(hc_track) == 3 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 4) assert hc_track[Position(3, 4)].duration == Duration(1, 3) print(hc_track)
def test_simple_setup(self): print('--- test_simple_setup') line = Line() notes = [ Note(DiatonicPitch.parse('a:4'), Duration(1, 4)), Note(DiatonicPitch.parse('b:4'), Duration(1, 4)), Note(DiatonicPitch.parse('c:4'), Duration(1, 4)), Note(DiatonicPitch.parse('d:4'), Duration(1, 4)), Note(DiatonicPitch.parse('e:4'), Duration(1, 2)), Note(DiatonicPitch.parse('f:4'), Duration(1, 2)), ] location = 0 for note in notes: line.pin(note, Offset(location)) location += note.duration.duration tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60, Duration(1, 4)), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4), 'sww'), Position(0))) diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 1))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) c = InstrumentCatalog.instance() violin = c.get_instrument("violin") score = LiteScore(line, hc_track, violin, tempo_seq, ts_seq) constraints = [ OnBeatConstraint(notes[1], BeatType.Strong), StepSequenceConstraint(notes, [1, 1, 1, -1, -1]) ] solver = MelodicConstraintSolver.create(score, constraints) cheat = {notes[2]: DiatonicPitch.parse('E:5')} results = solver.solve(cheat) assert results is not None assert results.beat_results is not None assert results.pitch_results is not None print(len(results.beat_results)) print(len(results.pitch_results)) assert 1 == len(results.beat_results) assert 1 == len(results.pitch_results) new_line = results.apply(next(iter(results.beat_results)), next(iter(results.pitch_results))) assert new_line is not None print(new_line) all_notes = new_line.get_all_notes() assert 'C:5' == str(all_notes[0].diatonic_pitch) assert 'D:5' == str(all_notes[1].diatonic_pitch) assert 'E:5' == str(all_notes[2].diatonic_pitch) assert 'F:5' == str(all_notes[3].diatonic_pitch) assert 'E:5' == str(all_notes[4].diatonic_pitch) assert 'D:5' == str(all_notes[5].diatonic_pitch) assert Position(3, 4) == all_notes[1].get_absolute_position()
def test_hct_rebuild_imperfect_overlap(self): print('----- test_hct_rebuild_imperfect_overlap -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("D")) chord_t_i = TertianChordTemplate.parse('tI') chord_i = chord_t_i.create_chord(diatonic_tonality) chord_t_iv = TertianChordTemplate.parse('tIV') chord_iv = chord_t_iv.create_chord(diatonic_tonality) chord_t_v = TertianChordTemplate.parse('tV') chord_v = chord_t_v.create_chord(diatonic_tonality) chord_t_vi = TertianChordTemplate.parse('tVI') chord_vi = chord_t_vi.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord_i, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord_iv, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_v, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord_vi, Duration(1))) TestTFlip.print_hct(hc_track) line_str = '{<D-Major: I> hA:5 <:IV> B C# <:V> qD E <:VI> hF# qG A}' lge = LineGrammarExecutor() target_line, target_hct = lge.parse(line_str) TestTFlip.print_hct(target_hct) cue = DiatonicPitch(5, 'f#') tflip = TDiatonicReflection(target_line, target_hct, cue) temporal_extent = Interval(Fraction(1, 4), Fraction(9, 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) == 8 assert str(notes[0].diatonic_pitch) == 'A:5' assert str(notes[1].diatonic_pitch) == 'C#:5' assert str(notes[2].diatonic_pitch) == 'B:5' assert str(notes[3].diatonic_pitch) == 'A:5' assert str(notes[4].diatonic_pitch) == 'G:5' assert str(notes[5].diatonic_pitch) == 'F#:5' assert str(notes[6].diatonic_pitch) == 'G:5' assert str(notes[7].diatonic_pitch) == 'A:5' hc_list = score_hct.hc_list() assert len(hc_list) == 6 assert hc_list[0].chord.chord_template.scale_degree == 1 assert {t[0].diatonic_symbol for t in hc_list[0].chord.tones} == {'D', 'F#', 'A'} assert hc_list[0].chord.chord_template.inversion == 1 assert hc_list[1].chord.chord_template.scale_degree == 1 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'D', 'F#', 'A'} assert hc_list[1].chord.chord_template.inversion == 3 assert hc_list[2].chord.chord_template.scale_degree == 5 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'E', 'A', 'C#'} assert hc_list[2].chord.chord_template.inversion == 3 assert hc_list[3].chord.chord_template.scale_degree == 4 assert {t[0].diatonic_symbol for t in hc_list[3].chord.tones} == {'D', 'G', 'B'} assert hc_list[3].chord.chord_template.inversion == 3 assert hc_list[4].chord.chord_template.scale_degree == 3 assert {t[0].diatonic_symbol for t in hc_list[4].chord.tones} == {'C#', 'F#', 'A'} assert hc_list[4].chord.chord_template.inversion == 3 assert hc_list[5].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[5].chord.tones} == {'B', 'D', 'F#'} assert hc_list[5].chord.chord_template.inversion == 1
def test_mozart(self): print('----- Mozart -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chort_t_i = TertianChordTemplate.parse('tI') chord_i = chort_t_i.create_chord(diatonic_tonality) chort_t_v = TertianChordTemplate.parse('tVMaj7') chord_v = chort_t_v.create_chord(diatonic_tonality) chord_t_i_1 = TertianChordTemplate.parse('tI') chord_i_1 = chord_t_i_1.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, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord_i_1, Duration(1, 2))) TestTFlip.print_hct(hc_track) tune = [('C:5', (1, 2)), ('E:5', (1, 4)), ('G:5', (1, 4)), ('B:4', (3, 8)), ('C:5', (1, 16)), ('D:5', (1, 16)), ('C:5', (1, 4))] line = TestTFlip.build_line(tune) cue = DiatonicPitch(5, 'd') tflip = TDiatonicReflection(line, hc_track, cue) temporal_extent = Interval(Fraction(0), Fraction(2)) 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) == 7 assert str(notes[0].diatonic_pitch) == 'E:5' assert str(notes[1].diatonic_pitch) == 'C:5' assert str(notes[2].diatonic_pitch) == 'A:4' assert str(notes[3].diatonic_pitch) == 'F:5' assert str(notes[4].diatonic_pitch) == 'E:5' assert str(notes[5].diatonic_pitch) == 'D:5' assert str(notes[6].diatonic_pitch) == 'E:5' hc_list = score_hct.hc_list() assert len(hc_list) == 3 assert hc_list[0].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[0].chord.tones} == {'E', 'A', 'C'} assert hc_list[0].chord.chord_template.inversion == 3 assert hc_list[1].chord.chord_template.scale_degree == 2 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'A', 'D', 'F', 'Bb'} assert hc_list[1].chord.chord_template.inversion == 3 assert hc_list[2].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'E', 'A', 'C'} assert hc_list[2].chord.chord_template.inversion == 3
class PositionDeltaInfo(object): """ This class hold information about the movement of various note structures in a line that in sum make all the OnBeat constraints work. This class not only records those movements, but is able to either create an image of the original line with movements made, or alter the original with the movements. """ def __init__(self, coverage_node_list, tempo_seq, ts_seq, hct, line): """ Constructor :param coverage_node_list: List of note structures that are affected by on beat constraints. :param tempo_seq: TempoEventSequence :param ts_seq: EventSequence of TimeSignatures :param hct: HarmonicContextTrack :param line: Line """ self.__coverage_node_list = coverage_node_list self.__coverage_node_aggregates = dict() self.__coverage_node_deltas = dict() # duplicate time signature event sequence new_ts_list = [] for e in ts_seq.sequence_list: new_ts_list.append( TimeSignatureEvent( TimeSignature(e.object.beats_per_measure, e.object.beat_duration, e.object.beat_pattern), e.time)) self.__ts_event_sequence = EventSequence(new_ts_list) # duplicate tempo event sequence new_tempo_list = [] for e in tempo_seq.sequence_list: new_tempo_list.append( TempoEvent(Tempo(e.object.tempo, e.object.beat_duration), e.time)) self.__tempo_event_sequence = TempoEventSequence(new_tempo_list) self.__line = line self.__hct = HarmonicContextTrack() for hc in hct.hc_list(): self.__hct.append( HarmonicContext(hc.tonality, hc.chord, Duration(hc.duration), Position(hc.position))) for n in self.coverage_node_list: self.__coverage_node_aggregates[n] = 0 self.__coverage_node_deltas[n] = 0 @property def coverage_node_list(self): return self.__coverage_node_list @property def line(self): return self.__line @property def hct(self): return self.__hct @property def ts_event_sequence(self): return self.__ts_event_sequence @property def tempo_event_sequence(self): return self.__tempo_event_sequence @property def coverage_node_deltas(self): return self.__coverage_node_deltas def line_duration(self): return Duration(self.correct_position(self.line.duration).position) def correct_position(self, position): # Adjust position by the set aggregates on structure. p_prime = Position(position) for cover in self.coverage_node_list: if cover.get_absolute_position() > p_prime: break p_prime = p_prime + self.coverage_node_deltas[cover] return p_prime def alter_at(self, cover, delta): self.coverage_node_deltas[cover] = delta.duration changed = list() for tse in self.ts_event_sequence.sequence_list: if tse.time >= self.correct_position( cover.get_absolute_position()) - delta.duration: changed.append(tse) for tse in changed: self.ts_event_sequence.remove(tse) tse.time += delta self.ts_event_sequence.add(tse) changed = list() for te in self.tempo_event_sequence.sequence_list: if te.time >= self.correct_position( cover.get_absolute_position()) - delta.duration: changed.append(te) for te in changed: self.tempo_event_sequence.remove(te) te.time += delta self.tempo_event_sequence.add(te) cover_start_position = self.correct_position( cover.get_absolute_position()) - delta.duration hc = self.hct[cover_start_position] if hc is not None: hc.duration = hc.duration + delta hc_list = self.hct.hc_list() index = hc_list.index(hc) for i in range(index + 1, len(hc_list)): hc_list[i].position = hc_list[i].position + delta self.hct.reset() def apply(self, line_copy=True): if line_copy: line = self.line.clone() line_map = self.map_lines(dict(), self.line, line) else: line = self.line line_map = None all_notes = sorted(self.line.get_all_notes(), key=lambda z: z.get_absolute_position()) delta_sum = 0 index = 0 while index < len(all_notes): note = all_notes[index] cover = PositionDeltaInfo._compute_cover(note) if cover in self.coverage_node_list: delta_sum += self.coverage_node_deltas[cover] if delta_sum != 0: cover_prime = line_map[cover] if line_copy else cover new_rel_pos = cover_prime.relative_position + delta_sum parent = cover_prime.parent parent.unpin(cover_prime) parent.pin(cover_prime, new_rel_pos) index += len(cover.get_all_notes()) return line @staticmethod def _compute_cover(note): c = note while not isinstance(c.parent, Line): c = c.parent return c def map_lines(self, line_map, p1, p2): line_map[p1] = p2 if isinstance(p1, AbstractNoteCollective): for from_note, to_note in zip(p1.sub_notes, p2.sub_notes): self.map_lines(line_map, from_note, to_note) return line_map def clone(self): c = PositionDeltaInfo(self.coverage_node_list, self.tempo_event_sequence, self.ts_event_sequence, self.hct, self.line) for n in self.coverage_node_list: c.__coverage_node_aggregates[n] = self.__coverage_node_aggregates[ n] c.__coverage_node_deltas[n] = self.__coverage_node_deltas[n] return c def __str__(self): str_list = list() for key, value in self.coverage_node_deltas.items(): str_list.append('{0} ==> {1}'.format(key, value)) return '\n'.join(s for s in str_list)