def convert2cadence(self, tempo_factors_per_unit: tuple, delays: tuple) -> old.JICadence: """ """ def return_item_and_sizes(element, lv=0) -> tuple: if type(element) == ji.JIHarmony or element == mel.TheEmptyPitch: return ((element, lv), ) else: ret = tuple([]) for tup in (return_item_and_sizes(it, lv + 1) for it in element): ret += tup return ret divisions_per_elements = int(tempo.TempoLine.divisions_per_element) cadence = [] unit_count = 0 for meter in self.__structure: for compound in meter: for unit in compound: delay = delays[unit_count] if delay: if cadence: cadence[-1].delay += delay.duration cadence[-1].duration += delay.duration else: cadence.append(old.Rest(delay.duration)) factors = tempo_factors_per_unit[unit_count] abstract_delays = [] harmonies = [] for element in unit: item_and_size_pairs = return_item_and_sizes(element) for pair in item_and_size_pairs: harmonies.append(pair[0]) de = int(divisions_per_elements * (1 / (2**pair[1]))) abstract_delays.append(de) real_delays = tuple( itertools.accumulate([0] + abstract_delays)) real_delays = tuple( sum(factors[idx0:idx1]) for idx0, idx1 in zip(real_delays, real_delays[1:])) for h, de in zip(harmonies, real_delays): if h: cadence.append(old.Chord(h, de)) else: cadence.append(old.Rest(de)) unit_count += 1 cadence = old.JICadence(cadence).discard_rests() return cadence
def solve(self, a: int, b: int, x: int, mode: modes.Mode, rhythm: tuple) -> tuple: try: assert all((rhythm[0] >= 5, rhythm[1] >= 1)) except AssertionError: msg = "Rhythmical structure has to be bigger than (4, 0)." raise ValueError(msg) primes = (a, b, x) a, b = primes[self.main_prime], primes[self.side_prime] x = tuple(p for p in (mode.x, mode.y, mode.z) if p not in (a, b))[0] data0 = FlippedEx.detect_data_for_pitches( ((x, b), (a, b), (a, x), (b, x), (b, a), (x, a)), mode) data1 = FlippedEx.detect_data_for_pitches( ((a, x), (a, b), (x, b), (x, a), (b, a), (b, x)), mode) if data0[2] > data1[2]: data = data0 else: data = data1 if rhythm[1] == 1: rhythms_middle = tools.euclid(rhythm[0], 5) rhythms_else = rhythm[0] middle = tuple( old.Tone(p, r) for p, r in zip((mel.TheEmptyPitch, ) + data[0], rhythms_middle)) return ((old.Rest(rhythms_else), ), middle, (old.Rest(rhythms_else), )) else: complete_duration = rhythm[0] * rhythm[1] amount_pitches = len(data[0]) + len( data[1]) + 1 # middle + high + rest rhythmic_ranking = indispensability.bar_indispensability2indices( indispensability.indispensability_for_bar( rhythm))[:amount_pitches] positions_middle = rhythmic_ranking[::2] positions_high = (0, ) + rhythmic_ranking[1::2] low_line = (old.Rest(complete_duration), ) middle_line = (old.Tone(p, r) for p, r in zip( (mel.TheEmptyPitch, ) + data[0], (b - a for a, b in zip( positions_middle, positions_middle[1:] + (complete_duration, ), )), )) high_line = (old.Tone(p, r) for p, r in zip( (mel.TheEmptyPitch, ) + data[1], (b - a for a, b in zip(positions_high, positions_high[1:] + (complete_duration, ))), )) return (low_line, middle_line, high_line)
def test_split(self): tone0 = old.Tone(ji.r(1, 1, 2), rhy.Unit(2), rhy.Unit(1)) tone0B = old.Tone(ji.r(1, 1, 2), rhy.Unit(1), rhy.Unit(1)) tone1 = old.Tone(ji.r(1, 1, 2), rhy.Unit(3), rhy.Unit(1)) tone1B = old.Tone(ji.r(1, 1, 2), rhy.Unit(1), rhy.Unit(1)) pause0 = old.Rest(rhy.Unit(1)) pause1 = old.Rest(rhy.Unit(2)) melody0 = old.Melody([tone0, tone1]) melody1 = old.Melody([tone0B, pause0, tone1B, pause1]) self.assertEqual(melody0.split(), melody1)
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 render(self, name: str, cadence: old.Cadence) -> subprocess.Popen: seq = [] for chord in cadence: dur = float(chord.delay) if chord.pitch != mel.TheEmptyPitch and bool(chord.pitch): size = len(chord.pitch) for idx, pi in enumerate(chord.pitch): if idx + 1 == size: de = float(dur) else: de = 0 if pi != mel.TheEmptyPitch: if chord.volume: volume = chord.volume else: volume = self.volume tone = midiplug.PyteqTone( ji.JIPitch(pi, multiply=self.CONCERT_PITCH), de, dur, volume=volume, ) else: tone = midiplug.PyteqTone( mel.TheEmptyPitch, de, dur, volume=self.volume ) seq.append(tone) else: seq.append(old.Rest(dur)) pt = midiplug.Pianoteq(tuple(seq), self.available_midi_notes) return pt.export2wav(name, 1, self.preset, self.fxp)
def return_cadence_and_instrument_for_complex(idx, tf, time_lv, is_sutained, cadences, instruments, is_full_or_not_per_sec): def detect_correct_instrument_for_empty_section( idx, is_full_or_not_per_sec): for is_full_or_not in is_full_or_not_per_sec[idx + 1:]: if is_full_or_not[0]: return instruments[1] elif is_full_or_not[1]: return instruments[2] for is_full_or_not in reversed(is_full_or_not_per_sec[:idx]): if is_full_or_not[0]: return instruments[1] elif is_full_or_not[1]: return instruments[2] return instruments[0] if all(is_full_or_not_per_sec[idx]): return cadences[0], instruments[0] elif all(tuple(not b for b in is_full_or_not_per_sec[idx])): i = detect_correct_instrument_for_empty_section( idx, is_full_or_not_per_sec) return old.JICadence([old.Rest(tf.size)]), i else: if cadences[0]: return cadences[0], instruments[1] else: return cadences[1], instruments[2]
class ToneSetTest(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)) t0_set = old.Tone(p0, rhy.Unit(0), rhy.Unit(1)) t1_set = old.Tone(p1, rhy.Unit(1), rhy.Unit(1)) t2_set = old.Tone(p2, rhy.Unit(2), rhy.Unit(1)) t3_set = old.Tone(p3, rhy.Unit(3), rhy.Unit(1)) t4_set = old.Tone(p4, rhy.Unit(4), rhy.Unit(1)) t5_set = old.Tone(p5, rhy.Unit(5), rhy.Unit(1)) t6_set = old.Tone(p5, rhy.Unit(1), rhy.Unit(5)) mel0 = old.Melody([t0, t1, t2, t3, t4, t5]) mel1 = old.Melody([old.Rest(rhy.Unit(1)), t1, t2, t3, t4, t5]) mel2 = old.Melody([t0, t1]) set0 = old.ToneSet([t0_set, t1_set, t2_set, t3_set, t4_set, t5_set]) set1 = old.ToneSet([t1_set, t2_set, t3_set, t4_set, t5_set]) set2 = old.ToneSet([t1_set, t6_set, t2_set]) def test_constructor(self): self.assertEqual(old.ToneSet.from_melody(ToneSetTest.mel0), ToneSetTest.set0) def test_converter(self): self.assertEqual(ToneSetTest.mel0, ToneSetTest.set0.convert2melody()) self.assertEqual(ToneSetTest.mel1, ToneSetTest.set1.convert2melody()) def test_pop_by(self): popped = ToneSetTest.set0.copy().pop_by_pitch(ToneSetTest.p0, ToneSetTest.p1) self.assertEqual(ToneSetTest.mel2, popped.convert2melody()) popped = ToneSetTest.set0.copy().pop_by_start(rhy.Unit(0), rhy.Unit(1)) self.assertEqual(ToneSetTest.mel2, popped.convert2melody()) def test_pop_by_time(self): for t in self.set0.pop_by_time(1): self.assertEqual(t, self.t1_set) for t in self.set0.pop_by_time(1.5): self.assertEqual(t, self.t1_set) test_set0 = self.set2.pop_by_time(1.5) test_set_compare0 = old.ToneSet([self.t1_set, self.t6_set]) test_set1 = self.set2.pop_by_time(2.7) test_set_compare1 = old.ToneSet([self.t2_set, self.t6_set]) self.assertEqual(test_set0, test_set_compare0) self.assertEqual(test_set1, test_set_compare1) def test_pop_by_correct_dur_and_delay(self): poped_by = self.set0.pop_by_pitch(self.p0, self.p5) melody = poped_by.convert2melody() self.assertEqual(melody[0].delay, rhy.Unit(5)) self.assertEqual(melody[0].duration, rhy.Unit(1))
def solve(self, a: int, b: int, x: int, mode: modes.Mode, rhythm: tuple) -> tuple: primes0, primes1 = self.detect_start_and_stop_primes(a, b, x, mode) pitch0, pitch1 = tuple( AbstractExpansion.transform_primes2pitches(p, mode) for p in (primes0, primes1)) high_pitches = self.detect_high_pitches(primes0, primes1, mode) complete_duration = rhythm[0] * rhythm[1] low_line = old.Rest(complete_duration) middle_line = tuple( old.Tone(p, rhythm[1]) for p in ShiftedEx.detect_middle_pitches( pitch0, pitch1, rhythm[0])) high_line = ShiftedEx.make_high_line(high_pitches, rhythm) return (low_line, middle_line, high_line)
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_time(self): t0 = old.Tone(ji.r(1, 1), rhy.Unit(2)) t1 = old.Tone(ji.r(2, 1), rhy.Unit(2)) t2 = old.Tone(ji.r(1, 1), rhy.Unit(1)) r0 = old.Rest(1) melody0 = old.Melody([t0, t1, t1, t0, t1]) melody1 = old.Melody([t1, t1, t0]) melody2 = old.Melody([r0, t1, t1, t0]) melody3 = old.Melody([t2, t1, t1, t0]) melody4 = old.Melody([t1, t1, t2]) self.assertEqual(melody0.cut_up_by_time(2, 8), melody1) self.assertEqual(melody0.cut_up_by_time(1, 8), melody2) self.assertEqual(melody0.cut_up_by_time(1, 8, add_earlier=True), melody3) self.assertEqual(melody0.cut_up_by_time(2, 7, hard_cut=True), melody4) self.assertEqual(melody0.cut_up_by_time(2, 7, hard_cut=False), melody1)
def estimate_best_meter(self, melody: old.Melody) -> tuple: """Return (Melody, TimeSignature) - pair.""" meter_fitness_pairs = [] for meter in self.potential_meters: n_potential_upbeats = int( fractions.Fraction(meter[0].numerator, meter[0].denominator) / fractions.Fraction(1, 8) ) for n_upbeats in range(n_potential_upbeats): adadpted_melody = melody.copy() if n_upbeats: adadpted_melody.insert( 0, old.Rest(n_upbeats * fractions.Fraction(1, 8)) ) metricity = self._calculate_metricity_of_melody(meter, adadpted_melody) meter_fitness_pairs.append((adadpted_melody, meter[0], metricity)) return max(meter_fitness_pairs, key=operator.itemgetter(2))[:2]
def __call__(self, name: str, cadence: old.JICadence) -> None: seq = [] for chord in cadence: dur = float(chord.delay) if chord.pitch != mel.TheEmptyPitch and bool(chord.pitch): size = len(chord.pitch) for idx, pi in enumerate(chord.pitch): if idx + 1 == size: de = float(dur) else: de = 0 tone = pyteq.PyteqTone( ji.JIPitch(pi, multiply=self.CONCERT_PITCH), de, dur, volume=self.volume, ) seq.append(tone) else: seq.append(old.Rest(dur)) pt = pyteq.Pianoteq(tuple(seq), self.available_midi_notes) pt.export2wav(name, 1, self.preset, self.fxp)
def make_diva_sequence(self, voice: tuple, tempo_factor: float) -> tuple: diva_sequence = [] for tone in voice: delay = tone.delay * tempo_factor if tone.pitch.is_empty: dt = old.Rest(delay) else: div_synth_args = { arg: next(self.init_arguments[arg]) for arg in self.init_arguments } dt = midiplug.DivaTone(ji.JIPitch( tone.pitch, multiply=globals.CONCERT_PITCH), delay, delay, volume=tone.volume, **div_synth_args) diva_sequence.append(dt) return tuple(diva_sequence)
def test_duration(self): self.assertEqual(self.melody0.duration, sum(self.rhy0)) melody1 = old.Melody([old.Rest(3)]) self.assertEqual(melody1.duration, 3)
def make_high_line(pitches: tuple, rhythm: tuple) -> tuple: def convert_pattern2pitches(pattern: tuple) -> tuple: return tuple(pitches[idx] if idx else mel.TheEmptyPitch for idx in pattern) if rhythm[1] == 1: return (old.Rest(rhythm[0] * rhythm[1]), ) elif rhythm[1] == 2: pattern0 = (0, 1, 0, None) pattern1 = (0, None, 0, 2) amount_pattern = (rhythm[0] - 1) // 2 pattern_cycle = itertools.cycle( tuple( convert_pattern2pitches(p) for p in (pattern0, pattern1))) pitch_line = functools.reduce( operator.add, tuple(next(pattern_cycle) for n in range(amount_pattern))) if rhythm[0] % 2 == 0: pitch_line = (pitches[0], mel.TheEmptyPitch) + pitch_line pitch_line = (mel.TheEmptyPitch, ) + pitch_line + (pitches[-1], ) try: assert len(pitch_line) == rhythm[0] * rhythm[1] except AssertionError: raise AssertionError("exp: {0} but {1}".format( len(pitch_line), rhythm[0] * rhythm[1])) return tuple( old.Melody(old.Tone(p, 1) for p in pitch_line).tie_pauses().discard_rests()) elif rhythm[1] == 3: patternA = (mel.TheEmptyPitch, pitches[1], pitches[0]) patternB = (mel.TheEmptyPitch, pitches[2], pitches[0]) dead_pattern = (mel.TheEmptyPitch, mel.TheEmptyPitch, pitches[0]) pattern_type_cycle = itertools.cycle((1, 0, 0)) choice_cycle = itertools.cycle((0, 1)) choices = tuple( next(choice_cycle) for n in range(((rhythm[0] - 1) // 2) * 2)) if rhythm[0] % 2 == 0: choices = (0, ) + choices choices = (1, ) + choices pattern_types = (next(pattern_type_cycle) for n in choices) pitch_line = functools.reduce( operator.add, tuple((patternA, patternB)[choice] if ptype == 0 else dead_pattern for choice, ptype in zip(choices, pattern_types)), ) try: assert len(pitch_line) == rhythm[0] * rhythm[1] except AssertionError: raise AssertionError("exp: {0} but {1}".format( len(pitch_line), rhythm[0] * rhythm[1])) return tuple( old.Melody(old.Tone(p, 1) for p in pitch_line).tie_pauses().discard_rests()) else: msg = "No solution for rhythmic structure {0} available".format( rhythm) raise ValueError(msg)