Numuse Documentation

numuse.converters

Source code for numuse.converters

from __future__ import annotations
from .tools import ranged_modulus_operator
import re
import pprint
from typing import Tuple, Set, List, Callable, Type
from fractions import Fraction
from .notation import RootedIntervalCollection, NoteCollection, Note
from .music import Moment, Line, Measure, Music

[docs]def generate_NCs_from_harmonic_shorthand( harmonic_shorthand: str, key_root: int = 0 ) -> List[Type[NoteCollection]]: """Converts handwritten harmonic shorthand into a list of note collections :param harmonic_shorthand: Harmonic information written by a human :type harmonic_shorthand: str :param key_root: The current keys root :type key_root: int :return: A list of note collections :rtype: List[NoteCollection] """ NCs = [] matches = re.findall( r'\[[^\]]*\]|\([^\)]*\)|"[^"]*"|\<[^\>]*\>|\S+', harmonic_shorthand ) for match in matches: if match[0] == "<": if is_RIC_notation(match): NCs.append( RootedIntervalCollection(*parse_KRIC_shorthand(match, key_root)) ) else: middle = re.findall(r"\<(.*?)\>", match)[0] NCs.append(NoteCollection(add_key_to_notes(middle, key_root))) elif match[0] == "(": if is_RIC_notation(match): NCs.append(RootedIntervalCollection(*parse_RIC_shorthand(match))) else: middle = re.findall(r"\((.*?)\)", match)[0] NCs.append(NoteCollection(get_notes(middle))) else: for unit in match.split(): if unit == "R": NCs.append(NoteCollection(set())) else: NCs.append(NoteCollection({Note(parse_shorthand_unit(unit))})) return NCs
[docs]def parse_music_measures(music_shorthand: List[List[Tuple[str, List[Fraction]]]], harmonic_information_shorthand_parser: Callable[ [str], List[Type[NoteCollection]] ] = generate_NCs_from_harmonic_shorthand): """Converts hand-written music into Music (see `Abbrs`_) :param music_shorthand: Music written in shorthand :type music_shorthand: List[List[Tuple[str, List[Fraction]]]] :return: Music which can be easily analyzed :rtype: Music :Example: >>> idea = [ ... [("0' 4' 7' 11' R", [tt, t, tt, t+b, b])], [("R 7' 4' 7' 7'", [tt, t, tt, t + b, b])], ... [("9' 6' R", [b + tt, t + b, b])], [("6' 2' 9' 6' 0'' 9' R",[tt, t, tt, t, tt, t, b])], ... ["(4 | 0 3 7 10) (9 | 0 3 7 10)",[2*b, 2*b])], [("(2 | 0 4 7 10)",[4*b])], [("(7 | 0 4 7 11)", [4*b])], ... ["(4 7 11 2) (9 0 4 7)",[2*b, 2*b])], [("(2 6 9 0)",[4*b])], [("(7 11 2 6)", [4*b])], ... ["<9 | 0 3 7 10> <2 | 0 3 7 10>",[2*b, 2*b])], [("<7 | 0 4 7 10>",[4*b])], [("<0 | 0 4 7 11>", [4*b])], ... ["<9 0 4 7> <2 5 9 0>",[2*b, 2*b])], [("<7 11 2 5>",[4*b])], [("<0 4 7 11>", [4*b])] ... ] >>> parse_music(idea) """ measures = [] current_time = 0 for measure in music_shorthand: music_lines = [] for line_shorthand in measure: new_time, line = parse_line_shorthand(current_time, line_shorthand, harmonic_information_shorthand_parser) current_time = new_time music_lines.append(Line(line)) measures.append(Measure(music_lines)) return measures
[docs]def parse_line_shorthand( current_time: float, line_shorthand: Tuple[str, List[Fraction]], harmonic_information_shorthand_parser: Callable[ [str], List[NoteCollection] ] = generate_NCs_from_harmonic_shorthand, ): """Converts a handwritten line into a line (see `Abbrs`_) You can pass in your own harmonic information parser because we are not tied to having a single way to represent the harmonic information, We are currently tied to the overall structure of a string and a list of """ line = [] # Rhythm information is the duration of the harmonic information harmonic_information_shorthand, rhythm_information = line_shorthand # This means that they have to have the same size harmonic_information = harmonic_information_shorthand_parser( harmonic_information_shorthand ) h_to_r = zip(harmonic_information, rhythm_information) for h, r in h_to_r: # If h is none, than it's a rest #print([str(x) for x in harmonic_information]) line.append(Moment(current_time, h, r)) current_time += r new_time = current_time return new_time, line
[docs]def parse_KRIC_shorthand(KRIC_shorthand: str, key_root: int) -> Tuple[Note, Set[int]]: """Converts KRIC shorthand to a root and set of NCs""" root, intervals = parse_RIC_shorthand(KRIC_shorthand) return root + key_root, intervals
[docs]def parse_RIC_shorthand(RIC_shorthand: str) -> Tuple[Note, Set[int]]: """Converts RIC shorthand to a root and set of NCs""" str_root, str_intervals = RIC_shorthand.split("|") root = Note(int(str_root)) intervals = {parse_shorthand_unit(unit) for unit in str_intervals.split(" ")} return root, intervals
[docs]def parse_shorthand_unit(RIC_shorthand_unit: str) -> int: """Given a unit of RIC shorthand, we convert it to an interval""" # It will always have a digit d = re.search(r"[0-9R]+", RIC_shorthand_unit) found = RIC_shorthand_unit[d.start() : d.end()] digit = int(found) # octave displacement m = re.search(r"[,'ud]", RIC_shorthand_unit) if m: direction = RIC_shorthand_unit[m.start()] count = len(RIC_shorthand_unit[m.start() :]) multiplier = -1 if direction in ["d", ","] else 1 return digit + multiplier * count * 12 else: return digit
[docs]def is_RIC_notation(notation): return "|" in notation
[docs]def get_notes(str_notes) -> Set[Note]: return {Note(parse_shorthand_unit(unit)) for unit in str_notes.split(" ")}
[docs]def add_key_to_notes(str_notes, key_root): return {n + key_root for n in get_notes(str_notes)}
if __name__ == "__main__": #print("got in") b = 1 # half h = 1 / 2 # thirds t = Fraction(b, 3) # two thirds tt = 2 * t jens_solo_arps = [ [("0' 4' 7' 11' R", [tt, t, tt, t + b, b])], [("R 7' 4' 7' 7'", [tt, t, tt, t + b, b])], [("9' 6' R", [b + tt, t + b, b])], [("6' 2' 9' 6' 0'' 9' R", [tt, t, tt, t, tt, t, b])], [("5' 2' 9' 0'' 5'", [tt, t, tt, t + b, b])], [("2' 7 11 2' 5' 2' R", [tt, t, tt, t, tt, t, b])], [("4' 4' 4' 0'", [b, tt, t + b, b])], [("11 7 11 2' 5' 2' R", [tt, t, tt, t, tt, t, b])], [("4' 0' R 4' R 4' R 4'", [tt, t, tt, t, tt, t, tt, t])], [("7' 4' 7' 7' R 11'", [tt, t, tt, t, 1 + tt, t])], [("0'' 0'' 9' R 9' 6'", [b, tt, t, tt, t, b])], [("R 2' 2' 2' R", [b, b, tt, t, b])], [("0'' 0'' 9' R 9' 5'", [b, tt, t, tt, t, b])], [("R 2' 11 5' 2' 11 7", [b, tt, t, tt, t, tt, t])], [("4' 0' R 4' 0' R", [tt, t, tt, t, b, b])], [("7' 4' 7' 10' R", [tt, t, tt, t + b, b])], [("R 9 0' 9 0' 9", [b, b, tt, t, tt, t])], [("5 9 0' 4' R", [tt, t, tt, t + b, b])], [("R 0' 4' 0' R", [b, b, tt, t, b])], [("9 0' 5 R", [b, tt, t + b, b])], [("2' R 0'' 6' 9' 6'", [b, b, tt, t, tt, t])], [("0'' 0'' 9' R", [b, tt, t + b, b])], [("9' R 9' 2' 5' 2'", [b, b, tt, t, tt, t])], [("11 11 2' R", [b, tt, t + b, b])], [("4' 0' 7' 0' R 4' 7' 11'", [tt, t, tt, t, tt, t, tt, t + b])], [("7' 11' R", [tt, t + b, b])], [("6' 2' 9' 2' R 9'", [tt, t, tt, t, b, b])], [("0'' 6' R 9' R", [tt, t, tt, t + b, b])], [("9' 2' R 5' 2'", [tt, t, tt, t + b, b])], [("5' 11 R 2' 5'", [tt, t, tt, t + b, b])], [("4' 0' 7' 4' 7' 11'", [tt, t, tt, t, tt, t + b])], [("R", [4 * b])], ] m = parse_music(jens_solo_arps) for measure in m.measures: for line in measure.m_lines: for moment in line.m_moments: print(moment)
Free document hosting provided by Read the Docs.