Download src/data/chord_functions.py from adhooge/gcds: direct link, hf CLI and curl.
- Browser
- Download file 6.06 kB
-
https://huggingface.co/spaces/adhooge/gcds/resolve/main/src/data/chord_functions.py
- Command line
-
hf download hf://spaces/adhooge/gcds/src/data/chord_functions.py
-
curl -L -o chord_functions.py https://huggingface.co/spaces/adhooge/gcds/resolve/main/src/data/chord_functions.py
6.06 kB
| from typing import Tuple | |
| import music21 as m21 | |
| import src.exceptions as E | |
| def get_root_from_chordname(chord: str) -> str: | |
| idx = 0 | |
| if chord[idx] == '(': | |
| idx += 1 | |
| tonic = chord[idx] | |
| if tonic == 'H': | |
| # polish/german notation | |
| tonic = 'B' | |
| idx += 1 | |
| try: | |
| if chord[idx] in ['b', '#']: | |
| alt = chord[idx] | |
| else: | |
| alt = '' | |
| except IndexError: | |
| alt = '' | |
| return tonic + alt | |
| def get_bass_from_chordname(chord: str) -> str: | |
| bass = '' | |
| if '/' in chord: | |
| bass = chord.split('/')[-1] | |
| if bass.isdigit(): | |
| bass = '' | |
| elif '+' in bass or '-' in bass: | |
| bass = '' | |
| return bass | |
| def transpose_down(root1: str, root2: str, pos1: str, pos2: str) -> Tuple[str,str,str,str]: | |
| new_root1, new_root2 = _previous_roots(root1, root2) | |
| new_pos1 = _shift_pos(pos1, root1, new_root1) | |
| new_pos2 = _shift_pos(pos2, root2, new_root2) | |
| return new_root1, new_root2, new_pos1, new_pos2 | |
| def transpose_up(root1: str, root2: str, pos1: str, pos2: str) -> Tuple[str,str,str,str]: | |
| new_root1, new_root2 = _next_roots(root1, root2) | |
| new_pos1 = _shift_pos(pos1, root1, new_root1) | |
| new_pos2 = _shift_pos(pos2, root2, new_root2) | |
| return new_root1, new_root2, new_pos1, new_pos2 | |
| def _previous_root(root: str) -> str: | |
| note = m21.note.Note(root) | |
| previous = note.transpose(-1).name | |
| if '-' in previous: | |
| previous = previous.replace('-', 'b') | |
| return previous | |
| def _next_root(root: str) -> str: | |
| note = m21.note.Note(root) | |
| nextr = note.transpose(+1).name | |
| if '-' in nextr: | |
| nextr = nextr.replace('-', 'b') | |
| return nextr | |
| def _get_midi_diff(root1: str, root2: str) -> int: | |
| midi2 = m21.note.Note(root2).pitch.midi | |
| midi1 = m21.note.Note(root1).pitch.midi | |
| midi1 = midi1 % 12 | |
| midi2 = midi2 % 12 | |
| diff = midi2 - midi1 | |
| if diff > 6: | |
| diff = diff - 12 | |
| if diff < -6: | |
| diff = diff + 12 | |
| return diff | |
| def _next_roots(root1: str, root2: str) -> Tuple[str, str]: | |
| nr1 = _next_root(root1) | |
| nr2 = _next_root(root2) | |
| diff1 = _get_midi_diff(root1, nr1) | |
| diff2 = _get_midi_diff(root2, nr2) | |
| if diff1 != diff2: | |
| ddiff1 = diff1 | |
| nnr1 = nr1 | |
| while ddiff1 < diff2: | |
| nnr1 = _next_root(nnr1) | |
| ddiff1 = _get_midi_diff(root1, nnr1) | |
| if ddiff1 == diff2: | |
| return nnr1, nr2 | |
| else: | |
| ddiff2 = diff2 | |
| nnr2 = nr2 | |
| while ddiff2 < diff1: | |
| nnr2 = _next_root(nnr2) | |
| ddiff2 = _get_midi_diff(root2, nnr2) | |
| if ddiff2 == diff1: | |
| return nr1, nnr2 | |
| else: | |
| return nr1, nr2 | |
| def _previous_roots(root1: str, root2: str) -> Tuple[str, str]: | |
| pr1 = _previous_root(root1) | |
| pr2 = _previous_root(root2) | |
| diff1 = _get_midi_diff(root1, pr1) | |
| diff2 = _get_midi_diff(root2, pr2) | |
| if diff1 != diff2: | |
| ddiff1 = diff1 | |
| ppr1 = pr1 | |
| while ddiff1 > diff2: | |
| ppr1 = _previous_root(ppr1) | |
| ddiff1 = _get_midi_diff(root1, ppr1) | |
| if ddiff1 == diff2: | |
| return ppr1, pr2 | |
| else: | |
| ddiff2 = diff2 | |
| ppr2 = pr2 | |
| while ddiff2 > diff1: | |
| ppr2 = _previous_root(ppr2) | |
| ddiff2 = _get_midi_diff(root2, ppr2) | |
| if ddiff2 == diff1: | |
| return pr1, ppr2 | |
| else: | |
| return pr1, pr2 | |
| def _shift_pos(pos: str, root: str, new_root: str) -> str: | |
| diff = _get_midi_diff(root, new_root) | |
| if diff == 0: | |
| return pos | |
| else: | |
| new_pos = transpose_pos(pos, diff) | |
| return new_pos | |
| def transpose_pos(pos: str, diff: int) -> str: | |
| new_pos = '' | |
| for char in pos.split('.'): | |
| if char in ['x', '']: | |
| new_pos += char | |
| else: | |
| new_char = str(int(char) + diff) | |
| new_pos += new_char | |
| new_pos += '.' | |
| return new_pos[:-1] | |
| def reach_twelfth_fret(pos: str) -> bool: | |
| for fret in pos.split('.'): | |
| if fret in ['x', '']: | |
| continue | |
| if int(fret) >= 12: | |
| return True | |
| return False | |
| def replace_root(chord: str, old_root: str, new_root: str) -> str: | |
| out = chord.replace(old_root, new_root, 1) | |
| return out | |
| def replace_bass(chord: str, old_bass: str, new_bass: str) -> str: | |
| out = chord.replace('/' + old_bass, '/' + new_bass) | |
| return out | |
| def update_chord(chord: str, old_root: str, new_root: str, | |
| old_bass: str, new_bass: str) -> str: | |
| if old_bass == '': | |
| if new_bass != '': | |
| raise ValueError(f"Why is old bass empty and not new bass?") | |
| out = replace_root(chord, old_root, new_root) | |
| out = replace_bass(out, old_bass, new_bass) | |
| return out | |
| def transpose(chordname: str, pos: str, shift: int) -> Tuple[str, str]: | |
| root = get_root_from_chordname(chordname) | |
| bass = get_bass_from_chordname(chordname) | |
| if shift == 1: | |
| try: | |
| new_root = _next_root(root) | |
| except m21.pitch.PitchException: | |
| raise E.RootError | |
| if bass != '': | |
| try: | |
| new_bass = _next_root(bass) | |
| except m21.pitch.PitchException: | |
| raise E.RootError | |
| else: | |
| new_bass = '' | |
| new_pos = transpose_pos(pos, shift) | |
| new_chord = update_chord(chordname, root, new_root, bass, new_bass) | |
| elif shift == -1: | |
| try: | |
| new_root = _previous_root(root) | |
| except m21.pitch.PitchException: | |
| raise E.RootError | |
| if bass != '': | |
| #print('bass:', bass) | |
| try: | |
| new_bass = _previous_root(bass) | |
| except m21.pitch.PitchException: | |
| raise E.RootError | |
| else: | |
| new_bass = '' | |
| new_pos = transpose_pos(pos, shift) | |
| new_chord = update_chord(chordname, root, new_root, bass, new_bass) | |
| else: | |
| raise ValueError(f"Shift other than +/- 1 is not supported yet. You tried shifting with {shift}") | |
| return new_chord, new_pos | |