def test_12(self): # breathing: duration_generator automatically, midi_generator: InterpolationGroup(2 x RandomInterpolations) breathing_proportions = [3, 7, 3, 10, 3] breathing_break_points = [1.5, 0.2, 1.5] breathing = Breathe(quarter_duration=sum(breathing_proportions), proportions=breathing_proportions, breakpoints=breathing_break_points) midi_generator = ValueGenerator() midi_generator.add_child( ValueGenerator(RandomInterpolation(start=[60, 62, 66, 68], end=[67, 69, 73, 75], seed=10), duration=10) ) midi_generator.add_child( ValueGenerator(RandomInterpolation(start=[67, 69, 73, 75], end=[60, 62, 66, 68], seed=11), duration=10) ) breathing.midi_generator = midi_generator copied = breathing.__deepcopy__() xml_path = path + 'test_12.xml' self.score.set_time_signatures(quarter_durations=breathing_proportions) copied.simple_format.to_stream_voice().add_to_score(self.score) self.score.max_division = 5 self.score.write(xml_path) self.assertCompareFiles(xml_path)
def test_10(self): midi_generator = ValueGenerator() midi_generator.add_child( ValueGenerator(RandomInterpolation(start=[60, 62, 66, 68], end=[67, 69, 73, 75], seed=10), duration=10) ) midi_generator.add_child( ValueGenerator(RandomInterpolation(start=[67, 69, 73, 75], end=[60, 62, 66, 68], seed=11), duration=10) ) cfg = ChordField( ) cf_1 = ChordField( quarter_duration=3, duration_generator=ValueGenerator(ArithmeticProgression(a1=0.5, an=1, correct_s=True)) ) cf_2 = ChordField( quarter_duration=6, duration_generator=ValueGenerator(ArithmeticProgression(a1=1, an=1, correct_s=True)) ) cfg.add_child(cf_1) cfg.add_child(cf_2) cfg.midi_generator = midi_generator cfg.__next__()
class ChordField(object): def __init__(self, quarter_duration=None, duration_generator=None, midi_generator=None, chord_generator=None, long_ending_mode=None, short_ending_mode=None, *args, **kwargs): super().__init__(*args, **kwargs) self._quarter_duration = None self._duration_generator = None self._midi_generator = None self._chord_generator = None self._chords = None self._long_ending_mode = None self._short_ending_mode = None self._children = None self._parent = None self._position = 0 self._name = None self.quarter_duration = quarter_duration self.duration_generator = duration_generator self.midi_generator = midi_generator self.chord_generator = chord_generator self.long_ending_mode = long_ending_mode self.short_ending_mode = short_ending_mode def _get_value_generators(self): return [value_generator for value_generator in (self.chord_generator, self.duration_generator, self.midi_generator) if value_generator is not None] def _get_private_value_generators(self): return [value_generator for value_generator in (self._chord_generator, self._duration_generator, self._midi_generator) if value_generator is not None] def _set_up_value_generator(self, value_generator, value_mode=None): if not isinstance(value_generator, ValueGenerator): raise TypeError('value_generator must be of type ValueGenerator not {}'.format( type(value_generator))) value_generator.value_mode = value_mode try: value_generator.duration = self.quarter_duration except ValueGeneratorException: if self.quarter_duration is None: raise ValueGeneratorException() factor = Fraction(self.quarter_duration, value_generator.duration) for child in value_generator.children: child.duration *= factor @property def children(self): return self._children @property def parent(self): return self._parent def add_child(self, child): if self._quarter_duration: raise ParentSetQuarterDurationError() if self.long_ending_mode is not None or self.short_ending_mode is not None: raise ParentSetEndingModesError() if not isinstance(child, ChordField): raise TypeError() if self._children is None: self._children = [] self._children.append(child) if child.duration_generator: if self.duration_generator is None: self.duration_generator = ValueGenerator() self.duration_generator.add_child(child.duration_generator) elif self.duration_generator.children: self.duration_generator.add_child(child.duration_generator) else: pass if child.midi_generator: if self.midi_generator is None: self.midi_generator = ValueGenerator() self.midi_generator.add_child(child.midi_generator) elif self.midi_generator.children: self.midi_generator.add_child(child.midi_generator) else: pass if child.chord_generator: if self.chord_generator is None: self.chord_generator = ValueGenerator() self.chord_generator.add_child(child.chord_generator) elif self.chord_generator.children: self.chord_generator.add_child(child.chord_generator) else: pass child._parent = self self._update_durations() return child def _update_durations(self): for value_generator in self._get_value_generators(): try: value_generator.duration = self.quarter_duration except ValueGeneratorException: pass @property def quarter_duration(self): if self.children: children_quarter_durations = [child.quarter_duration for child in self.children] if None in children_quarter_durations: return None else: return sum(children_quarter_durations) return self._quarter_duration @quarter_duration.setter def quarter_duration(self, value): if value is not None: if self.children: raise ParentSetQuarterDurationError() else: self._quarter_duration = value self._update_durations() if self.parent: self.parent._update_durations() @property def duration_generator(self): if not self._duration_generator and self.parent and self.parent.duration_generator: return self.parent.duration_generator return self._duration_generator @duration_generator.setter def duration_generator(self, value): self._duration_generator = value if value: self._set_up_value_generator(self.duration_generator, 'duration') @property def midi_generator(self): if not self._midi_generator and self.parent and self.parent.midi_generator: return self.parent.midi_generator return self._midi_generator @midi_generator.setter def midi_generator(self, value): self._midi_generator = value if value: self._set_up_value_generator(self.midi_generator, 'midi') @property def chord_generator(self): if not self._chord_generator and self.parent: return self.parent.chord_generator return self._chord_generator @chord_generator.setter def chord_generator(self, value): self._chord_generator = value if value: self._set_up_value_generator(self.chord_generator, 'chord') @property def position(self): return self._position @property def position_in_parent(self): index = self.parent.children.index(self) if index == 0: return 0 return sum([child.quarter_duration for child in self.parent.children[:index]]) @property def long_ending_mode(self): return self._long_ending_mode @long_ending_mode.setter def long_ending_mode(self, val): if val is not None and self.children is not None: raise ParentSetEndingModesError() """ :param val: can be None, 'self_extend', 'cut', 'omit', 'omit_and_add_rest', 'omit_and_stretch' for dealing with last chord, if it is too long and ends after self.quarter_duration None: raises Error self_extend: self.quarter_duration will be prolonged. cut: last chord will be cut short. omit: last chord will be omitted and self.quarter_duration cut short. omit_and_add_rest: last chord will be omitted and rests will be added. omit_and_stretch: last chord will be omitted and the new last chord will be extended. """ permitted = [None, 'self_extend', 'cut', 'omit', 'omit_and_add_rest', 'omit_and_stretch'] if val not in permitted: raise ValueError('long_ending_mode.value {} must be in {}'.format(val, permitted)) self._long_ending_mode = val @property def short_ending_mode(self): return self._short_ending_mode @short_ending_mode.setter def short_ending_mode(self, val): if val is not None and self.children is not None: raise ParentSetEndingModesError() """ :param val: can be None, 'self_shrink', 'add_rest', 'stretch' for dealing with last chord, if it is too long and ends after self.quarter_duration None: raises Error self_shrink: self.quarter_duration will be shortened. omit: rests will be added. stretch: last chord will be prolonged. """ permitted = [None, 'self_shrink', 'add_rest', 'stretch'] if val not in permitted: raise ValueError('short_ending_mode.value {} must be in {}'.format(val, permitted)) self._short_ending_mode = val @property def chords(self): if self.children: self._chords = [chord for child in self.children for chord in child.chords] else: list(self) return self._chords @property def simple_format(self): sf = SimpleFormat() if self.chords: for chord in self.chords: sf.add_chord(chord) return sf def _get_next_duration(self): if self.duration_generator: next_duration = self.duration_generator.__next__() self._position += next_duration for generator in self._get_value_generators(): if generator != self.duration_generator: generator._position += next_duration return next_duration else: return None def _get_next_midi(self): if self.midi_generator: # self.midi_generator._position = self.position return self.midi_generator.__next__() else: return None def _get_next_chord(self): next_chord = None next_midi = self._get_next_midi() next_duration = self._get_next_duration() if self.chord_generator: next_chord = self.chord_generator.__next__() if next_chord: if next_duration is not None: next_chord.quarter_duration = next_duration if next_midi is not None: next_chord.midis = next_midi else: if next_duration is None: raise NoNextChordError('next_duration is None!') if next_midi is None: raise NoNextChordError('next_midi is None!') next_chord = TreeChord(quarter_duration=next_duration, midis=next_midi) if self._chords is None: self._chords = [] self._chords.append(next_chord) return next_chord def _check_quarter_duration(self): if self._chords: delta = sum([chord.quarter_duration for chord in self._chords]) - self.quarter_duration if delta > 0: if self.long_ending_mode == 'self_extend': if self.parent: try: next_child = self.parent.children[self.parent.children.index(self) + 1] next_child._position = delta except IndexError: pass try: self.quarter_duration += delta except ParentSetQuarterDurationError: self.children[-1].quarter_duration += delta elif self.long_ending_mode == 'cut': self._chords[-1].quarter_duration -= delta elif self.long_ending_mode in ['omit', 'omit_and_add_rest', 'omit_and_stretch']: self._chords.pop() new_delta = self.quarter_duration - sum([chord.quarter_duration for chord in self._chords]) if self.long_ending_mode == 'omit_and_add_rest': new_chord = TreeChord(midis=0, quarter_duration=new_delta) new_chord.zero_mode = 'remove' self._chords.append(new_chord) elif self.long_ending_mode == 'omit_and_stretch': self._chords[-1].quarter_duration += new_delta else: self.quarter_duration -= new_delta else: raise LongEndingError(delta) elif delta < 0: if self.short_ending_mode == 'self_shrink': self.quarter_duration += delta elif self.short_ending_mode == 'add_rest': new_chord = TreeChord(midis=0, quarter_duration=-delta) new_chord.zero_mode = 'remove' self._chords.append(new_chord) elif self.short_ending_mode == 'stretch': self._chords[-1].quarter_duration -= delta else: raise ShortEndingError(delta) else: pass def __iter__(self): return self def __next__(self): try: next_chord = self._get_next_chord() return next_chord except StopIteration: self._check_quarter_duration() raise StopIteration() def __deepcopy__(self, memodict={}): if self.__class__ == Breathe: copied = self.__class__(proportions=self.proportions, breakpoints=self.breakpoints, quarter_duration=self.quarter_duration) else: copied = self.__class__(quarter_duration=self.quarter_duration) copied.long_ending_mode = self.long_ending_mode copied.short_ending_mode = self.short_ending_mode for generator in self._get_private_value_generators(): if generator.value_mode == 'duration': copied._duration_generator = generator.__deepcopy__() elif generator.value_mode == 'midi': copied._midi_generator = generator.__deepcopy__() elif generator.value_mode == 'chord': copied._chord_generator = generator.__deepcopy__() else: raise NotImplementedError() if self.children: copied._children = [] for child in self.children: copied_child = child.__deepcopy__() copied_child._parent = copied copied._children.append(copied_child) return copied