Transpose
This commit is contained in:
@@ -80,15 +80,20 @@ def shift_key(key: dict, steps: int, semitones: int) -> dict:
|
||||
result['custom'] = True
|
||||
return result
|
||||
|
||||
def transpose_document(document: dict, target_key_name: str) -> dict:
|
||||
def transposition_interval(document: dict, target_key_name: str) -> tuple[int, int]:
|
||||
metadata = document['metadata']
|
||||
origin = metadata['key'].get('tonic') or metadata.get('transpose_origin')
|
||||
if origin is None:
|
||||
raise ValueError('keyless practice requires a vamp:tonic score property')
|
||||
return interval_between(origin, parse_pitch_name(target_key_name))
|
||||
|
||||
def transpose_document(document: dict, target_key_name: str, *, octave_shift: int = 0) -> dict:
|
||||
if type(octave_shift) is not int:
|
||||
raise ValueError('octave adjustment must be an integer')
|
||||
steps, semitones = transposition_interval(document, target_key_name)
|
||||
output = copy.deepcopy(document)
|
||||
metadata = output['metadata']
|
||||
key = metadata['key']
|
||||
origin = key.get('tonic') or metadata.get('transpose_origin')
|
||||
if origin is None:
|
||||
raise ValueError('keyless melody practice requires a vamp:tonic score property')
|
||||
target = parse_pitch_name(target_key_name)
|
||||
steps, semitones = interval_between(origin, target)
|
||||
metadata['key'] = shift_key(key, steps, semitones)
|
||||
metadata['key_signature'] = key_label(metadata['key'])
|
||||
metadata['variant_tonic'] = target_key_name
|
||||
@@ -106,7 +111,10 @@ def transpose_document(document: dict, target_key_name: str) -> dict:
|
||||
h['symbol'] = harmony.symbol(h)
|
||||
for voice in measure['voices']:
|
||||
for note in voice['notes']:
|
||||
note['pitches'] = [shift_pitch(p, steps, semitones) for p in note.get('pitches', [])]
|
||||
try:
|
||||
note['pitches'] = [shift_pitch(p, steps + 7 * octave_shift, semitones + 12 * octave_shift) for p in note.get('pitches', [])]
|
||||
except ValueError as error:
|
||||
raise ValueError(f'measure {measure.get("number", measure["id"])}, voice {voice["id"]}, event {note["id"]}: {error}') from error
|
||||
return output
|
||||
|
||||
def concert_document(document: dict) -> dict:
|
||||
|
||||
Reference in New Issue
Block a user