Source code for evans.pitch

"""
Pitch functions.
"""
import math

import abjad
import quicktions

from .sequence import RatioSegment, flatten


[docs]class JIPitch(abjad.Pitch): r""" Just Intonation Pitch .. container:: example >>> pitch = evans.JIPitch("c'", "7/4", with_quarter_tones=True) >>> note = abjad.Note(pitch, (1, 4)) >>> mark = abjad.Markup(fr"\markup {str(pitch.deviation)}", direction=abjad.Up, literal=True) >>> abjad.attach(mark, note) >>> abjad.show(note) # doctest: +SKIP .. docs:: >>> print(abjad.lilypond(note)) aqs'4 ^ \markup 19 .. container:: example >>> pitch = evans.JIPitch("c'", "7/4", with_quarter_tones=False) >>> note = abjad.Note(pitch, (1, 4)) >>> mark = abjad.Markup(fr"\markup {str(pitch.deviation)}", direction=abjad.Up, literal=True) >>> abjad.attach(mark, note) >>> abjad.show(note) # doctest: +SKIP .. docs:: >>> print(abjad.lilypond(note)) bf'4 ^ \markup -31 """ def __init__( self, fundamental, ratio, with_quarter_tones=False, ): self.fundamental = abjad.NamedPitch(fundamental) self.ratio = quicktions.Fraction(ratio) self.with_quarter_tones = with_quarter_tones pair = self._calculate_pitch_and_deviation(self.fundamental, self.ratio) self.pitch = pair[0] self.deviation = pair[1]
[docs] def __add__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): self_ratio = self.ratio self_fraction = quicktions.Fraction(self_ratio) return type(self)( self.fundamental, quicktions.Fraction(self_fraction + argument), self.with_quarter_tones, ) elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return type(self)( self.fundamental.number + argument.fundamental.number, quicktions.Fraction(self_pitch.number + argument_pitch.number), self.with_quarter_tones, )
[docs] def __truediv__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): self_ratio = self.ratio self_fraction = quicktions.Fraction(self_ratio) return type(self)( self.fundamental, quicktions.Fraction(self_fraction / argument), self.with_quarter_tones, ) elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return type(self)( self.fundamental.number / argument.fundamental.number, quicktions.Fraction(self_pitch.number / argument_pitch.number), self.with_quarter_tones, )
[docs] def __lt__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): self_ratio = self.ratio self_fraction = quicktions.Fraction(self_ratio) return self_fraction < argument elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return self_pitch < argument_pitch
[docs] def __lte__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): self_ratio = self.ratio self_fraction = quicktions.Fraction(self_ratio) return self_fraction <= argument elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return self_pitch <= argument_pitch
[docs] def __mod__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): return self.pitch.number % argument elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return type(self)( self.fundamental.number % argument.fundamental.number, quicktions.Fraction(self_pitch.number % argument_pitch.number), self.with_quarter_tones, )
[docs] def __mul__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): self_ratio = self.ratio self_fraction = quicktions.Fraction(self_ratio) return type(self)( self.fundamental, quicktions.Fraction(self_fraction * argument), self.with_quarter_tones, ) elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return type(self)( self.fundamental.number * argument.fundamental.number, quicktions.Fraction(self_pitch.number * argument_pitch.number), self.with_quarter_tones, )
[docs] def __str__(self): return abjad.lilypond(self.pitch)
[docs] def __sub__(self, argument): if isinstance(argument, (int, float, quicktions.Fraction)): self_ratio = self.ratio self_fraction = quicktions.Fraction(self_ratio) return type(self)( self.fundamental, quicktions.Fraction(self_fraction - argument), self.with_quarter_tones, ) elif isinstance(argument, type(self)): self_pitch = self.pitch argument_pitch = argument.pitch return type(self)( self.fundamental.number - argument.fundamental.number, quicktions.Fraction(self_pitch.number - argument_pitch.number), self.with_quarter_tones, )
def _get_lilypond_format(self): return abjad.lilypond(self.pitch) def _calculate_pitch_and_deviation( self, pitch, ratio, ): ratio = quicktions.Fraction(ratio) log_ratio = quicktions.Fraction(math.log10(ratio)) log_2 = quicktions.Fraction(1200 / math.log10(2)) ji_cents = quicktions.Fraction(log_ratio * log_2) semitones = ji_cents / 100 parts = math.modf(semitones) pitch = abjad.NumberedPitch(pitch) + parts[1] remainder = round(parts[0] * 100) if 50 < abs(remainder): if 0 < remainder: pitch += 1 remainder = -100 + remainder else: pitch -= 1 remainder = 100 + remainder if self.with_quarter_tones: if 25 < abs(remainder): if 0 < remainder: pitch += 0.5 remainder = -50 + remainder else: pitch -= 0.5 remainder = 50 + remainder return pitch, remainder @property def name(self): return abjad.lilypond(self.pitch) @property def pitch_class(self): return abjad.NamedPitchClass(self.pitch) @property def octave(self): return abjad.Octave(self.pitch)
[docs]def combination_tones(pitches=[0, 5, 7], depth=1): """ .. container:: example >>> print( ... evans.combination_tones( ... pitches=[ ... 8.25, ... 18.75, ... 23.5, ... ], ... depth=1, ... ) ... ) [-2.0, 6.0, 8.0, 14.5, 19.0, 23.5, 26.0, 29.5, 33.5] .. container:: example >>> print( ... evans.combination_tones( ... pitches=[ ... 7.75, ... 19, ... 25.25, ... 28.5 ... ], ... depth=1, ... ) ... ) [-1.0, 4.0, 6.0, 8.0, 13.5, 17.0, 19.0, 22.0, 25.0, 26.0, 28.5, 30.5, 33.0, 34.0, 36.5, 39.0] """ pitches = [abjad.NumberedPitch(_).hertz for _ in pitches] new_pitches = [] for iter in range(depth): for i, num in enumerate(pitches): new_pitches.append(num) for num_ in pitches[i + 1 :]: new_pitches.append(num + num_) if num > num_: new_pitches.append(num - num_) elif num < num_: new_pitches.append(num_ - num) else: continue pitches = new_pitches new_pitches = [] pitches = [float(abjad.NumberedPitch.from_hertz(x)) for x in pitches] reduce = [] for y in pitches: if y not in reduce: reduce.append(y) reduce.sort() pitches = reduce return pitches
[docs]def herz_combination_tone_ratios( fundamental=261.625565, pitches=[327.03195625, 392.43834749999996], depth=2 ): """ .. container:: example >>> print( ... evans.herz_combination_tone_ratios( ... fundamental=261.625565, ... pitches=[ ... 327.03195625, ... 392.43834749999996 ... ], ... depth=1, ... ) ... ) ['4503599627370493/18014398509481984', '5/4', '3/2', '11/4'] """ new_pitches = [] for iter in range(depth): for i, num in enumerate(pitches): new_pitches.append(num) for num_ in pitches[i + 1 :]: new_pitches.append(num + num_) if num > num_: new_pitches.append(num - num_) elif num < num_: new_pitches.append(num_ - num) else: continue pitches = new_pitches new_pitches = [] reduce = [] for y in pitches: if y not in reduce: reduce.append(y) reduce.sort() pitches = reduce returned_list = [] for freq in pitches: returned_list.append(str(quicktions.Fraction(freq / fundamental))) return returned_list
[docs]def return_cent_markup( note_head, ratio, quarter_tones=False, ): ratio = quicktions.Fraction(ratio) log_ratio = quicktions.Fraction(math.log10(ratio)) log_2 = quicktions.Fraction(1200 / math.log10(2)) ji_cents = quicktions.Fraction(log_ratio * log_2) semitones = ji_cents / 100 parts = math.modf(semitones) pitch = abjad.NumberedPitch(note_head.written_pitch) + parts[1] remainder = round(parts[0] * 100) if 50 < abs(remainder): if 0 < remainder: pitch += 1 remainder = -100 + remainder else: pitch -= 1 remainder = 100 + remainder if quarter_tones: if 25 < abs(remainder): if 0 < remainder: pitch += 0.5 remainder = -50 + remainder else: pitch -= 0.5 remainder = 50 + remainder if remainder < 0: cent_string = f"{remainder}" else: cent_string = f"+{remainder}" mark = abjad.Markup( fr"\markup \center-align {cent_string}", direction=abjad.Up, literal=True ) return mark
[docs]def return_vertical_moment_ties(score): r""" .. container:: example >>> staff_1 = abjad.Staff("c'4 c'2 c'4") >>> staff_2 = abjad.Staff("cs'4 cs'4 cs'2") >>> staff_3 = abjad.Staff("d'8 d'8 d'8 d'8 d'8 d'8 d'8 d'8") >>> score = abjad.Score( ... [ ... staff_1, ... staff_2, ... staff_3, ... ] ... ) >>> for tie in evans.return_vertical_moment_ties(score): ... tie ... LogicalTie([Note("d'8")]) LogicalTie([Note("c'4")]) LogicalTie([Note("cs'4")]) LogicalTie([Note("d'8")]) LogicalTie([Note("d'8")]) LogicalTie([Note("cs'4")]) LogicalTie([Note("c'2")]) LogicalTie([Note("d'8")]) LogicalTie([Note("d'8")]) LogicalTie([Note("cs'2")]) LogicalTie([Note("d'8")]) LogicalTie([Note("d'8")]) LogicalTie([Note("c'4")]) LogicalTie([Note("d'8")]) .. container:: example >>> staff_1 = abjad.Staff("c'4 c'2 c'4") >>> staff_2 = abjad.Staff("cs'4 cs'4 cs'2") >>> staff_3 = abjad.Staff("d'8 d'8 d'8 d'8 d'8 d'8 d'8 d'8") >>> score = abjad.Score( ... [ ... staff_1, ... staff_2, ... staff_3, ... ] ... ) ... >>> handler = evans.PitchHandler( ... pitch_list=[0, 1, 2, 3, 4], ... forget=False, ... to_ties=True, ... ) ... >>> vm_ties = evans.return_vertical_moment_ties(score) >>> numbers = [_ for _ in range(len(vm_ties))] >>> for i, tie in zip(numbers, vm_ties): ... string = f"{i}" ... markup = abjad.Markup(fr"\markup {string}", direction=abjad.Up, literal=True) ... abjad.attach(markup, tie[0]) ... >>> handler(vm_ties) >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> file = abjad.LilyPondFile( ... items=[score], ... includes=["abjad.ily"], ... global_staff_size=16, ... ) ... >>> abjad.show(file) # doctest: +SKIP .. docs:: >>> print(abjad.lilypond(score)) \new Score \with { proportionalNotationDuration = #(ly:make-moment 1 25) } << \new Staff { cs'4 ^ \markup 1 cs'2 ^ \markup 6 d'4 ^ \markup 12 } \new Staff { d'4 ^ \markup 2 c'4 ^ \markup 5 e'2 ^ \markup 9 } \new Staff { c'8 ^ \markup 0 ef'8 ^ \markup 3 e'8 ^ \markup 4 d'8 ^ \markup 7 ef'8 ^ \markup 8 c'8 ^ \markup 10 cs'8 ^ \markup 11 ef'8 ^ \markup 13 } >> .. container:: example >>> staff_1 = abjad.Staff("c'4 ~ c'2 c'4") >>> staff_2 = abjad.Staff("cs'4 cs'4 cs'2") >>> staff_3 = abjad.Staff("d'8 d'8 d'8 d'8 d'8 d'8 d'8 d'8") >>> score = abjad.Score( ... [ ... staff_1, ... staff_2, ... staff_3, ... ] ... ) >>> handler = evans.PitchHandler(pitch_list=[0, 1, 2, 3, 4], forget=False) >>> vm_ties = evans.return_vertical_moment_ties(score) >>> numbers = [_ for _ in range(len(vm_ties))] >>> for i, tie in zip(numbers, vm_ties): ... string = f"{i}" ... markup = abjad.Markup(fr"\markup {string}", direction=abjad.Up, literal=True) ... abjad.attach(markup, tie[0]) ... handler(tie) ... >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> file = abjad.LilyPondFile( ... items=[score], ... includes=["abjad.ily"], ... global_staff_size=16, ... ) ... >>> abjad.show(file) # doctest: +SKIP .. docs:: >>> print(abjad.lilypond(score)) \new Score \with { proportionalNotationDuration = #(ly:make-moment 1 25) } << \new Staff { d'4 ^ \markup 2 ~ d'2 cs'4 ^ \markup 11 } \new Staff { cs'4 ^ \markup 1 c'4 ^ \markup 5 ef'2 ^ \markup 8 } \new Staff { c'8 ^ \markup 0 ef'8 ^ \markup 3 e'8 ^ \markup 4 cs'8 ^ \markup 6 d'8 ^ \markup 7 e'8 ^ \markup 9 c'8 ^ \markup 10 d'8 ^ \markup 12 } >> """ moments = [_ for _ in abjad.iterate_vertical_moments(score)] new_moments = [] for i, moment in enumerate(moments): new_moment = [] new_moment_notes = [] for note in moment.start_notes: new_moment_notes.append(note) if 0 < len(new_moment_notes): new_moment.append( [_ for _ in abjad.select(new_moment_notes).logical_ties()] ) new_moments.append(new_moment) flat_moments = flatten(new_moments) flat_moments.sort(key=lambda _: abjad.get.timespan(_)) return flat_moments
[docs]def to_nearest_eighth_tone(number, frac=False): """ Rounds number to nearest eighth .. container:: example >>> l = [0, 1.111, 4.5, 2.23, 6.4, 7.3, 7.15] >>> l = [evans.to_nearest_eighth_tone(_, frac=True) for _ in l] >>> l [Fraction(0, 1), Fraction(1, 1), Fraction(9, 2), Fraction(9, 4), Fraction(13, 2), Fraction(29, 4), Fraction(29, 4)] """ number = round(float(number) * 4) / 4 div, mod = divmod(number, 1) if mod == 0.75: div += 0.75 elif mod == 0.5: div += 0.5 elif mod == 0.25: div += 0.25 if frac is False: return abjad.math.integer_equivalent_number_to_integer(div) else: return quicktions.Fraction(abjad.math.integer_equivalent_number_to_integer(div))
[docs]def to_nearest_quarter_tone(number, frac=False): """ Rounds number to nearest quarter .. container:: example >>> l = [0, 1.111, 4.5, 2.23, 6.4, 7.3, 7.15] >>> l = [evans.to_nearest_quarter_tone(_, frac=True) for _ in l] >>> l [Fraction(0, 1), Fraction(1, 1), Fraction(9, 2), Fraction(2, 1), Fraction(13, 2), Fraction(7, 1), Fraction(7, 1)] """ number = round(float(number) * 4) / 4 div, mod = divmod(number, 1) if mod == 0.75: div += 1 elif mod == 0.5: div += 0.5 if frac is False: return abjad.math.integer_equivalent_number_to_integer(div) else: return quicktions.Fraction(abjad.math.integer_equivalent_number_to_integer(div))
[docs]def to_nearest_sixth_tone(number): """ Rounds number to nearest sixth .. container:: example >>> l = [0, 1.111, 4.5, 2.23, 6.4, 7.3, 7.15] >>> l = [evans.to_nearest_sixth_tone(_) for _ in l] >>> l [Fraction(0, 1), Fraction(1, 1), Fraction(9, 2), Fraction(7, 3), Fraction(19, 3), Fraction(22, 3), Fraction(7, 1)] """ semitones = quicktions.Fraction(int(round(6 * number)), 6) if semitones.denominator == 6: semitones = quicktions.Fraction(int(round(3 * number)), 3) return semitones
[docs]def to_nearest_third_tone(number): """ Rounds number to nearest third .. container:: example >>> l = [0, 1.111, 4.5, 2.23, 6.4, 7.3, 7.15] >>> l = [evans.to_nearest_third_tone(_) for _ in l] >>> l [Fraction(0, 1), Fraction(1, 1), Fraction(14, 3), Fraction(2, 1), Fraction(20, 3), Fraction(22, 3), Fraction(7, 1)] """ semitones = quicktions.Fraction(int(round(3 * number)), 3) if semitones.denominator == 3: semitones = quicktions.Fraction( int(round(quicktions.Fraction(3, 2) * number)), quicktions.Fraction(3, 2) ) return semitones
[docs]def to_nearest_twelfth_tone(number): """ Rounds number to nearest twelfth .. container:: example >>> l = [0, 1.111, 4.5, 2.23, 6.4, 7.3, 7.15] >>> l = [evans.to_nearest_twelfth_tone(_) for _ in l] >>> l [Fraction(0, 1), Fraction(7, 6), Fraction(9, 2), Fraction(9, 4), Fraction(19, 3), Fraction(22, 3), Fraction(43, 6)] """ semitones = quicktions.Fraction(int(round(12 * number)), 12) if semitones.denominator == 12: semitones = quicktions.Fraction(int(round(6 * number)), 6) return semitones
[docs]def tonnetz(chord, chord_quality, transforms): """ .. container:: example >>> source = ["1/1", "6/5", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l", "r"]) >>> for triad in triads: ... print(triad) ... (1, 6/5, 3/2) (1, 5/4, 3/2) (5/4, 3/2, 15/8) (3/2, 15/8, 9/8) .. container:: example >>> source = ["1/1", "5/4", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l", "r"]) >>> for triad in triads: ... print(triad) ... (1, 5/4, 3/2) (1, 6/5, 3/2) (4/5, 1, 6/5) (2/3, 4/5, 1) .. container:: example >>> source = ["1/1", "12/7", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l7", "r7"]) >>> for triad in triads: ... print(triad) ... (1, 12/7, 3/2) (1, 7/8, 3/2) (7/4, 3/2, 21/16) (3/2, 21/16, 9/8) .. container:: example >>> source = ["1/1", "7/4", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l7", "r7"]) >>> for triad in triads: ... print(triad) ... (1, 7/4, 3/2) (1, 6/7, 3/2) (4/7, 1, 6/7) (2/3, 4/7, 1/2) .. container:: example >>> source = ["1/1", "12/11", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l11", "r11"]) >>> for triad in triads: ... print(triad) ... (1, 12/11, 3/2) (1, 11/8, 3/2) (11/8, 3/2, 33/32) (3/2, 33/32, 9/8) .. container:: example >>> source = ["1/1", "11/8", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l11", "r11"]) >>> for triad in triads: ... print(triad) ... (1, 11/8, 3/2) (1, 12/11, 3/2) (8/11, 1, 12/11) (2/3, 8/11, 1) .. container:: example >>> source = ["1/1", "24/13", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l13", "r13"]) >>> for triad in triads: ... print(triad) ... (1, 24/13, 3/2) (1, 13/16, 3/2) (13/8, 3/2, 39/32) (3/2, 39/32, 9/8) .. container:: example >>> source = ["1/1", "13/8", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l13", "r13"]) >>> for triad in triads: ... print(triad) ... (1, 13/8, 3/2) (1, 12/13, 3/2) (8/13, 1, 12/13) (2/3, 8/13, 1/2) .. container:: example >>> source = ["1/1", "24/17", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l17", "r17"]) >>> for triad in triads: ... print(triad) ... (1, 24/17, 3/2) (1, 17/16, 3/2) (17/16, 3/2, 51/32) (3/2, 51/32, 9/8) .. container:: example >>> source = ["1/1", "17/16", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l17", "r17"]) >>> for triad in triads: ... print(triad) ... (1, 17/16, 3/2) (1, 24/17, 3/2) (16/17, 1, 24/17) (2/3, 16/17, 1) .. container:: example >>> source = ["1/1", "24/19", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l19", "r19"]) >>> for triad in triads: ... print(triad) ... (1, 24/19, 3/2) (1, 19/16, 3/2) (19/16, 3/2, 57/32) (3/2, 57/32, 9/8) .. container:: example >>> source = ["1/1", "19/16", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l19", "r19"]) >>> for triad in triads: ... print(triad) ... (1, 19/16, 3/2) (1, 24/19, 3/2) (16/19, 1, 24/19) (2/3, 16/19, 1) .. container:: example >>> source = ["1/1", "24/23", "3/2"] >>> triads = evans.tonnetz(source, "minor", ["p", "l23", "r23"]) >>> for triad in triads: ... print(triad) ... (1, 24/23, 3/2) (1, 23/16, 3/2) (23/16, 3/2, 69/64) (3/2, 69/64, 9/8) .. container:: example >>> source = ["1/1", "23/16", "3/2"] >>> triads = evans.tonnetz(source, "major", ["p", "l23", "r23"]) >>> for triad in triads: ... print(triad) ... (1, 23/16, 3/2) (1, 24/23, 3/2) (16/23, 1, 24/23) (2/3, 16/23, 1) """ chord = RatioSegment(chord) chord = chord.constrain_to_octave() returned_list = [chord] updated_transforms = [] for transform in transforms: if transform == "n": updated_transforms.extend(["r", "l", "p"]) elif transform == "s": updated_transforms.extend(["l", "p", "r"]) elif transform == "h": updated_transforms.extend(["l", "p", "l"]) elif transform == "N": updated_transforms.append(["r", "l", "p"]) elif transform == "S": updated_transforms.append(["l", "p", "r"]) elif transform == "H": updated_transforms.append(["l", "p", "l"]) else: updated_transforms.append(transform) for transform in updated_transforms: if isinstance(transform, list): returned_list.append( tonnetz(returned_list[-1], chord_quality, transform)[-1] ) elif transform == "p": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() returned_list.append(i) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() returned_list.append(i) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("5/4") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("4/5") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("5/6") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("6/5") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l7": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("7/4") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("4/7") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r7": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("7/12") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("12/7") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l11": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("11/8") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("8/11") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r11": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("11/12") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("12/11") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l13": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("13/8") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("8/13") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r13": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("13/24") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("24/13") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l17": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("17/16") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("16/17") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r17": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("17/24") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("24/17") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l19": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("19/16") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("16/19") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r19": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("19/24") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("24/19") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "l23": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("23/16") il = il.constrain_to_octave() returned_list.append(il) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() il = i.multiply("16/23") il = il.constrain_to_octave() returned_list.append(il) else: raise Exception(f"Unrecogized chord quality {chord_quality}") elif transform == "r23": if chord_quality == "major": chord_quality = "minor" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("23/24") ir = ir.constrain_to_octave() returned_list.append(ir) elif chord_quality == "minor": chord_quality = "major" target = returned_list[-1] i = target.invert(target[0]) i = i.multiply("3/2") i = i.constrain_to_octave() i = i.retrograde() ir = i.multiply("24/23") ir = ir.constrain_to_octave() returned_list.append(ir) else: raise Exception(f"Unrecogized chord quality {chord_quality}") else: raise Exception( f"Transform '{transform}' not recognized. Use p, l, l7, l11, l13, l17, l19, l23, r, r7, r11, r13, r17, r19, r23, s, h, or, n." ) return returned_list
[docs]def tune_to_ratio( note_head, ratio, quarter_tones=False, ): """ Tunes pitch to ratio. """ ratio = quicktions.Fraction(ratio) log_ratio = quicktions.Fraction(math.log10(ratio)) log_2 = quicktions.Fraction(1200 / math.log10(2)) ji_cents = quicktions.Fraction(log_ratio * log_2) semitones = ji_cents / 100 parts = math.modf(semitones) pitch = abjad.NumberedPitch(note_head.written_pitch) + parts[1] remainder = round(parts[0] * 100) if 50 < abs(remainder): if 0 < remainder: pitch += 1 remainder = -100 + remainder else: pitch -= 1 remainder = 100 + remainder if quarter_tones: if 25 < abs(remainder): if 0 < remainder: pitch += 0.5 remainder = -50 + remainder else: pitch -= 0.5 remainder = 50 + remainder note_head.written_pitch = pitch