|
|
import json |
|
|
import pathlib |
|
|
from collections import OrderedDict |
|
|
|
|
|
import click |
|
|
|
|
|
|
|
|
@click.command(help='Eliminate short slur notes in DS files') |
|
|
@click.argument('ds_dir', metavar='DS_DIR') |
|
|
@click.argument('threshold', type=float, metavar='THRESHOLD') |
|
|
def eliminate_short( |
|
|
ds_dir, |
|
|
threshold: float |
|
|
): |
|
|
ds_dir = pathlib.Path(ds_dir).resolve() |
|
|
assert ds_dir.exists(), 'The directory of DS files does not exist.' |
|
|
|
|
|
for ds in ds_dir.iterdir(): |
|
|
if not ds.is_file() or ds.suffix != '.ds': |
|
|
continue |
|
|
|
|
|
with open(ds, 'r', encoding='utf8') as f: |
|
|
params = json.load(f) |
|
|
if not isinstance(params, list): |
|
|
params = [params] |
|
|
params = [OrderedDict(p) for p in params] |
|
|
|
|
|
for param in params: |
|
|
note_list = [ |
|
|
(note, float(dur), bool(int(slur))) |
|
|
for note, dur, slur |
|
|
in zip(param['note_seq'].split(), param['note_dur'].split(), param['note_slur'].split()) |
|
|
] |
|
|
word_note_div = [] |
|
|
cache = [] |
|
|
for note in note_list: |
|
|
if len(cache) == 0 or note[2]: |
|
|
cache.append(note) |
|
|
else: |
|
|
word_note_div.append(cache) |
|
|
cache = [note] |
|
|
if len(cache) > 0: |
|
|
word_note_div.append(cache) |
|
|
|
|
|
word_note_div_new = [] |
|
|
for i in range(len(word_note_div)): |
|
|
word_note_seq = word_note_div[i] |
|
|
if len(word_note_seq) == 1 or all(n[1] < threshold for n in word_note_seq): |
|
|
word_note_div_new.append(word_note_seq) |
|
|
continue |
|
|
|
|
|
word_note_seq_new = [] |
|
|
j = 0 |
|
|
prev_merge = 0. |
|
|
while word_note_seq[j][1] < threshold: |
|
|
|
|
|
prev_merge += word_note_seq[j][1] |
|
|
j += 1 |
|
|
|
|
|
while j < len(word_note_seq): |
|
|
k = j + 1 |
|
|
while k < len(word_note_seq) and word_note_seq[k][1] < threshold: |
|
|
k += 1 |
|
|
post_merge = sum(n[1] for n in word_note_seq[j + 1: k]) |
|
|
if k < len(word_note_seq): |
|
|
post_merge /= 2 |
|
|
word_note_seq_new.append( |
|
|
(word_note_seq[j][0], prev_merge + word_note_seq[j][1] + post_merge, False) |
|
|
) |
|
|
prev_merge = post_merge |
|
|
j = k |
|
|
|
|
|
word_note_div_new.append(word_note_seq_new) |
|
|
|
|
|
note_seq_new = [] |
|
|
note_dur_new = [] |
|
|
note_slur_new = [] |
|
|
for word_note_seq in word_note_div_new: |
|
|
note_seq_new += [n[0] for n in word_note_seq] |
|
|
note_dur_new += [n[1] for n in word_note_seq] |
|
|
note_slur_new += [pos > 0 for pos in range(len(word_note_seq))] |
|
|
param['note_seq'] = ' '.join(note_seq_new) |
|
|
param['note_dur'] = ' '.join(str(round(d, 6)) for d in note_dur_new) |
|
|
param['note_slur'] = ' '.join(str(int(s)) for s in note_slur_new) |
|
|
|
|
|
with open(ds, 'w', encoding='utf8') as f: |
|
|
json.dump(params, f, ensure_ascii=False, indent=2) |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
eliminate_short() |
|
|
|