def test_delay(self): rh0 = rhy.Unit(4) rhy_comp0 = rhy.Compound([rhy.Unit(2), rhy.Unit(4), rhy.Unit(1)]) rhy_comp1 = rhy.Compound([rhy.Unit(4), rhy.Unit(8), rhy.Unit(2)]) self.assertEqual(rh0.delay, time.Time(4)) self.assertEqual(rhy_comp0.delay, time.Time(7)) self.assertEqual(rhy_comp1.delay, time.Time(14))
def __call__(self, sf_path: str, raw_data: tuple) -> tuple: """Return (old.Melody, bars).""" # convert raw data to relative - time - based melody melody = self._filter_raw_data_and_convert2melody(raw_data) # estimate tempo of soundfile tempo = self.estimate_tempo(sf_path) # divide tempo by 60 and multiply time values with factor to get values where one # whole notes equals 1, one halve note equals 0.5, etc. factor = tempo / 60 melody.dur = rhy.Compound(melody.dur).stretch(factor) melody.delay = rhy.Compound(melody.delay).stretch(factor) # quantizise rhythmical values to precise numbers melody = self.estimate_rhythm(melody) if self.remove_repeating_pitches: melody = melody.tie() # detect metre of melody and adjust melody melody, metre, spread_metrical_loop = self.estimate_metre(melody) return melody, metre, spread_metrical_loop, tempo
def estimate_rhythm(self, melody: old.Melody) -> tuple: melody.dur = rhy.Compound(melody.dur).stretch(self.stretch_factor) melody.delay = rhy.Compound(melody.delay).stretch(self.stretch_factor) melody = quantizise.quantisize_rhythm( melody, self.n_divisions, self.min_tone_size, self.min_rest_size ) melody.dur = rhy.Compound(melody.dur).stretch(self.post_stretch_factor) melody.delay = rhy.Compound(melody.delay).stretch(self.post_stretch_factor) return melody
def test_stretch(self): rh0 = rhy.Unit(2) rh1 = rhy.Unit(4) rh2 = rhy.Unit(1) self.assertEqual(rh0.stretch(2), rh1) self.assertEqual(rh0.stretch(0.5), rh2) rhy_comp0 = rhy.Compound([rhy.Unit(2), rhy.Unit(4), rhy.Unit(1)]) rhy_comp1 = rhy.Compound([rhy.Unit(4), rhy.Unit(8), rhy.Unit(2)]) rhy_comp2 = rhy.Compound([rhy.Unit(1), rhy.Unit(2), rhy.Unit(0.5)]) self.assertEqual(rhy_comp0, rhy_comp1.stretch(0.5)) self.assertEqual(rhy_comp0.stretch(2), rhy_comp1) self.assertEqual(rhy_comp0.stretch(0.5), rhy_comp2)
def convert2relative(self): """Change time dimension of the object. Starting time of specific event becomes its Delay , stoptime of specific event becomes its duration. """ copy = self.copy() if self.time_measure == "absolute": delay = rhy.Compound(copy.delay).convert2relative() copy.dur = tuple(dur - delay for dur, delay in zip(self.dur, self.delay)) delay.append(copy.dur[-1]) copy.delay = delay copy._time_measure = "relative" return copy
def convert2absolute(self) -> "AbstractLine": """Change time dimension of the object. Delay becomes the starting time of the specific event, duration becomes the stoptime of the specific event. """ copy = self.copy() if self.time_measure == "relative": copy.delay = rhy.Compound(copy.delay).convert2absolute() stop = tuple((d + s) for d, s in zip(copy.delay, copy.dur)) copy.dur = stop copy._time_measure = "absolute" return copy
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 mk_sco(self, cadence: old.Cadence) -> str: lines = [] abs_start = rhy.Compound(cadence.delay).convert2absolute() for event, start in zip(cadence, abs_start): if event.pitch and event.pitch != mel.TheEmptyPitch: duration = float(event.delay) + self.overlap release = self.release if self.release < duration else duration - 0.0001 line = r"i1 {0} {1} ".format(start, duration) for pi in tuple(p for p in event.pitch if p != mel.TheEmptyPitch): sample_name, factor = self.find_sample(pi) final_line = '{0} "{1}" {2} {3} {4}'.format( line, sample_name, factor, self.volume, release) lines.append(final_line) complete_duration = float(cadence.duration + 5) lines.append("i2 0 {0}".format(complete_duration)) return "\n".join(lines)
def test_convert2relative(self): r0 = rhy.Compound((0, 2, 4, 7, 8)) r1 = rhy.Compound((2, 2, 3, 1)) self.assertEqual(r0.convert2relative(), r1)
def test_convert2absolute(self): r0 = rhy.Compound((2, 2, 3, 1)) r1 = rhy.Compound((0, 2, 4, 7, 8)) self.assertEqual(r0.convert2absolute(), r1[:-1]) self.assertEqual(r0.convert2absolute(skiplast=False), r1)
def __init__( self, voice: old.Melody, new_sample_positions: tuple, sample_per_change: tuple, make_envelope: bool, average_volume: float, min_volume: float, max_volume: float, duration: float, tempo_factor: float, shadow_time: float, crossfade_duration: float = 0.25, anticipation_time: float = 0, overlaying_time: float = 0, attack_duration: infit.InfIt = infit.Value(0.5), release_duration: infit.InfIt = infit.Value(0.5), random_seed: int = 100, ) -> None: assert max_volume > min_volume assert min_volume > average_volume if not isinstance(attack_duration, infit.InfIt): attack_duration = infit.Value(attack_duration) if not isinstance(release_duration, infit.InfIt): release_duration = infit.Value(release_duration) import random as random_module random_module.seed(random_seed) self.__random_module = random_module voice.delay = rhy.Compound(voice.delay).stretch(tempo_factor) voice.dur = rhy.Compound(voice.dur).stretch(tempo_factor) self.__sndinfo_per_sample = { sample: pyo.sndinfo(sample) for sample in set(sample_per_change) } self.__n_channels_per_sample = { sample: self.__sndinfo_per_sample[sample][3] for sample in self.__sndinfo_per_sample } self.__duration_per_sample = { sample: self.__sndinfo_per_sample[sample][1] for sample in self.__sndinfo_per_sample } self.__new_sample_positions = new_sample_positions self.__sample_per_change = sample_per_change self.__duration = duration self.__envelope = self.mk_envelope( voice, shadow_time, duration, average_volume, min_volume, max_volume, make_envelope, anticipation_time, overlaying_time, ) self.__anticipation_time = anticipation_time self.__overlaying_time = overlaying_time self.__tempo_factor = tempo_factor self.__attack_duration = attack_duration self.__release_duration = release_duration self.__crossfade_duration = crossfade_duration self.__halved_crossfade_duration = crossfade_duration * 0.5
class MelodyTest(unittest.TestCase): p0 = ji.r(14, 9) p1 = ji.r(7, 4) d0 = rhy.Unit(400) d1 = rhy.Unit(800) t0 = old.Tone(p0, d0) t1 = old.Tone(p1, d1) mel0 = mel.Mel([p0] * 3) mel1 = mel.Mel([p1] * 3) rhy0 = rhy.Compound([d0] * 3) rhy1 = rhy.Compound([d1] * 3) melody0 = old.Melody([t0] * 3) def test_constructor(self): old.Melody([self.t0, self.t0, self.t0]) def test_alternative_constructor(self): melody1 = old.Melody.from_parameter(self.mel0, self.rhy0) self.assertEqual(self.melody0, melody1) def test_duration(self): self.assertEqual(self.melody0.duration, sum(self.rhy0)) melody1 = old.Melody([old.Rest(3)]) self.assertEqual(melody1.duration, 3) def test_get_attributes(self): self.assertEqual(self.melody0.__get_pitch__(), self.mel0) self.assertEqual(self.melody0.__get_delay__(), self.rhy0) self.assertEqual(self.melody0.__get_duration__(), self.rhy0) 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 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_freq(self): self.assertEqual(self.melody0.freq, self.mel0.freq) 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) 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) 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 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_convert2absolute(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), ) ) self.assertEqual(self.melody0.convert2absolute(), melody_converted) 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="relative", ) self.assertEqual(self.melody0.convert2absolute(), melody_converted) 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 test_copy(self): melody0 = old.Melody([old.Tone(self.p0, self.d0), old.Tone(self.p0, self.d0)]) self.assertEqual(melody0, melody0.copy())
def make_natural_radio( voices_main: tuple, voices_side: tuple, tempo_factor: float, gender: bool, make_envelope: bool, samples: tuple, n_changes: int, crossfade_duration: float, anticipation_time: float, overlaying_time: float, average_volume: float, min_volume: float, max_volume: float, shadow_time: float, silent_channels: tuple, attack_duration: infit.InfIt, release_duration: infit.InfIt, ) -> dict: n_samples = len(samples) # make sure there are at least one sample but not more than three assert n_samples in (1, 2, 3) # are those asserts here really necessary? assert shadow_time <= anticipation_time assert shadow_time <= overlaying_time inner_voices = globals.POSITIVE_VOICES_POSITION outer_voices = globals.NEGATIVE_VOICES_POSITIONS duration = float(voices_main[0].duration * tempo_factor) duration += anticipation_time + overlaying_time if not gender: inner_voices, outer_voices = outer_voices, inner_voices delay_volume_pairs_per_voice = tuple( tuple((delay, tone.volume) for delay, tone in zip( rhy.Compound(melody.delay).stretch( tempo_factor).convert2absolute(), melody, )) for melody in voices_main) delay_volume_pairs = functools.reduce(operator.add, delay_volume_pairs_per_voice) sorted_delay_volume_pairs = sorted(delay_volume_pairs, key=operator.itemgetter(1), reverse=True) change_positions = [0] for delay_volume_pair in sorted_delay_volume_pairs: if len(change_positions) - 1 == n_changes: break position = delay_volume_pair[0] if position not in change_positions: change_positions.append(position) change_positions = sorted(change_positions) sample_distributer_cycle = itertools.cycle(( # for one sample ( _CyclicPermutation((0, ) * 6), ), # for two samples ( _CyclicPermutation((0, 1) * 3), _CyclicPermutation((0, 0, 1, 0, 1, 1)), ), # for three samples ( _CyclicPermutation((0, 1, 2, 2, 1, 0)), _CyclicPermutation((0, 1, 2, 0, 1, 2)), ), )[n_samples - 1]) sample_distribution_per_change = tuple( next(next(sample_distributer_cycle)) for n in range(n_changes + 1)) sample_per_change_per_voice = tuple( tuple(samples[sample_idx] for sample_idx in voice) for voice in zip(*sample_distribution_per_change)) init_attributes = {} for voice_type, voices in enumerate((voices_main, voices_side)): for voice_idx, voice in enumerate(voices): absolute_voice_idx = (inner_voices, outer_voices)[voice_type][voice_idx] if absolute_voice_idx not in silent_channels: sound_engine = radio.RadioEngine( voice, change_positions, sample_per_change_per_voice[absolute_voice_idx], make_envelope, average_volume, min_volume, max_volume, duration, tempo_factor, shadow_time, crossfade_duration, anticipation_time=anticipation_time, overlaying_time=overlaying_time, attack_duration=attack_duration, release_duration=release_duration, ) voice_name = "natural_radio_{}".format(absolute_voice_idx) init_attributes.update({ voice_name: { "start": -anticipation_time, "duration": duration, "sound_engine": sound_engine, } }) return init_attributes
def delay(self) -> rhy.Compound: return rhy.Compound(obj.delay.copy() for obj in self)