scriabin/csv_to_score.py : Now interleaves scriabin excerpts.

This commit is contained in:
kevin 2024-05-20 13:24:28 -04:00
parent 2e700eb1ba
commit bec23f191f

View File

@ -8,9 +8,15 @@ def parse_score( score_fn ):
for r in rdr:
d = dict(r)
d['src'] = "gutim"
d['loc'] = int(d['loc']) if d['loc'] else None
d['oloc'] = int(d['oloc']) if d['oloc'] else None
d['src'] = "gutim"
d['loc'] = int(d['loc']) if d['loc'] else None
d['oloc'] = int(d['oloc']) if d['oloc'] else None
d['status'] = int(d['status']) if d['status'] else None
d['d0'] = int(d['d0']) if d['d0'] else None
d['d1'] = int(d['d1']) if d['d1'] else None
d['sec'] = float(d['sec'])
d['opcode'] = d['opcode'].strip()
scoreL.append(d)
@ -36,7 +42,7 @@ def invert_velocity( d1 ):
def parse_scriabin( ifn ):
ped_off = { 'dtick':0, 'sec':0, 'type':'ped', 'd0':64, 'd1':0, 'sci_pitch':None }
ped_off = { 'dtick':0, 'sec':0, 'type':'ped', 'd0':64, 'd1':0, 'sci_pitch':None, 'UID':None }
noteL = []
@ -56,7 +62,8 @@ def parse_scriabin( ifn ):
'type': type_label,
'd0': int(r['D0']),
'd1': invert_velocity(int(r['D1'])) if type_label=='non' else int(r['D1']) ,
'sci_pitch': r['sci_pitch'].strip() if 'sci_pitch' in r else None
'sci_pitch': r['sci_pitch'].strip() if 'sci_pitch' in r else None,
'UID': int(r['UID'])
}
noteL.append(x)
@ -123,6 +130,182 @@ def insert_scriabin( scoreL, noteL, src_label, insert_loc, insert_after_fl, delt
return outL
def interleave_scriabin( scoreL, noteL, src_label, beg_score_loc, cut_score_loc, end_scriabin_uid ):
# beg_score_loc: the 'loc' where the inserted scriabin begins
# cut_score_loc: the 'loc' where the inserted scriabin ends
# end_scriabin_uid: the 'uid' which syncronizes to the 'cut_score_loc'.
#
# BSL CSL
# --------------+ +------------------------------
# | | |
# --------------+ +------------------------------
# | |
# +-------------------------+
# | | |
# +-------------------------+
# ESU
def scribian_esu_secs( noteL, end_scriabin_uid ):
if end_scriabin_uid is None:
return noteL[-1]['sec']
for d in noteL:
if d['UID'] == end_scriabin_uid:
return d['sec']
assert(0)
def score_bsl_secs( scoreL, beg_score_loc ):
for d in scoreL:
if d['loc'] == beg_score_loc:
return d['sec']
assert(0)
def cut_score_loc_index( scoreL, cut_score_loc ):
for i,d in enumerate(scoreL):
if d['loc'] == beg_score_loc:
return i
assert(0)
def assign_event_id( scoreL ):
# Set a matching 'eid' for each note-on/off
# and each pedal-dn/up event.
def _is_note_on(d):
return d['status'] == 144 and d['d1'] is not None and d['d1']>0
def _is_note_off(d):
return d['status'] == 144 and d['d1'] is not None and d['d1']==0
def _is_pedal_dn(d):
return d['opcode'] == 'ped' and d['d1'] >= 64
def _is_pedal_up(d):
return d['opcode'] == 'ped' and d['d1'] < 64
def _set_end_evt_eid(scoreL,i,d,evt_id,func):
for n in scoreL[i:]:
if func(n) and n['d0'] == d['d0']:
n['eid'] = evt_id
return
assert(0)
evt_id = 0
for i,d in enumerate(scoreL):
if _is_note_on(d):
_set_end_evt_eid(scoreL,i,d,evt_id,_is_note_off)
elif _is_pedal_dn(d):
_set_end_evt_eid(scoreL,i,d,evt_id,_is_pedal_up)
if 'eid' not in d:
d['eid'] = evt_id;
evt_id += 1
def offset_scriabin( noteL, offset_sec ):
for d in noteL:
d['sec'] += offset_sec
def offset_score_after_cut( scoreL, csl_index, secs ):
csl_eid = scoreL[csl_index]['eid']
# offset all events that start on or after csl_index
# (this will not shift note-off's/pedal-ups that
# are associated with note-on/pedal-dn's which occur
# before 'csl_index'.
sec0 = None
for d in scoreL[csl_index:]:
if sec0 is not None:
dsec = d['sec'] - sec0
secs += dsec
sec0 = d['sec']
if d['eid'] >= csl_eid:
d['sec'] = secs
def scriabin_to_score( scoreL, noteL, src_label ):
status_map = { 'non':144, 'nof':144, 'ped':176, 'ctl':176 }
type_map = { 'non':'non', 'nof':'nof', 'ped':'ctl', 'ctl':'ctl' }
for n in noteL:
d = {}
d['meas'] = None
d['loc'] = None
d['oloc'] = None
d['sec'] = float(n['sec'])
d['opcode'] = type_map[ n['type'].strip() ]
d['status'] = status_map[n['type'].strip()]
d['d0'] = n['d0']
d['d1'] = n['d1']
d['tick'] = n['dtick']
d['sci_pitch'] = n['sci_pitch']
d['src'] = src_label
scoreL.append(d)
return sorted(scoreL,key=lambda x:x['sec'])
def score_to_csv_debug(scoreL):
fieldnames = list(scoreL[0].keys())
with open("foo.csv","w") as f:
wtr = csv.DictWriter(f,fieldnames)
wtr.writeheader()
for r in scoreL:
wtr.writerow(r)
def remove_eid_field(scoreL):
for i,d in enumerate(scoreL):
if 'eid' in d:
del d['eid']
scoreL[i] = d
# Offset in seconds to be applied to the scriabin to
# sync it's start with 'beg_score_loc'
bsl_secs = score_bsl_secs( scoreL, beg_score_loc )
# Score index of the first score note to play
# at the end of the scriabin sequence
csl_index = cut_score_loc_index( scoreL, cut_score_loc )
# Assign matching note-on/off events the same evt-id
assign_event_id(scoreL)
#score_to_csv_debug(scoreL)
# Shift scriabin to start at the beg_score_loc
offset_scriabin(noteL,bsl_secs)
# Start location in seconds of the second part of the score.
esu_secs = scribian_esu_secs( noteL, end_scriabin_uid )
# Shift the second part of score to begin at 'esu_secs'
# (while not shifting the end events (note-off/ped-up)
# for events which started before the cut)
offset_score_after_cut( scoreL, csl_index, esu_secs )
scoreL = scriabin_to_score( scoreL, noteL, src_label )
remove_eid_field( scoreL )
return scoreL
def write_meta_cfg( o_cfg_fn, name, beg_loc, end_loc ):
cfg = { "player_name": name,
@ -250,31 +433,24 @@ def gen_reference( scoreL, out_dir, out_fn ):
r0 = r
def insert_pedal( scoreL, locL ):
def insert_pedal( scoreL, beg_oloc, end_oloc ):
def _ped_msg( secs, d1 ):
return { "opcode":"ctl","loc":None,"oloc":None,"sec":secs,"status":176,"d0":64,"d1":d1,"src":"ped" }
for dn_loc,up_loc in locL:
assert( dn_loc < up_loc )
outL = []
for i,r in enumerate(scoreL):
if r['oloc'] == dn_loc:
outL.append(_ped_msg(r["secs"],64))
if r['oloc'] == up_loc:
outL.append(_ped_msg(r["secs"],0))
outL.append(r)
state = 'dn'
for d in scoreL:
if state=='dn' and d['oloc'] == beg_oloc:
outL.append( _ped_msg( d['sec'], 64 ) )
state = 'up'
if state =='up' and d['oloc'] == end_oloc:
outL.append( _ped_msg( d['sec'], 0 ))
stae = None
break
return sorted(scoreL, key=lambda x:x['sec'])
@ -398,6 +574,19 @@ if __name__ == "__main__":
]
# beg_score_loc: score location which syncs w/ scriabin start
# cut_score_loc: location where score starts again
# end_scriabin_uid: uid of scriabin which syncs to 'cut_score_loc'.
fileL = [
# *
{ "src":"74_1", "ifn":"scriabin_prelude_op74_1.csv", "beg_score_loc":1229, "cut_score_loc":1231, "end_scriabin_uid":740, "ofn":"scriabin_op74_1" },
# *
{ "src":"74_2", "ifn":"scriabin_prelude_op74_2.csv", "beg_score_loc": 1867, "cut_score_loc":1870, "end_scriabin_uid":628, "ofn":"scriabin_op74_2" },
]
scoreL = parse_score(score_fn)
fieldnamesL = list(scoreL[0].keys())
@ -408,7 +597,10 @@ if __name__ == "__main__":
noteL = parse_scriabin(f['ifn'])
scoreL = insert_scriabin(scoreL, noteL, f['src'], f['insert_loc'], f['after_fl'], f['delta_sec'] )
if 'beg_score_loc' in f:
scoreL = interleave_scriabin( scoreL, noteL, f['src'], f['beg_score_loc'],f['cut_score_loc'], f['end_scriabin_uid'] )
else:
scoreL = insert_scriabin( scoreL, noteL, f['src'], f['insert_loc'], f['after_fl'], f['delta_sec'] )
assign_loc(scoreL)