def mk_siter_cadence( self, siter_panerus_pitch, gender, previous_signified: int, previous_side_prime: int, current_signified: int, current_side_prime: int, following_signified: int, following_side_prime: int, stresses, ) -> old.JICadence: siter_pitches = self.siter_style.convert2interpolation( gender, previous_signified, previous_side_prime, current_signified, current_side_prime, following_signified, following_side_prime, stresses, ) siter_pitches = tuple(ji.JIHarmony([p]) for p in siter_pitches) siter_pitches = (ji.JIHarmony(siter_panerus_pitch), ) + siter_pitches return old.JICadence([old.Chord(h, 1) for h in siter_pitches])
def mk_simple_conversion( mode: modes.Mode, funcs: tuple, subfunctions_per_interpol: tuple ) -> old.JICadence: """Expect real functions (with applied modulation), not symbolic functions""" def get_from_func_pitch(func) -> ji.JIPitch: p = func(mode) if p.set_val_border(2).primes == (3,): # 3 * 9 doesn't exist in current tuning return p.normalize(2) - ji.r(2, 1) else: return mel.TheEmptyPitch def filter_subfunc_pitch(pitch) -> ji.JIPitch: if pitch == ji.r(1, 1): pitch += ji.r(2, 1) if pitch in SITER_BARUNG.pitches: return pitch else: return mel.TheEmptyPitch res = [] for func0, func1, subfuncline in zip(funcs, funcs[1:], subfunctions_per_interpol): fp = get_from_func_pitch(func0) subfunc_pitches = list( (filter_subfunc_pitch(p),) for p in subfuncline.convert_signifiers2pitches(mode, func0, func1)[:-1] ) if fp: subfunc_pitches[0] = subfunc_pitches[0] + (fp,) for h in subfunc_pitches: h = tuple(p for p in h if p) res.append(h) return old.JICadence([old.Chord(ji.JIHarmony(h), 1) for h in res])
def mk_simple_conversion(mode: modes.Mode, compounds_per_function: tuple, funcs: tuple) -> old.JICadence: def define_gong(mode) -> ji.JIPitch: gong_pitch = ji.r( functools.reduce(operator.mul, (mode.x, mode.y, mode.z)), 1) if not mode.gender: gong_pitch = gong_pitch.inverse() return gong_pitch.normalize(2) - ji.r(4, 1) def get_pitch(f) -> ji.JIPitch: p = f(mode) if p.set_val_border(2).primes == ( 3, ): # 3 * 9 doesn't exist in current tuning return mel.TheEmptyPitch else: return f(mode).normalize() - ji.r(2, 1) gong = define_gong(mode) pitches = tuple(get_pitch(f) for f in funcs) pitches = ((gong, p) if f.gong else (p, ) for f, p in zip(funcs, pitches)) return old.JICadence([ old.Chord(ji.JIHarmony(tuple(pi for pi in p if pi)), delay) for p, delay in zip(pitches, compounds_per_function) ])
def divide_recursively(cadence, size=1): duration = float(cadence.duration) beats = duration / size try: assert float(beats) == int(beats) except AssertionError: msg = "{0} beats for size {1} in cadence {2}.".format( beats, size, cadence) msg += " Attribute 'beats' has to be an integer number." raise ValueError(msg) beats = int(beats) group = tuple(size for i in range(beats)) divided = MDC.divide_cadence_by_groups(cadence, group, is_pitch_sustained) result = [] for div in divided: if len(div) == 1: p = ji.JIHarmony(div[0].pitch) if len(p) == 0: p = mel.TheEmptyPitch result.append(p) else: result.append(divide_recursively(div, size / 2)) if size < 1: assert len(result) == 2 if result[1] == mel.TheEmptyPitch and type(result[0]) != tuple: return result[0] return tuple(result)
def create_cadence( self, stresses: tuple, does_siter_play: tuple, gender: bool, previous_signified: int, current_signified: int, following_signified: int, previous_side_prime: int, current_side_prime: int, following_side_prime: int, ) -> old.JICadence: chord0 = old.Chord(ji.JIHarmony([]), 1) pattern = self.detect_pattern( stresses, does_siter_play, gender, previous_signified, current_signified, following_signified, previous_side_prime, current_side_prime, following_side_prime, ) final_cadence = [chord0] for idx, pat in enumerate(pattern): pat = list(pat) final_cadence += pat return old.JICadence(final_cadence)
def mk_loop_cadence_with_tuk(loopsize: int, meter: metre.Metre) -> old.JICadence: size = meter.size loop_amount = size // loopsize rest = size % loopsize harmony0 = ji.JIHarmony([ji.r(3, 2)]) harmony1 = ji.JIHarmony([ji.r(1, 1)]) basic_cadence = [old.Chord(harmony0, 0.5) ] + [old.Chord(harmony1, 1) for i in range(loopsize - 1)] basic_cadence.append(old.Chord(harmony1, 0.5)) print(old.JICadence(basic_cadence).duration) cadence = [basic_cadence for i in range(loop_amount)] cadence = functools.reduce(operator.add, cadence) if rest: cadence.append(old.Chord(harmony0, rest)) return old.JICadence(cadence)
def mk_mdc_gong_and_tong(cadence, timeflow) -> tuple: cadence_gong, cadence_tong = [], [] for chord in cadence: hg, ht = [], [] for p in chord.pitch: if p < ji.r(1, 2): hg.append(p) else: ht.append(p) cadence_gong.append(old.Chord(ji.JIHarmony(hg), chord.delay)) cadence_tong.append(old.Chord(ji.JIHarmony(ht), chord.delay)) cadences = tuple( old.JICadence(c).discard_rests() for c in (cadence_gong, cadence_tong)) return tuple( MDC.mk_mdc_by_cadence(c, timeflow, Score.TIME_LV_PER_INSTRUMENT[0], False) for c in cadences)
def mk_loop_cadence(loopsize: int, meter: metre.Metre) -> old.JICadence: size = meter.size loop_amount = size // loopsize rest = size % loopsize harmony = ji.JIHarmony([ji.r(3, 2)]) cadence = [old.Chord(harmony, loopsize) for i in range(loop_amount)] if rest: cadence.append(old.Chord(harmony, rest)) return old.JICadence(cadence)
def distribute_harmony(harmony) -> tuple: harmonies_per_mdc = [[] for i in range(amount_mdc)] for pitch in harmony: if pitch != mel.TheEmptyPitch: for instridx in decomposition[pitch]: harmonies_per_mdc[instridx].append(pitch) container = [] for idx, harmony in enumerate(harmonies_per_mdc): if harmony: container.append(ji.JIHarmony(harmony)) else: container.append(mel.TheEmptyPitch) return tuple(container)
def find_normalize_dependent_combinations( self, primes, maxlevel, gender, compound, compound_asymmetrical, three_compound, allow_stacking, normalize, additional_intervals, ): # find all intervals: intervals = ji.JIHarmony( Tree.find_intervals( primes, maxlevel, gender, compound, compound_asymmetrical, three_compound, )) for additional in additional_intervals: intervals.add(additional) intervals = [ i.set_val_border(1).normalize(normalize) for i in intervals ] self.intervals = intervals comb_intervals = [ inter for inter in intervals if inter != ji.r(1, 1, val_border=2) ] if allow_stacking is True: combinations = tuple( itertools.combinations_with_replacement(comb_intervals, 2)) else: combinations = tuple(itertools.combinations(comb_intervals, 2)) valid_combinations = [] for interval in intervals: valid = [] for comb in combinations: if (comb[0] + comb[1]).normalize(normalize) == interval: valid.append(comb) valid_combinations.append(valid) return valid_combinations
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 divide_recursively(remaining_cadence, remaining_groups, divided_cadences: list = []) -> list: if remaining_cadence: new_cadence = type(remaining_cadence)([]) surplus_element = None group_size = remaining_groups[0] acc = 0 for idx, item in enumerate(remaining_cadence): size = float(item.delay) acc += size if acc == group_size: new_cadence.append(item) break elif acc < group_size: new_cadence.append(item) elif acc > group_size: diff = acc - group_size item0 = item.copy() item0.delay -= diff item0.duration -= diff item1 = item.copy() item1.delay = diff item1.duration = diff if is_pitch_sustained is False: item1.pitch = ji.JIHarmony([]) new_cadence.append(item0) surplus_element = item1 break divided_cadences.append(new_cadence) remaining_cadence = remaining_cadence[idx + 1:] if surplus_element is not None: remaining_cadence.insert(0, surplus_element) return divide_recursively(remaining_cadence, remaining_groups[1:], divided_cadences) else: return divided_cadences
def create_cadence( self, stresses: tuple, does_siter_play: tuple, gender: bool, previous_signified: int, current_signified: int, following_signified: int, previous_side_prime: int, current_side_prime: int, following_side_prime: int, ) -> old.JICadence: if self.apply_with_header_if_header_exist: cadence = old.JICadence([]) else: cadence = old.JICadence([old.Chord(ji.JIHarmony([]), 0.5)]) divided_stresses = self.divide_stresses(stresses) amount_divisions = len(divided_stresses) is_with_modulation = current_signified != following_signified for idx, division in enumerate(divided_stresses): if idx == 0 and self.apply_with_header_if_header_exist: add_header = True else: add_header = False amount_stresses = len(division) is_with_resolution = not all(tuple(not s for s in division)) conditions_for_modulation = ( is_with_modulation, not is_with_resolution, idx + 1 == amount_divisions, ) if all(conditions_for_modulation): pattern = self.pattern[1][amount_stresses] cadence += self.convert_modulation_pattern( gender, current_signified, current_side_prime, following_signified, following_side_prime, pattern, add_header, ) else: pattern_idx = int(amount_stresses) if is_with_resolution: add_tail = True else: pattern_idx += 1 add_tail = False pattern = self.pattern[0][pattern_idx] cadence += self.convert_resolution_pattern( gender, current_signified, current_side_prime, pattern, add_header, add_tail, ) return old.JICadence(cadence)
def find_intervals( primes, maxlevel, gender: int, compound=True, compound_asymmetrical=True, three_compound=True, ): val_border = 2 intervals = ji.JIHarmony([]) for p in primes: for lv in range(maxlevel): scale = lv + 1 intervals.add(ji.r(p, 1, val_border=val_border).scalar(scale)) intervals.add(ji.r(1, p, val_border=val_border).scalar(scale)) if compound is True: for p0, p1 in itertools.combinations(primes, 2): for lv in range(maxlevel): scale = lv + 1 intervals.add( ji.r(p0, p1, val_border=val_border).scalar(scale)) intervals.add( ji.r(1, p1 * p0, val_border=val_border).scalar(scale)) intervals.add( ji.r(p0 * p1, 1, val_border=val_border).scalar(scale)) intervals.add( ji.r(p1, p0, val_border=val_border).scalar(scale)) if compound_asymmetrical is True: for lv in range(maxlevel): scale0 = lv scale1 = lv + 1 p00A = ji.r(p0, 1, val_border=val_border).scalar(scale0) p10A = ji.r(1, p1, val_border=val_border).scalar(scale1) p01A = ji.r(p0, 1, val_border=val_border).scalar(scale1) p11A = ji.r(1, p1, val_border=val_border).scalar(scale0) pres0 = p00A + p10A pres1 = p01A + p11A intervals.add(pres0) intervals.add(pres1) intervals.add(pres0.inverse()) intervals.add(pres1.inverse()) if three_compound is True: for p0, p1, p2 in itertools.combinations(primes, 3): for lv in range(maxlevel): scale = lv + 2 intervals.add( ji.r(p0 + p2, p1, val_border=val_border).scalar(scale)) intervals.add( ji.r(p1 + p2, p0, val_border=val_border).scalar(scale)) intervals.add( ji.r(p0 + p1, p2, val_border=val_border).scalar(scale)) if compound_asymmetrical is True: for lv in range(maxlevel): def make_zero_inverse(p0, p1, p2): return p0 + p1 + p2 def make_one_inverse(p0, p1, p2): return p0 + p1 + p2.inverse() def make_two_inverse(p0, p1, p2): return p0 + p1.inverse() + p2.inverse() def make_all_inverse(p0, p1, p2): return p0.inverse() + p1.inverse() + p2.inverse() scale0 = lv scale1 = lv + 1 scale2 = lv + 2 p00A = ji.r(p0, 1, val_border=val_border).scalar(scale0) p10A = ji.r(p1, 1, val_border=val_border).scalar(scale0) p20A = ji.r(p2, 1, val_border=val_border).scalar(scale0) p01A = ji.r(p0, 1, val_border=val_border).scalar(scale1) p11A = ji.r(p1, 1, val_border=val_border).scalar(scale1) p21A = ji.r(p2, 1, val_border=val_border).scalar(scale1) p02A = ji.r(p0, 1, val_border=val_border).scalar(scale2) p12A = ji.r(p1, 1, val_border=val_border).scalar(scale2) p22A = ji.r(p2, 1, val_border=val_border).scalar(scale2) data = [ p00A, p10A, p20A, p01A, p11A, p21A, p02A, p12A, p22A ] comb = itertools.combinations(data, 3) for c in comb: for p in itertools.permutations(c): intervals.add(make_one_inverse(*p)) intervals.add(make_two_inverse(*p)) intervals.add(make_all_inverse(*p)) if gender != 0: if gender == 1: intervals = (p for p in intervals if p.gender is True) elif gender == -1: intervals = (p for p in intervals if p.gender is False) else: raise ValueError("Invalid arg for gender") return list(intervals)
def find_octave_independent_combinations( self, primes, maxlevel, gender, compound, compound_asymmetrical, three_compound, allow_stacking, octaves, additional_intervals, ): # find all intervals: intervals = ji.JIHarmony( Tree.find_intervals( primes, maxlevel, gender, compound, compound_asymmetrical, three_compound=three_compound, )) for additional in additional_intervals: intervals.add(additional) comb_intervals = [ inter for inter in intervals if inter != ji.r(1, 1, val_border=2) ] if allow_stacking is True: combinations = tuple( itertools.combinations_with_replacement(comb_intervals, 2)) else: combinations = tuple(itertools.combinations(comb_intervals, 2)) valid_combinations = [] for interval in intervals: valid = [] for comb in combinations: if comb[0] + comb[1] == interval: valid.append( [c.set_val_border(1).normalize(2) for c in comb]) valid_combinations.append(valid) resulting_intervals = [ i.set_val_border(1).normalize(2) for i in intervals ] if octaves is not None: add = [] for octave in octaves: for inter in resulting_intervals: add.append(inter + octave) resulting_intervals.extend(add) resulting_valid_combinations = [] for interval, valid_combination in zip( resulting_intervals, itertools.cycle(valid_combinations)): really_valid = [] for combination in valid_combination: for oct_comb in itertools.combinations_with_replacement( octaves, 2): combination0 = [ combination[0] + oct_comb[0], combination[1] + oct_comb[1], ] combination1 = [ combination[0] + oct_comb[1], combination[1] + oct_comb[0], ] for c in (combination0, combination1): if c[0] + c[1] == interval: really_valid.append(c) resulting_valid_combinations.append(really_valid) self.intervals = resulting_intervals return resulting_valid_combinations