def mk_harmonics_melodies(origin_melodies: tuple, n_voices: int = 5, max_harmonic: int = MAX_HARMONIC) -> tuple: """Make polyphonic movement of common (sub-)harmonics from the origin melodies. The resulting tuple contains as many melodies as previously declared with the n_voices argument. The n_voices argument may be helpful for making sure not having too many resulting voices what could happen when voices occasionally contain octaves or primes. """ poly_per_interlocking = [] origin_melodies = tuple(m.discard_rests().tie() for m in origin_melodies) for comb in itertools.combinations(origin_melodies, 2): cadence = old.Polyphon(comb).chordify(add_longer=True) harmonics_per_pitch = tuple( functools.reduce( operator.add, tuple( find_common_harmonics( p[0], p[1], gender=gender, border=max_harmonic) for gender in (True, False)), ) if len(p) == 2 else tuple([]) for p in tuple( tuple(h) for h in cadence.pitch)) poly = [[old.Rest(chord.delay) for chord in cadence] for n in range(n_voices)] for h_idx, harmonics in enumerate(harmonics_per_pitch): for p_idx, p in enumerate(harmonics[:n_voices]): poly[p_idx][h_idx] = p.convert2tone(cadence.delay[h_idx]) poly = [old.Melody(melody) for melody in poly] poly_per_interlocking.append(old.Polyphon(poly)) return tuple(poly_per_interlocking)
def test_find_exact_simultan_events(self): poly2 = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3), old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 1), old.Tone(ji.r(4, 3), 2)]), ) ) simultan_events4 = poly2.find_exact_simultan_events(0, 1) simultan_events4_expected = ( old.Tone(ji.r(3, 2), 1, 1), old.Tone(ji.r(3, 2), 2, 2), old.Tone(ji.r(4, 3), 1, 1), ) self.assertEqual(simultan_events4, simultan_events4_expected) simultan_events0 = self.poly0.find_exact_simultan_events(0, 0) self.assertEqual(simultan_events0, (self.poly0[1][0],)) simultan_events1 = self.poly0.find_exact_simultan_events(0, 0, False) self.assertEqual(simultan_events1, (self.poly0[1].convert2absolute()[0],)) simultan_events2 = self.poly1.find_exact_simultan_events(1, 0) simultan_events2_expected = (self.poly1[2][0], self.poly1[2][0]) self.assertEqual(simultan_events2, simultan_events2_expected) simultan_events3 = self.poly1.find_exact_simultan_events(1, 1) simultan_events3_expected = (self.t8, self.t7, self.t7, self.t7, self.t2) self.assertEqual(simultan_events3, simultan_events3_expected)
def detect_intervals_and_duration_pairs_per_tone_per_voice( voices: tuple) -> tuple: voices = tuple(old.Melody(v) for v in voices) interval_and_time_pairs_per_tone_per_voice = [] for v_idx, voice in enumerate(voices): poly = old.Polyphon(v for v_idx1, v in enumerate(voices) if v_idx1 != v_idx) melody = voice.copy() interval_and_time_pairs_per_tone = [] for tone in melody.convert2absolute(): start, stop = tone.delay, tone.duration simultan_events = functools.reduce( operator.add, tuple(m[:] for m in poly.cut_up_by_time(start, stop))) interval_and_time_pairs = [] for simultan_event in simultan_events: if not simultan_event.pitch.is_empty: interval = simultan_event.pitch - tone.pitch interval_and_time_pairs.append( (interval, simultan_event.duration)) interval_and_time_pairs_per_tone.append( tuple(interval_and_time_pairs)) interval_and_time_pairs_per_tone_per_voice.append( tuple(interval_and_time_pairs_per_tone)) return tuple(interval_and_time_pairs_per_tone_per_voice)
def test_cut_up_by_idx(self): poly0 = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3), old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 1), old.Tone(ji.r(4, 3), 2)]), ) ) poly0_cut = poly0.cut_up_by_idx(2, 1) poly0_cut_expected = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 1), old.Tone(ji.r(1, 1), 1)]), old.Melody([old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly0_cut, poly0_cut_expected)
def test_cut_up_by_time(self): poly0 = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3), old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 1), old.Tone(ji.r(4, 3), 2)]), ) ) poly0_cut = poly0.cut_up_by_time(1, 3) poly0_cut_expected = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 1), old.Tone(ji.r(1, 1), 1)]), old.Melody([old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly0_cut, poly0_cut_expected) poly1_cut = poly0.cut_up_by_time(1, 3, add_earlier=False) poly1_cut_expected = old.Polyphon( ( old.Melody([old.Rest(1), old.Tone(ji.r(1, 1), 1)]), old.Melody([old.Rest(2)]), old.Melody([old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly1_cut, poly1_cut_expected) poly2_cut = poly0.cut_up_by_time(1, 3, hard_cut=False) poly2_cut_expected = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3)]), old.Melody([old.Rest(1), old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly2_cut[2], poly2_cut_expected[2])
class PolyTest(unittest.TestCase): p0 = ji.r(5, 4) p1 = ji.r(3, 2) p2 = ji.r(1, 1) p3 = ji.r(6, 5) p4 = ji.r(7, 4) p5 = ji.r(9, 8) t0 = old.Tone(p0, rhy.Unit(1)) t1 = old.Tone(p1, rhy.Unit(1)) t2 = old.Tone(p2, rhy.Unit(1)) t3 = old.Tone(p3, rhy.Unit(1)) t3 = old.Tone(p3, rhy.Unit(1)) t4 = old.Tone(p4, rhy.Unit(1)) t5 = old.Tone(p5, rhy.Unit(1)) t6 = old.Tone(p0, rhy.Unit(2)) t7 = old.Tone(p0, rhy.Unit(0.5)) t8 = old.Tone(p0, rhy.Unit(1.5)) t9 = old.Tone(p1, rhy.Unit(1.5)) t10 = old.Tone(p5, rhy.Unit(0.5)) t11 = old.Tone(p2, rhy.Unit(1)) melody0 = old.Melody((t0, t1)) melody1 = old.Melody((t2, t3)) melody2 = old.Melody((t6, t6, t0, t7)) # duration 5.5 melody3 = old.Melody((t7, t6, t2, t2)) # duration 4.5 melody4 = old.Melody((t7, t7, t7, t2, t2)) # duration 3.5 melody5 = old.Melody((t10, t9, t3, t8, t0)) # duration 5.5 melody6 = old.Melody((t6, t6, t2, t7)) # duration 5.5 poly0 = old.Polyphon([melody0, melody1]) poly1 = old.Polyphon([melody2, melody3, melody4]) poly2 = old.Polyphon([melody6, melody5]) def test_chordify(self): chord0 = old.Chord(ji.JIHarmony([self.t0.pitch, self.t2.pitch]), rhy.Unit(1)) chord1 = old.Chord(ji.JIHarmony([self.t1.pitch, self.t3.pitch]), rhy.Unit(1)) cadence0 = old.Cadence([chord0, chord1]) self.assertEqual(cadence0, self.poly0.chordify()) chord0 = old.Chord(ji.JIHarmony([self.p0, self.p5]), rhy.Unit(0.5)) chord1 = old.Chord(ji.JIHarmony([self.p0, self.p1]), rhy.Unit(1.5)) chord2 = old.Chord(ji.JIHarmony([self.p0, self.p3]), rhy.Unit(1)) chord3 = old.Chord(ji.JIHarmony([self.p0]), rhy.Unit(1)) chord4 = old.Chord(ji.JIHarmony([self.p0, self.p2]), rhy.Unit(0.5)) chord5 = old.Chord(ji.JIHarmony([self.p0]), rhy.Unit(0.5)) expected = old.Cadence([chord0, chord1, chord2, chord3, chord4, chord4, chord5]) result = self.poly2.chordify( harmony_class=ji.JIHarmony, cadence_class=old.Cadence, add_longer=True ) for ex, re in zip(expected, result): print(ex, re) self.assertEqual(expected, result) def test_find_simultan_events(self): simultan_events0 = self.poly0.find_simultan_events(0, 0) self.assertEqual(simultan_events0, (self.poly0[1].convert2absolute()[0],)) simultan_events1 = self.poly0.find_simultan_events(1, 1) self.assertEqual(simultan_events1, (self.poly0[0].convert2absolute()[1],)) simultan_events2 = self.poly1.find_simultan_events(0, 1) simultan_events2_comp = ( self.poly1[1].convert2absolute()[1], self.poly1[1].convert2absolute()[2], self.poly1[1].convert2absolute()[3], self.poly1[2].convert2absolute()[-2], self.poly1[2].convert2absolute()[-1], ) self.assertEqual(simultan_events2, simultan_events2_comp) simultan_events3 = self.poly1.find_simultan_events(1, 1) simultan_events3_comp = ( self.poly1[0].convert2absolute()[0], self.poly1[0].convert2absolute()[1], self.poly1[2].convert2absolute()[1], self.poly1[2].convert2absolute()[2], self.poly1[2].convert2absolute()[3], ) self.assertEqual(simultan_events3, simultan_events3_comp) def test_find_exact_simultan_events(self): poly2 = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3), old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 1), old.Tone(ji.r(4, 3), 2)]), ) ) simultan_events4 = poly2.find_exact_simultan_events(0, 1) simultan_events4_expected = ( old.Tone(ji.r(3, 2), 1, 1), old.Tone(ji.r(3, 2), 2, 2), old.Tone(ji.r(4, 3), 1, 1), ) self.assertEqual(simultan_events4, simultan_events4_expected) simultan_events0 = self.poly0.find_exact_simultan_events(0, 0) self.assertEqual(simultan_events0, (self.poly0[1][0],)) simultan_events1 = self.poly0.find_exact_simultan_events(0, 0, False) self.assertEqual(simultan_events1, (self.poly0[1].convert2absolute()[0],)) simultan_events2 = self.poly1.find_exact_simultan_events(1, 0) simultan_events2_expected = (self.poly1[2][0], self.poly1[2][0]) self.assertEqual(simultan_events2, simultan_events2_expected) simultan_events3 = self.poly1.find_exact_simultan_events(1, 1) simultan_events3_expected = (self.t8, self.t7, self.t7, self.t7, self.t2) self.assertEqual(simultan_events3, simultan_events3_expected) def test_cut_up_by_time(self): poly0 = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3), old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 1), old.Tone(ji.r(4, 3), 2)]), ) ) poly0_cut = poly0.cut_up_by_time(1, 3) poly0_cut_expected = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 1), old.Tone(ji.r(1, 1), 1)]), old.Melody([old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly0_cut, poly0_cut_expected) poly1_cut = poly0.cut_up_by_time(1, 3, add_earlier=False) poly1_cut_expected = old.Polyphon( ( old.Melody([old.Rest(1), old.Tone(ji.r(1, 1), 1)]), old.Melody([old.Rest(2)]), old.Melody([old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly1_cut, poly1_cut_expected) poly2_cut = poly0.cut_up_by_time(1, 3, hard_cut=False) poly2_cut_expected = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3)]), old.Melody([old.Rest(1), old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly2_cut[2], poly2_cut_expected[2]) def test_cut_up_by_idx(self): poly0 = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 2), old.Tone(ji.r(1, 1), 3)]), old.Melody([old.Tone(ji.r(3, 2), 3), old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 1), old.Tone(ji.r(4, 3), 2)]), ) ) poly0_cut = poly0.cut_up_by_idx(2, 1) poly0_cut_expected = old.Polyphon( ( old.Melody([old.Tone(ji.r(1, 1), 1), old.Tone(ji.r(1, 1), 1)]), old.Melody([old.Tone(ji.r(3, 2), 2)]), old.Melody([old.Tone(ji.r(4, 3), 2)]), ) ) self.assertEqual(poly0_cut, poly0_cut_expected)
def convert2cadence(self, gender=True): return old.Polyphon(self.convert2voices()).chordify()
def __init__( self, action_per_voice: tuple, sound_per_voice: tuple, allowed_pitches_per_voice: tuple, allowed_attacks_per_voice: tuple, weights_per_beat: tuple, predefined_voices: tuple = tuple([]), allow_unisono: bool = True, allow_melodic_octaves: bool = False, harmonic_weight: float = 2, melodic_weight: float = 1, random_seed: int = 1000, harmonic_range: tuple = (0, 1), melodic_range: tuple = (0, 1), distance_range: tuple = (0, 1), metrical_range: tuple = (0, 1), ) -> None: self.test_arguments_for_equal_size( "voice specific arguments", ( action_per_voice, sound_per_voice, allowed_attacks_per_voice, allowed_pitches_per_voice, ), lambda data: len(data), ) self.test_arguments_for_equal_size( "allowed_attacks_per_voice", allowed_attacks_per_voice + tuple(vox.delay for vox in predefined_voices), lambda rhythm: sum(rhythm), ) # set attributes available_pitches = functools.reduce(operator.add, allowed_pitches_per_voice) for vox in predefined_voices: available_pitches += tuple(p for p in vox.pitch if not p.is_empty) import random random.seed(random_seed) self._average_distance_per_voice = self._detect_average_distance_per_voice( action_per_voice, allowed_attacks_per_voice ) self._linspace_for_distance_likelihood = interpolations.Linear()( 0, 1, self._GRIDSIZE ) self._duration = len(weights_per_beat) self._melodic_weight = melodic_weight self._harmonic_weight = harmonic_weight self._predefined_voices = predefined_voices self._predefined_polyphon = old.Polyphon(predefined_voices) self._weights_per_beat = tools.scale(weights_per_beat, *metrical_range) self._sound_per_voice = sound_per_voice self._allowed_pitches_per_voice = allowed_pitches_per_voice self._absolute_allowed_attacks_per_voice = tuple( tuple(r.convert2absolute()) for r in allowed_attacks_per_voice ) self._random_module = random self._n_voices = len(sound_per_voice) self._melodicity_dict_per_voice = self._detect_melodicity_dict_per_voice( allowed_pitches_per_voice ) self._harmonicity_dict = self._make_harmonicity_dict(available_pitches) self._allow_melodic_octaves = allow_melodic_octaves self._allow_unisono = allow_unisono self._position_and_voices_pairs = self._detect_position_and_voices_pairs( allowed_attacks_per_voice ) super().__init__(self._make_voices())