Source code for abjadext.microtones.et

"""
Package for equal tempered microtones.
"""
import math

import abjad
import quicktions


[docs]class ETBundle: """ ET bundle. >>> from abjadext import microtones """ def __init__(self, pitch="c'", accidental_string=None): self.pitch = pitch self.accidental_string = accidental_string
[docs] def __repr__(self): """ Gets interpreter representation. .. container:: example >>> microtones.ETBundle() ETBundle(pitch="c'") """ return abjad.StorageFormatManager(self).get_repr_format()
_accidental_to_value = { "double sharp": 2, "three-quarters sharp": quicktions.Fraction(3 / 2), "sharp": 1, "quarter sharp": quicktions.Fraction(1 / 2), "natural": 0, "quarter flat": quicktions.Fraction(-1 / 2), "flat": -1, "three-quarters flat": quicktions.Fraction(-3 / 2), "double flat": -2, } _value_to_accidental = { "2": r"\double-sharp", "11/6": r"\eleven-twelfths-sharp", "7/4": r"\seven-eighths-sharp", "5/3": r"\five-sixths-sharp", "8/5": r"\four-fifths-sharp", "3/2": r"\three-quarters-sharp", "7/5": r"\seven-tenths-sharp", "4/3": r"\two-thirds-sharp", "5/4": r"\five-eighths-sharp", "6/5": r"\three-fifths-sharp", "7/6": r"\seven-twelfths-sharp", "1": r"\abjad-sharp", "5/6": r"\five-twelfths-sharp", "4/5": r"\two-fifths-sharp", "3/4": r"\three-eighths-sharp", "2/3": r"\one-third-sharp", "3/5": r"\three-tenths-sharp", "1/2": r"\one-quarter-sharp", "2/5": r"\one-fifth-sharp", "1/3": r"\one-sixth-sharp", "1/4": r"\one-eighth-sharp", "1/5": r"\one-tenth-sharp", "1/6": r"\one-twelfth-sharp", "0": r"\abjad-natural", "-1/6": r"\one-twelfth-flat", "-1/5": r"\one-tenth-flat", "-1/4": r"\one-eighth-flat", "-1/3": r"\one-sixth-flat", "-2/5": r"\one-fifth-flat", "-1/2": r"\one-quarter-flat", "-3/5": r"\three-tenths-flat", "-2/3": r"\one-third-flat", "-3/4": r"\three-eighths-flat", "-4/5": r"\two-fifths-flat", "-5/6": r"\five-twelfths-flat", "-1": r"\abjad-flat", "-7/6": r"\seven-twelfths-flat", "-6/5": r"\three-fifths-flat", "-5/4": r"\five-eighths-flat", "-4/3": r"\two-thirds-flat", "-7/5": r"\seven-tenths-flat", "-3/2": r"\three-quarters-flat", "-8/5": r"\four-fifths-flat", "-5/3": r"\five-sixths-flat", "-7/4": r"\seven-eighths-flat", "-11/6": r"\eleven-twelfths-flat", "-2": r"\double-flat", } _reversed_value_to_accidental = { r"\double-sharp-markup": "2/1", r"\eleven-twelfths-sharp-markup": "11/6", r"\seven-eighths-sharp-markup": "7/4", r"\five-sixths-sharp-markup": "5/3", r"\four-fifths-sharp-markup": "8/5", r"\three-quarters-sharp-markup": "3/2", r"\two-thirds-sharp-markup": "4/3", r"\five-eighths-sharp-markup": "5/4", r"\three-fifths-sharp-markup": "6/5", r"\seven-twelfths-sharp-markup": "7/6", r"\abjad-sharp-markup": "1/1", r"\five-twelfths-sharp-markup": "5/6", r"\two-fifths-sharp-markup": "4/5", r"\three-eighths-sharp-markup": "3/4", r"\one-third-sharp-markup": "2/3", r"\one-quarter-sharp-markup": "1/2", r"\one-fifth-sharp-markup": "2/5", r"\one-sixth-sharp-markup": "1/3", r"\one-eighth-sharp-markup": "1/4", r"\one-twelfth-sharp-markup": "1/6", r"\abjad-natural-markup": "0", r"\one-twelfth-flat-markup": "-1/6", r"\one-eighth-flat-markup": "-1/4", r"\one-sixth-flat-markup": "-1/3", r"\one-fifth-flat-markup": "-2/5", r"\one-quarter-flat-markup": "-1/2", r"\one-third-flat-markup": "-2/3", r"\three-eighths-flat-markup": "-3/4", r"\two-fifths-flat-markup": "-4/5", r"\five-twelfths-flat-markup": "-5/6", r"\abjad-flat-markup": "-1/1", r"\seven-twelfths-flat-markup": "-7/6", r"\three-fifths-flat-markup": "-6/5", r"\five-eighths-flat-markup": "-5/4", r"\two-thirds-flat-markup": "-4/3", r"\three-quarters-flat-markup": "-3/2", r"\four-fifths-flat-markup": "-8/5", r"\five-sixths-flat-markup": "-5/3", r"\seven-eighths-flat-markup": "-7/4", r"\eleven-twelfths-flat-markup": "-11/6", r"\double-flat-markup": "-2/1", }
[docs]def get_accidental_value(pitch): """ Gets accidental value. .. container:: example >>> pitch = abjad.NamedPitch("cs'") >>> microtones.get_accidental_value(pitch) 1 """ accidental = pitch.accidental.name accidental_value = _accidental_to_value[f"{accidental}"] return accidental_value
[docs]def get_value_sum(pitch, value): """ Gets value sum. .. container:: example >>> pitch = abjad.NamedPitch("cs'") >>> microtones.get_value_sum(pitch, "3/4") Fraction(7, 4) """ value = quicktions.Fraction(value) return get_accidental_value(pitch) + value
[docs]def get_alteration(pitch, value, spell=None): r""" Gets alteration. .. container:: example >>> pitch = abjad.NumberedPitch(0) >>> bundle = microtones.get_alteration(pitch, "2/1") >>> bundle.pitch NumberedPitch(2) >>> bundle.accidental_string '\\abjad-natural-markup' .. container:: example >>> pitch = abjad.NumberedPitch(0) >>> bundle = microtones.get_alteration(pitch, "1/1") >>> bundle.pitch NumberedPitch(1) >>> bundle.accidental_string '\\abjad-sharp-markup' .. container:: example >>> pitch = abjad.NumberedPitch(0) >>> bundle = microtones.get_alteration(pitch, "1/1", "flat") >>> bundle.pitch NamedPitch("df'") >>> bundle.accidental_string '\\abjad-flat-markup' .. container:: example >>> pitch = abjad.NumberedPitch(0) >>> bundle = microtones.get_alteration(pitch, "3/2", "sharp") >>> bundle.pitch NumberedPitch(1) >>> bundle.accidental_string '\\three-quarters-sharp-markup' .. container:: example >>> pitch = abjad.NumberedPitch(0) >>> bundle = microtones.get_alteration(pitch, "11/6", "sharp") >>> bundle.pitch NumberedPitch(1) >>> bundle.accidental_string '\\eleven-twelfths-sharp-markup' """ value = quicktions.Fraction(value) semitones = int(math.modf(value)[1]) remainder = quicktions.Fraction(value - int(math.modf(value)[1])) if semitones != 0: pitch = abjad.NumberedInterval(semitones).transpose(pitch) transposed_accidental_value = get_value_sum(pitch, remainder) key = str(transposed_accidental_value) new_accidental = _value_to_accidental[key] + "-markup" if spell is not None: if spell == "sharp": if quicktions.Fraction(_reversed_value_to_accidental[new_accidental]) < 0: # make sharp temp_note = abjad.Note(abjad.NamedPitch(pitch), (1, 4)) abjad.iterpitches.respell_with_sharps([temp_note]) pitch = temp_note.written_pitch transposed_accidental_value = get_value_sum(pitch, remainder) key = str(transposed_accidental_value) new_accidental = _value_to_accidental[key] + "-markup" if spell == "flat": if 0 < quicktions.Fraction(_reversed_value_to_accidental[new_accidental]): # make flat temp_note = abjad.Note(abjad.NamedPitch(pitch), (1, 4)) abjad.iterpitches.respell_with_flats([temp_note]) pitch = temp_note.written_pitch transposed_accidental_value = get_value_sum(pitch, remainder) key = str(transposed_accidental_value) new_accidental = _value_to_accidental[key] + "-markup" return ETBundle(pitch, new_accidental)
[docs]def apply_alteration(note_head, value, spell=None): r""" Applies alteration. .. container:: example Eighth tone accidentals: >>> from quicktions import Fraction >>> steps = [0, "1/8", "2/8", "3/8", "4/8", "5/8", "6/8", "7/8", 1] >>> steps = [Fraction(step) * 2 for step in steps] >>> reverse_steps = [0 - step for step in steps] >>> reverse_steps.reverse() >>> total_steps = [] >>> total_steps.extend(reverse_steps) >>> total_steps.extend(steps) >>> final_steps = sorted(list(set(total_steps))) >>> notes = [abjad.Note("c'4") for step in final_steps] >>> for note, step in zip(notes, final_steps): ... microtones.apply_alteration(note.note_head, step) ... >>> staff = abjad.Staff(notes) >>> score = abjad.Score([staff]) >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> lilypond_file = abjad.LilyPondFile( ... items=[score, abjad.Block(name="layout")], ... includes=[ ... "default.ily", ... "abjad.ily", ... "all-edo-markups-example.ily", ... ], ... global_staff_size=16, ... ) >>> style = '"dodecaphonic"' >>> lilypond_file.layout_block.items.append(fr"\accidentalStyle {style}") >>> abjad.show(lilypond_file) # doctest: +SKIP .. container:: example Tenth tone accidentals: >>> from quicktions import Fraction >>> steps = [0, "1/10", "2/10", "3/10", "4/10", "5/10", "6/10", "7/10", "8/10", "9/10", 1] >>> steps = [Fraction(step) * 2 for step in steps] >>> reverse_steps = [0 - step for step in steps] >>> reverse_steps.reverse() >>> total_steps = [] >>> total_steps.extend(reverse_steps) >>> total_steps.extend(steps) >>> final_steps = sorted(list(set(total_steps))) >>> notes = [abjad.Note("c'4") for step in final_steps] >>> for note, step in zip(notes, final_steps): ... microtones.apply_alteration(note.note_head, step) ... >>> staff = abjad.Staff(notes) >>> score = abjad.Score([staff]) >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> lilypond_file = abjad.LilyPondFile( ... items=[score, abjad.Block(name="layout")], ... includes=[ ... "default.ily", ... "abjad.ily", ... "all-edo-markups-example.ily", ... ], ... global_staff_size=16, ... ) >>> style = '"dodecaphonic"' >>> lilypond_file.layout_block.items.append(fr"\accidentalStyle {style}") >>> abjad.show(lilypond_file) # doctest: +SKIP .. container:: example Twelfth tone accidentals: >>> from quicktions import Fraction >>> steps = [0, "1/12", "2/12", "3/12", "4/12", "5/12", "6/12", "7/12", "8/12", "9/12", "10/12", "11/12", 1] >>> steps = [Fraction(step) * 2 for step in steps] >>> reverse_steps = [0 - step for step in steps] >>> reverse_steps.reverse() >>> total_steps = [] >>> total_steps.extend(reverse_steps) >>> total_steps.extend(steps) >>> final_steps = sorted(list(set(total_steps))) >>> notes = [abjad.Note("c'4") for step in final_steps] >>> for note, step in zip(notes, final_steps): ... microtones.apply_alteration(note.note_head, step) ... >>> staff = abjad.Staff(notes) >>> score = abjad.Score([staff]) >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> lilypond_file = abjad.LilyPondFile( ... items=[score, abjad.Block(name="layout")], ... includes=[ ... "default.ily", ... "abjad.ily", ... "all-edo-markups-example.ily", ... ], ... global_staff_size=16, ... ) >>> style = '"dodecaphonic"' >>> lilypond_file.layout_block.items.append(fr"\accidentalStyle {style}") >>> abjad.show(lilypond_file) # doctest: +SKIP .. container:: example Spells with sharps when ``spell="sharp"``: >>> step = "3/2" >>> note = abjad.Note("c'4") >>> microtones.apply_alteration(note.note_head, step, spell="sharp") >>> staff = abjad.Staff([note]) >>> score = abjad.Score([staff]) >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> lilypond_file = abjad.LilyPondFile( ... items=[score, abjad.Block(name="layout")], ... includes=[ ... "default.ily", ... "abjad.ily", ... "all-edo-markups-example.ily", ... ], ... global_staff_size=16, ... ) >>> style = '"dodecaphonic"' >>> lilypond_file.layout_block.items.append(fr"\accidentalStyle {style}") >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> print(abjad.lilypond(staff)) \new Staff { \tweak Accidental.stencil #ly:text-interface::print \tweak Accidental.text \three-quarters-sharp-markup cs'4 } .. container:: example Spells with flats when ``spell="flat"``: >>> step = "3/2" >>> note = abjad.Note("c'4") >>> microtones.apply_alteration(note.note_head, step, spell="flat") >>> staff = abjad.Staff([note]) >>> score = abjad.Score([staff]) >>> moment = "#(ly:make-moment 1 25)" >>> abjad.setting(score).proportional_notation_duration = moment >>> lilypond_file = abjad.LilyPondFile( ... items=[score, abjad.Block(name="layout")], ... includes=[ ... "default.ily", ... "abjad.ily", ... "all-edo-markups-example.ily", ... ], ... global_staff_size=16, ... ) >>> style = '"dodecaphonic"' >>> lilypond_file.layout_block.items.append(fr"\accidentalStyle {style}") >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> print(abjad.lilypond(staff)) \new Staff { \tweak Accidental.stencil #ly:text-interface::print \tweak Accidental.text \one-quarter-flat-markup df'4 } """ value = quicktions.Fraction(value) pitch = note_head.written_pitch bundle = get_alteration(pitch, value, spell) note_head.written_pitch = bundle.pitch string = r"#ly:text-interface::print" abjad.tweak(note_head, literal=True).Accidental.stencil = string abjad.tweak(note_head, literal=True).Accidental.text = bundle.accidental_string