def _synthezise(name: str, instrument: str, scale: tuple) -> None: """make short sound files for string players to get used to intonation""" # (1) generate file where scale get played up & down duration_per_tone = 1.5 rest_duration = 0.75 melody = old.Melody([]) for pitch in scale + tuple(reversed(scale))[1:]: melody.append(old.Tone(pitch, duration_per_tone)) melody.append(old.Tone(mel.TheEmptyPitch, rest_duration)) synth = synthesis.SimpleCsoundSinePlayer(melody) # for debugging: # synth.remove_files = False # synth.print_output = True synth.concert_pitch = globals_.CONCERT_PITCH synth.render("{}/soundfiles/wav/scale_{}".format(name, instrument)) instrument_path = "{}/soundfiles/wav/{}".format(name, instrument) tools.igmkdir(instrument_path) # (2) generate for each scale degree one file single_tone_duration = 3 duration_per_tone_rest_duration = 0.75 for idx, pitch in enumerate(scale): melody = old.Melody( [ old.Tone(pitch, single_tone_duration), old.Tone(mel.TheEmptyPitch, duration_per_tone_rest_duration), ] ) synth = synthesis.SimpleCsoundSinePlayer(melody) synth.concert_pitch = globals_.CONCERT_PITCH synth.render("{}/{}".format(instrument_path, idx + 1))
def test_set_item(self): t0 = old.Tone(ji.r(1, 1), rhy.Unit(2)) t1 = old.Tone(ji.r(2, 1), rhy.Unit(2)) melody0 = old.Melody([t0, t1]) melody1 = old.Melody([t1, t0]) melody0[0], melody0[1] = melody1[0], melody1[1] self.assertEqual(melody0, melody1)
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_tie(self): melodyTest0 = old.Melody([old.Tone(self.t0.pitch, self.t0.delay * 3)]) self.assertEqual(self.melody0.tie(), melodyTest0) melodyTest1 = old.Melody([old.Tone(self.t0.pitch, self.t0.delay * 2), self.t1]) melody1 = old.Melody([self.t0, self.t0, self.t1]) self.assertEqual(melody1.tie(), melodyTest1) melody2 = old.Melody([self.t0, self.t1, self.t0]) self.assertEqual(melody2.tie(), melody2)
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 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 __call__(self, melody: old.Melody) -> old.Melody: new_melody = old.Melody([]) for tone in melody: if not tone.pitch.is_empty and next(self.__add_tremolo_decider): rhythm = tone.delay duration_per_attack = [] tremolo_size_generator = next( self.__tremolo_size_generator_per_tone) while sum(duration_per_attack) < rhythm: duration_per_attack.append(next(tremolo_size_generator)) if len(duration_per_attack) > 1: duration_per_attack = duration_per_attack[:-1] difference = rhythm - sum(duration_per_attack) duration_per_attack[-1] += difference else: difference = sum(duration_per_attack) - rhythm duration_per_attack[-1] -= difference for duration in duration_per_attack: new_melody.append( old.Tone(tone.pitch.copy(), duration, volume=tone.volume)) else: new_melody.append(tone.copy()) return new_melody
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 __call__( self, melody: old.Melody, is_consonance_per_tone: tuple, spectrum_profile_per_tone: tuple, ) -> old.Melody: new_melody = old.Melody([]) new_is_consonance_per_tone = [] new_spectrum_profile_per_tone = [] for tone, is_consonance, spectrum_profile in zip( melody, is_consonance_per_tone, spectrum_profile_per_tone ): new_is_consonance_per_tone.append(is_consonance) new_spectrum_profile_per_tone.append(spectrum_profile) test0 = is_consonance or not self.__only_on_non_dissonant_pitches test0 = test0 and not tone.pitch.is_empty if test0 and next(self.__add_tremolo_decider): rhythm = tone.delay duration_per_attack = [] tremolo_size_generator = next(self.__tremolo_size_generator_per_tone) while sum(duration_per_attack) < rhythm: duration_per_attack.append(next(tremolo_size_generator)) if len(duration_per_attack) > 1: duration_per_attack = duration_per_attack[:-1] difference = rhythm - sum(duration_per_attack) duration_per_attack[-1] += difference else: difference = sum(duration_per_attack) - rhythm duration_per_attack[-1] -= difference is_first = True for duration in duration_per_attack: if not is_first: new_spectrum_profile_per_tone.append(spectrum_profile) new_is_consonance_per_tone.append(False) volume = tone.volume * self.__tremolo_volume_factor else: volume = tone.volume new_melody.append( old.Tone(tone.pitch.copy(), duration, volume=volume) ) is_first = False else: new_melody.append(tone.copy()) return ( new_melody, tuple(new_is_consonance_per_tone), tuple(new_spectrum_profile_per_tone), )
def make_melody(self) -> old.Melody: if self._gender: self._melody_register = -self._melody_register melody_pitches = tuple( p if p.is_empty else p.register(p.octave + self._melody_register) for p in self._melody_pitches) transposition_pitch = ( (globals.FEMALE_SOIL, globals.MALE_SOIL)[self._gender].pitches_per_vox_per_bar[ self._bar_number][0][0].normalize()) if transposition_pitch.cents > 600: transposition_pitch = transposition_pitch.register(-1) melody_pitches = tuple(p if p.is_empty else p + transposition_pitch for p in melody_pitches) if self._gender: melody_pitches = tuple( p if p.is_empty else p.inverse(transposition_pitch) for p in melody_pitches) distributed_beats = tools.euclid( self._n_bars * self._metrical_numbers[0], sum(self._melody_beats)) absolute_rhythms = tools.accumulate_from_zero(self._melody_beats) distributed_rhythms = tuple( sum(distributed_beats[pos0:pos1]) for pos0, pos1 in zip(absolute_rhythms, absolute_rhythms[1:])) absolute_rhythms = tools.accumulate_from_zero(distributed_rhythms) rhythms = tuple( sum(self._rhythms[0][pos0:pos1]) for pos0, pos1 in zip(absolute_rhythms, absolute_rhythms[1:])) return old.Melody(tuple(map(old.Tone, melody_pitches, rhythms)))
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 __call__(self, melody: old.Melody) -> tuple: """Return (Melody, MetricalLoop) - pair.""" possible_mappings = tuple({ "violin": p[0], "viola": p[1], "cello": p[2] } for p in itertools.permutations(globals_.METRICAL_PRIMES)) melody = old.Melody(melody) hof = crosstrainer.MultiDimensionalRating(fitness=[1, -1]) c = 0 for metrical_loop in self._available_metrical_loops: for mapping in possible_mappings: transformation = metrical_loop.transform_melody( melody, mapping) relevant_data, fitness = transformation hof.append(relevant_data, *fitness) c += 1 best = hof.convert2list()[-1] melody, spread_metrical_loop = best[0] # it's only a lambda function before for preventing to generate unused objects spread_metrical_loop = spread_metrical_loop() return melody, spread_metrical_loop.bars, spread_metrical_loop
def harmonic_synthesis(poly_per_interlocking: tuple): import pyteq for poly_idx, poly in enumerate(poly_per_interlocking): for melody_idx, voice in enumerate(poly): voice = old.Melody(voice[:280]) melody = [ pyteq.PyteqTone( ji.JIPitch(t.pitch, multiply=250), t.delay, t.duration, volume=t.volume, impedance=2, q_factor=0.2, string_length=9.9, sustain_pedal=1, ) if t.pitch != mel.TheEmptyPitch else pyteq.PyteqTone( t.pitch, t.delay, t.duration) for t in voice ] instr_range = tuple(n for n in range(10, 125)) f = pyteq.Pianoteq(melody, available_midi_notes=instr_range) f.export2wav( "pianoteq_output/glitter_{0}_{1}".format(poly_idx, melody_idx), # preset='"Kalimba Spacey"', preset='"Celtic Harp Bright"', )
def _filter_raw_data_and_convert2melody(raw_data: tuple) -> old.Melody: melody = old.Melody([], time_measure="absolute") for tone in raw_data: pitch, start, stop_time, volume = tone if melody: stop_last_tone = melody[-1].duration difference = start - stop_last_tone if difference > 0: melody.append(old.Tone(mel.TheEmptyPitch, stop_last_tone, start)) elif difference < 0: melody[-1].duration += difference else: if start != 0: melody.append(old.Tone(mel.TheEmptyPitch, 0, start)) melody.append(old.Tone(pitch, start, stop_time, volume=volume)) melody = melody.convert2relative() if melody[0].pitch.is_empty: melody = melody[1:] return melody
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 test_convert2relative(self): melody_converted = old.Melody( ( old.Tone(self.p0, self.d0 * 0, self.d0 * 1), old.Tone(self.p0, self.d0 * 1, self.d0 * 2), old.Tone(self.p0, self.d0 * 2, self.d0 * 3), ), time_measure="absolute", ) self.assertEqual(melody_converted.convert2relative(), self.melody0)
def convert2voices(self, gender=True) -> tuple: len_voices = tuple(len(v) for v in self.voices) maxima = max(len_voices) rhythm_per_vox = [maxima // lv for lv in len_voices] return tuple( old.Melody( [ old.Tone(f.convert2pitch(gender=gender).normalize(), rhythm) for f in vox ] ) for vox, rhythm in zip(self.voices, rhythm_per_vox) )
def quantizise( self, stretch_factor: float = 1, n_divisions: int = 8, min_tone_size: fractions.Fraction = 0, min_rest_size: fractions.Fraction = fractions.Fraction(1, 10), ) -> tuple: delays = rhy.Compound(tuple( t.delay for t in self.tones)).stretch(stretch_factor) tones = old.Melody(self.tones).copy() tones.delay = delays tones.dur = delays melody = quantizise.quantisize_rhythm(tones, n_divisions, min_tone_size, min_rest_size) return melody.pitch, melody.delay
def test_set_attributes(self): melody0 = old.Melody([]) melody0.__set_pitch__(self.mel0) melody0.__set_delay__(self.rhy0) self.assertEqual(melody0.__get_pitch__(), self.mel0) self.assertEqual(melody0.__get_delay__(), self.rhy0) self.assertEqual(melody0.pitch, self.mel0) self.assertEqual(melody0.delay, self.rhy0) melody0.__set_pitch__(self.mel1) melody0.__set_delay__(self.rhy1) melody0.__set_duration__(self.rhy0) self.assertEqual(melody0.__get_pitch__(), self.mel1) self.assertEqual(melody0.__get_delay__(), self.rhy1) self.assertEqual(melody0.__get_duration__(), self.rhy0) self.assertEqual(melody0.pitch, self.mel1) self.assertEqual(melody0.delay, self.rhy1) self.assertEqual(melody0.dur, self.rhy0)
def __init__( self, tempo_factor: float, pitches: tuple, rhythm: binr.Compound, discard_rests: bool = True, ): self.__tempo_factor = tempo_factor self.__pitches = pitches self.__rhythm = rhythm melody = old.Melody( old.Tone(ji.JIPitch(p, multiply=globals.CONCERT_PITCH), r * tempo_factor) if not p.is_empty else old. Rest(r * tempo_factor) for p, r in zip(pitches, rhythm)) if discard_rests: melody = melody.discard_rests() super().__init__(melody, attack=0.08, decay=0.05, release=0.25)
def simple_synthesis(melodies: tuple, make_diva=True): import random random.seed(10) import pyteq for idx, voice in enumerate(melodies): # voice = old.Melody(voice[:120]).tie() voice = old.Melody(voice[:200]) if make_diva: melody_diva = [ pyteq.DivaTone( ji.JIPitch(t.pitch, multiply=250), t.delay, t.duration, glissando=t.glissando, volume=t.volume, ) if t.pitch != mel.TheEmptyPitch else pyteq.PyteqTone( t.pitch, t.delay, t.duration) for t in voice ] pyteq.Diva(melody_diva).export( "pianoteq_output/test_diva{0}.mid".format(idx)) melody_pteq = [ pyteq.PyteqTone( ji.JIPitch(t.pitch, multiply=250), t.delay, t.duration, volume=t.volume, glissando=t.glissando, # impedance=random.uniform(2.801, 2.98), q_factor=random.uniform(0.201, 0.28), string_length=random.uniform(8.9, 9.8), sustain_pedal=1, ) if t.pitch != mel.TheEmptyPitch else pyteq.PyteqTone( t.pitch, t.delay, t.duration) for t in voice ] f = pyteq.Pianoteq(melody_pteq, available_midi_notes=tuple(n for n in range(20, 125))) f.export2wav("pianoteq_output/test{0}".format(idx), preset='"Concert Harp Daily"')
def quantisize_rhythm( melody: old.Melody, n_divisions: int = 8, min_tone_size: fractions.Fraction = 0, min_rest_size: fractions.Fraction = fractions.Fraction(1, 10), ) -> tuple: new_melody = [] min_size = fractions.Fraction(1, n_divisions) left_over = 0 for tone in melody: r = tone.delay if tone.pitch.is_empty: is_addable = r >= min_rest_size else: is_addable = r >= min_tone_size if is_addable: r += left_over left_over = 0 quantisized = rhy.Unit(round(r * n_divisions) / n_divisions).fraction if quantisized == 0: quantisized = min_size new_tone = tone.copy() new_tone.delay = quantisized new_tone.duration = quantisized new_melody.append(new_tone) else: left_over += r new_melody[-1].delay += left_over new_melody[-1].duration += left_over return old.Melody(new_melody)
def synthesize( self, stretch_factor: float = 1, n_divisions: int = 8, min_tone_size: fractions.Fraction = 0, min_rest_size: fractions.Fraction = fractions.Fraction(1, 10), concert_pitch: float = None, tie_notes: bool = False, remove_rests: bool = False, ) -> None: if not concert_pitch: concert_pitch = self.concert_pitch pitches, delays = self.quantizise( stretch_factor=stretch_factor, n_divisions=n_divisions, min_tone_size=min_tone_size, min_rest_size=min_rest_size, ) melody = old.Melody([old.Tone(p, d) for p, d in zip(pitches, delays)]) if remove_rests: melody = melody.discard_rests() if tie_notes: melody = melody.tie() sequence = [] for tone in melody: p = tone.pitch d = tone.delay p.multiply = concert_pitch d *= 4 sequence.append(midiplug.PyteqTone(p, d, d)) midiplug.Pianoteq(sequence).export2wav("{}_transcription".format( self.name), preset='"Erard Player"')
def _convert_data2melody( data: tuple, name: str, tempo_estimation_method: str = "essentia") -> tuple: tempo = Transcription.estimate_tempo(name, method=tempo_estimation_method) melody = old.Melody([], time_measure="absolute") for tone in data: pitch, start, stop_time, volume = tone if melody: stop_last_tone = melody[-1].duration difference = start - stop_last_tone if difference > 0: melody.append( old.Tone(mel.TheEmptyPitch, stop_last_tone, start)) elif difference < 0: melody[-1].duration += difference else: if start != 0: melody.append(old.Tone(mel.TheEmptyPitch, 0, start)) melody.append(old.Tone(pitch, start, stop_time, volume=volume)) melody = melody.convert2relative() if melody[0].pitch.is_empty: melody = melody[1:] factor = tempo / 60 melody.delay = tuple(d * factor for d in melody.delay) melody.dur = tuple(d * factor for d in melody.dur) return tuple(melody)
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 __init__( self, chapter: int = 59, verse: int = "opening", time_transcriber=transcriptions.TimeTranscriber(), octave_of_first_pitch: int = 0, use_full_scale: bool = False, tempo_factor: float = 0.5, harmonic_field_max_n_pitches: int = 4, harmonic_field_minimal_harmonicity: float = 0.135, harmonic_tolerance: float = 0.5, # a very low harmonic tolerance won't add any # additional harmonic pitches, while a very high tolerance will try to add as many # additional harmonic pitches as possible. harmonic_pitches_add_artifical_harmonics: bool = True, harmonic_pitches_add_normal_pitches: bool = True, harmonic_pitches_tonality_flux_maximum_octave_difference_from_melody_pitch: tuple = ( 1, 0, ), harmonic_pitches_complex_interval_helper_maximum_octave_difference_from_melody_pitch: tuple = ( 1, 0, ), max_rest_size_to_ignore: fractions.Fraction = fractions.Fraction(1, 4), maximum_deviation_from_center: float = 0.5, # rhythmical orientation data ro_temperature: float = 0.7, # a low temperature increases the chance for a # beat to get added. ro_density: float = 0.5, # a high density value increases the amount of # orientation beats. area_density_maker: infit.InfIt = None, # a higher value # leads to more perforated melodic pitches. area_density_reference_size: fractions.Fraction = fractions.Fraction( 1, 2), area_min_split_size: fractions.Fraction = fractions.Fraction(1, 4), ) -> None: if area_density_maker is None: area_density_maker = infit.Gaussian(0.25, 0.075) self.transcription = self._get_transcription( chapter=chapter, verse=verse, time_transcriber=time_transcriber, octave_of_first_pitch=octave_of_first_pitch, use_full_scale=use_full_scale, ) self._transcription_melody = old.Melody(tuple(self.transcription[:])) self.areas = areas.Areas.from_melody( self._transcription_melody, self.transcription.spread_metrical_loop, area_density_maker, area_density_reference_size, area_min_split_size, ) self.chapter = chapter self.verse = verse self.tempo_factor = tempo_factor self.bread = breads.Bread.from_melody( old.Melody(self.transcription).copy(), self.bars, max_rest_size_to_ignore, maximum_deviation_from_center, ) self.assign_harmonic_pitches_to_slices( harmonic_tolerance, harmonic_pitches_add_artifical_harmonics, harmonic_pitches_add_normal_pitches, harmonic_pitches_tonality_flux_maximum_octave_difference_from_melody_pitch, harmonic_pitches_complex_interval_helper_maximum_octave_difference_from_melody_pitch, ) self.assign_harmonic_fields_to_slices( harmonic_field_max_n_pitches, harmonic_field_minimal_harmonicity) self.rhythmic_orientation_indices = self._detect_rhythmic_orientation( temperature=ro_temperature, density=ro_density) self.melodic_orientation = self._make_melodic_orientation_system() self.rhythmic_orientation = self._make_rhythmic_orientation_system() super().__init__() self.attach( violin=strings.SilentStringMaker(globals_.VIOLIN), viola=strings.SilentStringMaker(globals_.VIOLA), cello=strings.SilentStringMaker(globals_.CELLO), keyboard=keyboard.SilentKeyboardMaker(), )
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 test_copy(self): melody0 = old.Melody([old.Tone(self.p0, self.d0), old.Tone(self.p0, self.d0)]) self.assertEqual(melody0, melody0.copy())
def test_add(self): compound = old.Melody([self.t0, self.t1, self.t1]) melody0 = old.Melody([self.t0]) melody1 = old.Melody([self.t1] * 2) self.assertEqual(melody0 + melody1, compound)