Compare commits
9 Commits
648e29c4c4
...
7119fe471b
Author | SHA1 | Date | |
---|---|---|---|
|
7119fe471b | ||
|
f36e7c8a64 | ||
|
e32f224d12 | ||
|
109944f130 | ||
|
6b845bd1b3 | ||
|
55695164b5 | ||
|
ca030abcf5 | ||
|
d96bc2fded | ||
|
9374bcee0c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
|
*.ipynb
|
||||||
*.pyc
|
*.pyc
|
||||||
.ipynb_checkpoints
|
.ipynb_checkpoints
|
68
ChordTester.py
Normal file
68
ChordTester.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import types
|
||||||
|
import time
|
||||||
|
|
||||||
|
class ChordTester:
|
||||||
|
def __init__( self, cfg, api ):
|
||||||
|
self.api = api
|
||||||
|
self.cfg = types.SimpleNamespace(**cfg.ChordTester)
|
||||||
|
|
||||||
|
self.nextMs = 0
|
||||||
|
self.isStartedFl = False
|
||||||
|
self.curNoteCnt = 0
|
||||||
|
self.curRepeatCnt = 0
|
||||||
|
self.isPlayingFl = False
|
||||||
|
|
||||||
|
|
||||||
|
def start( self ):
|
||||||
|
self.api.set_hold_duty_all( self.cfg.holdDuty )
|
||||||
|
if self.cfg.useVelTableFl:
|
||||||
|
self.api.set_vel_table_all( self.cfg.pitchL )
|
||||||
|
self.curNoteCnt = 0
|
||||||
|
self.curRepeatCnt = 0
|
||||||
|
self.isStartedFl = True
|
||||||
|
|
||||||
|
def stop( self ):
|
||||||
|
self.isStartedFl = False
|
||||||
|
self.api.all_notes_off()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def tick( self, ms ):
|
||||||
|
|
||||||
|
if self.isStartedFl and ms >= self.nextMs:
|
||||||
|
|
||||||
|
if self.isPlayingFl:
|
||||||
|
|
||||||
|
# turn notes off
|
||||||
|
for i in range(0,self.curNoteCnt+1):
|
||||||
|
self.api.note_off( self.cfg.pitchL[i])
|
||||||
|
time.sleep( 0.01 )
|
||||||
|
|
||||||
|
# repeat or advance the chord note count
|
||||||
|
self.curRepeatCnt += 1
|
||||||
|
if self.curRepeatCnt >= self.cfg.repeatCnt:
|
||||||
|
self.curRepeatCnt = 0
|
||||||
|
self.curNoteCnt += 1
|
||||||
|
if self.curNoteCnt >= len(self.cfg.pitchL):
|
||||||
|
self.isStartedFl = False
|
||||||
|
self.curNoteCnt = 0
|
||||||
|
|
||||||
|
self.isPlayingFl = False
|
||||||
|
self.nextMs = ms + self.cfg.pauseMs
|
||||||
|
|
||||||
|
else:
|
||||||
|
for i in range(0,self.curNoteCnt+1):
|
||||||
|
if self.cfg.useVelTableFl:
|
||||||
|
self.api.note_on_vel(self.cfg.pitchL[i], 45 )
|
||||||
|
else:
|
||||||
|
self.api.note_on_us(self.cfg.pitchL[i], self.cfg.atkUsec)
|
||||||
|
time.sleep( 0.02 )
|
||||||
|
|
||||||
|
self.nextMs = ms + self.cfg.durMs
|
||||||
|
self.isPlayingFl = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -136,10 +136,12 @@ class MidiDevice(object):
|
|||||||
o_msgL = []
|
o_msgL = []
|
||||||
|
|
||||||
if self.mip is not None:
|
if self.mip is not None:
|
||||||
midi_msg = self.mip.get_message()
|
while True:
|
||||||
if midi_msg and midi_msg[0]:
|
midi_msg = self.mip.get_message()
|
||||||
|
if not midi_msg or not midi_msg[0]:
|
||||||
|
break;
|
||||||
|
|
||||||
if self.monitorInFl:
|
if self.inMonitorFl:
|
||||||
o_msgL.append( self._midi_data_to_text_msg(True,midi_msg[0]) )
|
o_msgL.append( self._midi_data_to_text_msg(True,midi_msg[0]) )
|
||||||
|
|
||||||
if self.throughFl and self.mop is not None:
|
if self.throughFl and self.mop is not None:
|
||||||
|
119
NoteTester.py
Normal file
119
NoteTester.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import sys,os,types,json
|
||||||
|
from random import randrange
|
||||||
|
|
||||||
|
class NoteTester:
|
||||||
|
def __init__( self, cfg, api ):
|
||||||
|
self.cfg = cfg
|
||||||
|
self.api = api
|
||||||
|
|
||||||
|
r = types.SimpleNamespace(**cfg.NoteTester)
|
||||||
|
|
||||||
|
self.durMsL = [ randrange(r.minNoteDurMs, r.maxNoteDurMs) for _ in range(r.noteCount) ]
|
||||||
|
self.pauseMsL = [ randrange(r.minPauseDurMs, r.maxPauseDurMs) for _ in range(r.noteCount) ]
|
||||||
|
self.eventL = []
|
||||||
|
self.nextMs = 0 # next transition time
|
||||||
|
self.eventIdx = 0 # next event to play
|
||||||
|
self.noteOnFl = False # True if note is currently sounding
|
||||||
|
self.pitch = r.pitch #
|
||||||
|
self.filename = r.filename
|
||||||
|
self.isStartedFl = False
|
||||||
|
self.minAttackUsec = r.minAttackUsec
|
||||||
|
self.maxAttackUsec = r.maxAttackUsec
|
||||||
|
|
||||||
|
def start( self ):
|
||||||
|
self.eventIdx = 0
|
||||||
|
self.noteOnFl = False
|
||||||
|
self.nextMs = 0
|
||||||
|
self.isStartedFl = True
|
||||||
|
|
||||||
|
def stop( self ):
|
||||||
|
self.isStartedFl = False
|
||||||
|
self.write()
|
||||||
|
|
||||||
|
def tick( self, ms ):
|
||||||
|
|
||||||
|
if self.isStartedFl and ms > self.nextMs:
|
||||||
|
|
||||||
|
offsMs = 0
|
||||||
|
|
||||||
|
if self.noteOnFl:
|
||||||
|
self.noteOnFl = False
|
||||||
|
self.api.note_off( self.pitch )
|
||||||
|
offsMs = self.pauseMsL[ self.eventIdx ]
|
||||||
|
self.eventIdx += 1
|
||||||
|
print("off:%i ms" % (offsMs))
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
usec = self.minAttackUsec + (int(self.eventIdx * 250) % int(self.maxAttackUsec - self.minAttackUsec))
|
||||||
|
decay_level = self.api.calc_decay_level( usec )
|
||||||
|
|
||||||
|
self.api.note_on_us( self.pitch, usec, decay_level )
|
||||||
|
offsMs = self.durMsL[ self.eventIdx ]
|
||||||
|
print("usec:%i %i dcy:%i" % (usec,offsMs, decay_level) )
|
||||||
|
self.noteOnFl = True
|
||||||
|
|
||||||
|
|
||||||
|
self.eventL.append( (ms, self.noteOnFl) )
|
||||||
|
self.nextMs = ms + offsMs
|
||||||
|
|
||||||
|
if self.eventIdx >= len(self.durMsL):
|
||||||
|
self.write();
|
||||||
|
self.isStartedFl = False
|
||||||
|
print("done % i" % (len(self.eventL)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def write( self ):
|
||||||
|
|
||||||
|
with open(self.filename,"w") as f:
|
||||||
|
json.dump({ "eventL":self.eventL },f )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def note_tester_compare( nt_fn, logica_fn ):
|
||||||
|
|
||||||
|
eventL = []
|
||||||
|
logicaL = []
|
||||||
|
|
||||||
|
with open(nt_fn,"r") as f:
|
||||||
|
r = json.load(f)
|
||||||
|
eventL = r['eventL']
|
||||||
|
eventL = [ (ms-eventL[0][0], level ) for ms,level in eventL ]
|
||||||
|
|
||||||
|
with open(logica_fn,"r") as f:
|
||||||
|
logicaL = [ ( d['count']/16e3,d['level']) for d in json.load(f) if d['signal'] == 0 ]
|
||||||
|
logicaL = [ (ms-logicaL[0][0], level!=0 ) for ms,level in logicaL ]
|
||||||
|
|
||||||
|
|
||||||
|
print(len(eventL))
|
||||||
|
print(len(logicaL))
|
||||||
|
|
||||||
|
#edL = [ eventL[i][0] - eventL[i-1][0] for i in range(2,len(eventL)) ]
|
||||||
|
#ldL = [ logicaL[i][0] - logicaL[i-1][0] for i in range(2,len(logicaL)) ]
|
||||||
|
|
||||||
|
#print(edL[:10])
|
||||||
|
#print(ldL[:10])
|
||||||
|
|
||||||
|
|
||||||
|
durMs = 0
|
||||||
|
ms = 0
|
||||||
|
for i,(t0,t1) in enumerate(zip(eventL,logicaL)):
|
||||||
|
t = t0[0] # eventL[] time
|
||||||
|
dt = int(t - t1[0]) # diff between eventL[] and logicaL[] time
|
||||||
|
fl = ' ' if t0[1] == t1[1] else '*' # mark level mismatch with '*'
|
||||||
|
print("%5i %7i %4i %i %s" % (i,durMs,dt,t0[1],fl))
|
||||||
|
durMs = t-ms
|
||||||
|
ms = t
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
nt_fn = "note_tester.json"
|
||||||
|
logica_fn = sys.argv[1]
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
nt_fn = sys.argv[2]
|
||||||
|
|
||||||
|
note_tester_compare( nt_fn, logica_fn)
|
||||||
|
|
||||||
|
|
148
PolyNoteTester.py
Normal file
148
PolyNoteTester.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import types
|
||||||
|
import time
|
||||||
|
from random import randrange
|
||||||
|
|
||||||
|
class PolyNoteTester:
|
||||||
|
def __init__( self, cfg, api ):
|
||||||
|
self.api = api
|
||||||
|
|
||||||
|
r = types.SimpleNamespace(**cfg.PolyNoteTester)
|
||||||
|
self.cfg = r
|
||||||
|
|
||||||
|
if r.mode == "simple":
|
||||||
|
print("mode:simple")
|
||||||
|
self.schedL = self._gen_simple_sched(r)
|
||||||
|
else:
|
||||||
|
print("mode:poly")
|
||||||
|
self.schedL = self._gen_sched(r)
|
||||||
|
|
||||||
|
|
||||||
|
self.schedL = sorted( self.schedL, key=lambda x: x[0] )
|
||||||
|
self.nextMs = 0 # next transition time
|
||||||
|
self.schedIdx = 0 # next event to play
|
||||||
|
self.isStartedFl = False
|
||||||
|
|
||||||
|
#self._report()
|
||||||
|
|
||||||
|
def _report( self ):
|
||||||
|
for t,cmd,pitch,atkUs in self.schedL:
|
||||||
|
print("%s %6i %3i %5i" % (cmd,t,pitch,atkUs))
|
||||||
|
|
||||||
|
def _gen_simple_sched( self, r ):
|
||||||
|
""" Play each note sequentially from lowest to highest. """
|
||||||
|
durMs = int(r.minNoteDurMs + (r.maxNoteDurMs - r.minNoteDurMs)/2)
|
||||||
|
ioMs = int(r.minInterOnsetMs + (r.maxInterOnsetMs - r.minInterOnsetMs)/2)
|
||||||
|
atkUs = int(r.minAttackUsec + (r.maxAttackUsec - r.minAttackUsec)/2)
|
||||||
|
schedL = []
|
||||||
|
|
||||||
|
t0 = 0
|
||||||
|
for pitch in range(r.minPitch,r.maxPitch+1):
|
||||||
|
schedL.append((t0,'on',pitch,atkUs))
|
||||||
|
schedL.append((t0+durMs,'off',pitch,0))
|
||||||
|
t0 += durMs + ioMs
|
||||||
|
|
||||||
|
return schedL
|
||||||
|
|
||||||
|
|
||||||
|
def _does_note_overlap( self, beg0Ms, end0Ms, beg1Ms, end1Ms ):
|
||||||
|
""" if note 0 is entirely before or after note 1 """
|
||||||
|
return not (beg0Ms > end1Ms or end0Ms < beg1Ms)
|
||||||
|
|
||||||
|
def _do_any_notes_overlap( self, begMs, endMs, begEndL ):
|
||||||
|
for beg1,end1 in begEndL:
|
||||||
|
if self._does_note_overlap(begMs,endMs,beg1,end1):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _get_last_end_time( self, begEndL ):
|
||||||
|
end0 = 0
|
||||||
|
for beg,end in begEndL:
|
||||||
|
if end > end0:
|
||||||
|
end0 = end
|
||||||
|
|
||||||
|
return end0
|
||||||
|
|
||||||
|
|
||||||
|
def _gen_sched( self, r ):
|
||||||
|
|
||||||
|
pitchL = [ randrange(r.minPitch,r.maxPitch) for _ in range(r.noteCount) ]
|
||||||
|
durMsL = [ randrange(r.minNoteDurMs, r.maxNoteDurMs) for _ in range(r.noteCount) ]
|
||||||
|
ioMsL = [ randrange(r.minInterOnsetMs, r.maxInterOnsetMs) for _ in range(r.noteCount) ]
|
||||||
|
atkUsL = [ randrange(r.minAttackUsec, r.maxAttackUsec) for _ in range(r.noteCount) ]
|
||||||
|
schedL = []
|
||||||
|
pitchD = {} # pitch: [ (begMs,endMs) ]
|
||||||
|
|
||||||
|
t0 = 0
|
||||||
|
# for each pitch,dur,ioi,atkUs tuple
|
||||||
|
for pitch,durMs,interOnsetMs,atkUs in zip(pitchL,durMsL,ioMsL,atkUsL):
|
||||||
|
|
||||||
|
# calc note begin and end time
|
||||||
|
begMs = t0
|
||||||
|
endMs = t0 + durMs
|
||||||
|
|
||||||
|
# if this pitch hasn't yet been added to pitchD
|
||||||
|
if pitch not in pitchD:
|
||||||
|
pitchD[ pitch ] = [ (begMs,endMs) ]
|
||||||
|
else:
|
||||||
|
|
||||||
|
# if the proposed note overlaps with other notes for this pitch
|
||||||
|
if self._do_any_notes_overlap( begMs, endMs, pitchD[pitch] ):
|
||||||
|
# move this pitch past the last note
|
||||||
|
begMs = self._get_last_end_time( pitchD[pitch] ) + interOnsetMs
|
||||||
|
endMs = begMs + durMs
|
||||||
|
|
||||||
|
# add the new note to pitchD
|
||||||
|
pitchD[ pitch ].append( (begMs,endMs) )
|
||||||
|
|
||||||
|
|
||||||
|
# update the schedule
|
||||||
|
schedL.append( (begMs, 'on', pitch, atkUs))
|
||||||
|
schedL.append( (endMs, 'off', pitch, 0 ))
|
||||||
|
|
||||||
|
t0 += interOnsetMs
|
||||||
|
|
||||||
|
|
||||||
|
return schedL
|
||||||
|
|
||||||
|
|
||||||
|
def start( self ):
|
||||||
|
self.schedIdx = 0
|
||||||
|
self.nextMs = 0
|
||||||
|
self.api.set_hold_duty_all(self.cfg.holdDutyPct)
|
||||||
|
self.isStartedFl = True
|
||||||
|
|
||||||
|
|
||||||
|
def stop( self ):
|
||||||
|
self.isStartedFl = False
|
||||||
|
self.api.all_notes_off()
|
||||||
|
|
||||||
|
|
||||||
|
def tick( self, ms ):
|
||||||
|
|
||||||
|
while self.isStartedFl and ms >= self.nextMs and self.schedIdx < len(self.schedL):
|
||||||
|
|
||||||
|
t0,cmd,pitch,usec = self.schedL[self.schedIdx]
|
||||||
|
|
||||||
|
if cmd == 'on':
|
||||||
|
if pitch not in self.cfg.skipPitchL:
|
||||||
|
decay_level = self.api.calc_decay_level( usec )
|
||||||
|
self.api.note_on_us( pitch, usec, decay_level )
|
||||||
|
print("on %i %i %i" % (pitch,usec,decay_level))
|
||||||
|
|
||||||
|
elif cmd == 'off':
|
||||||
|
if pitch not in self.cfg.skipPitchL:
|
||||||
|
self.api.note_off( pitch )
|
||||||
|
print("off %i" % pitch)
|
||||||
|
|
||||||
|
self.schedIdx += 1
|
||||||
|
if self.schedIdx < len(self.schedL):
|
||||||
|
self.nextMs = ms + (self.schedL[self.schedIdx][0] - t0)
|
||||||
|
else:
|
||||||
|
self.isStartedFl = False
|
||||||
|
print("Done.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
39
README.md
39
README.md
@ -27,10 +27,13 @@ Capture note 60 and 61 using the full_pulseL[] and holdDutyPctD{} from the p_ac.
|
|||||||
## Plot Cheat Sheet
|
## Plot Cheat Sheet
|
||||||
|
|
||||||
|
|
||||||
![Plot Seq 1](doc/do_td_plot.png)
|
---
|
||||||
|
|
||||||
Print a specific pitch and take.
|
Print a specific pitch and take.
|
||||||
|
|
||||||
|
![Plot Seq 1](doc/do_td_plot.png)
|
||||||
|
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq.py p_ac.yml ~/temp/p_ac_3_of td_plot 60 2
|
python plot_seq.py p_ac.yml ~/temp/p_ac_3_of td_plot 60 2
|
||||||
|
|
||||||
@ -39,19 +42,20 @@ Print a specific pitch and take.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
![Multi Usec dB](doc/us_db.png)
|
|
||||||
|
|
||||||
Plot all the takes for a given pitch
|
Plot all the takes for a given pitch
|
||||||
|
|
||||||
|
![Multi Usec dB](doc/us_db.png)
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od us_db 84
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od us_db 84
|
||||||
````
|
````
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Plot a specific set of pitches and takes.
|
||||||
|
|
||||||
![Overlapping USec dB](doc/us_db_takes.png)
|
![Overlapping USec dB](doc/us_db_takes.png)
|
||||||
|
|
||||||
Plot a specific set of pitches and takes.
|
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_of us_db_pitch_take 75 0 76 0 77 0 78 0 72 10 73 1 74 1
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_of us_db_pitch_take 75 0 76 0 77 0 78 0 72 10 73 1 74 1
|
||||||
@ -59,9 +63,10 @@ python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_of us_db_pitch_take 75 0 76 0 77 0 7
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Plot the last take from a list of pitches.
|
||||||
|
|
||||||
![Overlapping USec dB](doc/us_db_takes_last.png)
|
![Overlapping USec dB](doc/us_db_takes_last.png)
|
||||||
|
|
||||||
Plot the last take from a list of pitches.
|
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_of us_db_pitch_last 77 78 79 80
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_of us_db_pitch_last 77 78 79 80
|
||||||
@ -70,9 +75,10 @@ python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_of us_db_pitch_last 77 78 79 80
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Plot the time domain envelope for a specific set of pitches and takes.
|
||||||
|
|
||||||
![Multi Plot 1](doc/multi_plot.png)
|
![Multi Plot 1](doc/multi_plot.png)
|
||||||
|
|
||||||
Plot the time domain envelope for a specific set of pitches and takes.
|
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq.py p_ac.yml ~/temp/p_ac_3_od td_multi_plot 60 3 60 4 60 5
|
python plot_seq.py p_ac.yml ~/temp/p_ac_3_od td_multi_plot 60 3 60 4 60 5
|
||||||
@ -81,9 +87,10 @@ plot_seq.py `do_td_multi_plot(inDir,cfg.analysisArgs,[(36,4), (48,2)] )
|
|||||||
````
|
````
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Plot the spectrum with harmonic location markers of a specific set of pitches and takes.
|
||||||
|
|
||||||
![Spectral Ranges](doc/plot_spectral_ranges.png)
|
![Spectral Ranges](doc/plot_spectral_ranges.png)
|
||||||
|
|
||||||
Plot the spectrum with harmonic location markers of a specific set of pitches and takes.
|
|
||||||
|
|
||||||
````
|
````
|
||||||
# pitch0 takeId0 pitch1 takeId1
|
# pitch0 takeId0 pitch1 takeId1
|
||||||
@ -93,21 +100,21 @@ python plot_seq.py p_ac.yml ~/temp/p_ac_3_od plot_spectral_ranges 60 3
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
![Usec dB Spread](doc/us_db_map.png)
|
|
||||||
|
|
||||||
Plot the microsecond variance to achieve a given decibel value.
|
Plot the microsecond variance to achieve a given decibel value.
|
||||||
|
|
||||||
|
![Usec dB Spread](doc/us_db_map.png)
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od us_db_map 84 72
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od us_db_map 84 72
|
||||||
````
|
````
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
![Resample](doc/resample_pulse_times.png)
|
|
||||||
|
|
||||||
Analyze all takes for given pitch and show the mean us/db curve and
|
Analyze all takes for given pitch and show the mean us/db curve and
|
||||||
places where resampling may be necessary.
|
places where resampling may be necessary.
|
||||||
|
|
||||||
|
![Resample](doc/resample_pulse_times.png)
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq.py p_ac.yml ~/temp/p_ac_3_of resample_pulse_times 84
|
python plot_seq.py p_ac.yml ~/temp/p_ac_3_of resample_pulse_times 84
|
||||||
````
|
````
|
||||||
@ -115,30 +122,30 @@ python plot_seq.py p_ac.yml ~/temp/p_ac_3_of resample_pulse_times 84
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
![Min Max](doc/min_max_db.png)
|
|
||||||
|
|
||||||
Plot the min and max decibel values for specified pitches.
|
Plot the min and max decibel values for specified pitches.
|
||||||
|
|
||||||
|
![Min Max](doc/min_max_db.png)
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od min_max 36 48 60 72 84
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od min_max 36 48 60 72 84
|
||||||
````
|
````
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
![Min Max 2](doc/min_max_db_2.png)
|
|
||||||
|
|
||||||
Plot the min and max decibel values for specified pitches.
|
Plot the min and max decibel values for specified pitches.
|
||||||
|
|
||||||
|
![Min Max 2](doc/min_max_db_2.png)
|
||||||
|
|
||||||
````
|
````
|
||||||
# pitch0 pitch1 pitch2 pitch3 pitch4 takeId
|
# pitch0 pitch1 pitch2 pitch3 pitch4 takeId
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od min_max_2 36 48 60 72 84 2
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od min_max_2 36 48 60 72 84 2
|
||||||
````
|
````
|
||||||
|
|
||||||
---
|
---
|
||||||
![Manual dB](doc/manual_db.png)
|
|
||||||
|
|
||||||
Plot the min and max decibel values for specified set of manually corrected pitches.
|
Plot the min and max decibel values for specified set of manually corrected pitches.
|
||||||
|
|
||||||
|
![Manual dB](doc/manual_db.png)
|
||||||
|
|
||||||
````
|
````
|
||||||
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od manual_db
|
python plot_seq_1.py p_ac.yml ~/temp/p_ac_3_od manual_db
|
||||||
|
148
VelTablePlayer.py
Normal file
148
VelTablePlayer.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import json
|
||||||
|
from rt_note_analysis import RT_Analyzer
|
||||||
|
|
||||||
|
class VelTablePlayer:
|
||||||
|
|
||||||
|
def __init__( self, cfg, api, audio, holdDutyPctD, fn ):
|
||||||
|
self.cfg = cfg
|
||||||
|
self.api = api
|
||||||
|
self.audio = audio
|
||||||
|
self.rtAnalyzer = RT_Analyzer()
|
||||||
|
self.holdDutyPctD = holdDutyPctD
|
||||||
|
self.durMs = 500
|
||||||
|
self.mode = "across"
|
||||||
|
self.state = "off"
|
||||||
|
self.minPitch = 21
|
||||||
|
self.maxPitch = 108
|
||||||
|
self.velMapD = {}
|
||||||
|
|
||||||
|
self.curMaxPitch = self.maxPitch
|
||||||
|
self.curMinPitch = self.minPitch
|
||||||
|
self.curPitch = 21
|
||||||
|
self.curVelocity = 0
|
||||||
|
self.curEndMs = 0
|
||||||
|
self.curBegNoteMs = 0
|
||||||
|
self.curEndNoteMs = 0
|
||||||
|
|
||||||
|
with open(fn,"r") as f:
|
||||||
|
d = json.load(f)
|
||||||
|
|
||||||
|
for pitch,value in d.items():
|
||||||
|
self.velMapD[ int(pitch) ] = [ int(x[0]) for x in d[pitch] ]
|
||||||
|
|
||||||
|
assert self.minPitch in self.velMapD
|
||||||
|
assert self.maxPitch in self.velMapD
|
||||||
|
|
||||||
|
|
||||||
|
def start( self, minPitch, maxPitch, mode ):
|
||||||
|
self.curMaxPitch = maxPitch
|
||||||
|
self.curMinPitch = minPitch
|
||||||
|
self.curPitch = minPitch
|
||||||
|
self.curVelocity = 0
|
||||||
|
self.state = "note_on"
|
||||||
|
self.mode = mode
|
||||||
|
self.audio.record_enable(True) # start recording audio
|
||||||
|
|
||||||
|
def stop( self ):
|
||||||
|
self.curPitch = self.minPitch
|
||||||
|
self._all_notes_off()
|
||||||
|
self.audio.record_enable(False)
|
||||||
|
|
||||||
|
def tick( self, ms ):
|
||||||
|
if self.state == "off":
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif self.state == "note_on":
|
||||||
|
self.state = self._note_on(ms)
|
||||||
|
|
||||||
|
elif self.state == "playing":
|
||||||
|
if ms >= self.curEndMs:
|
||||||
|
self.state = "note_off"
|
||||||
|
|
||||||
|
elif self.state == "note_off":
|
||||||
|
self.state = self._note_off(ms)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_duty_cycle( self, pitch, usec ):
|
||||||
|
usDutyL = self.holdDutyPctD[pitch]
|
||||||
|
|
||||||
|
for i in range(len(usDutyL)):
|
||||||
|
if usDutyL[i][0] >= usec:
|
||||||
|
return usDutyL[i][1]
|
||||||
|
|
||||||
|
return usDutyL[-1][1]
|
||||||
|
|
||||||
|
def _calc_next_pitch( self ):
|
||||||
|
|
||||||
|
self.curPitch += 1
|
||||||
|
while self.curPitch not in self.velMapD and self.curPitch <= self.curMaxPitch:
|
||||||
|
self.curPitch+1
|
||||||
|
|
||||||
|
return self.curPitch <= self.curMaxPitch
|
||||||
|
|
||||||
|
def _get_next_note_params( self ):
|
||||||
|
|
||||||
|
usec = None
|
||||||
|
dutyPct = None
|
||||||
|
doneFl = False
|
||||||
|
|
||||||
|
if self.mode == "updown":
|
||||||
|
if self.curVelocity + 1 < len(self.velMapD[ self.curPitch ]):
|
||||||
|
self.curVelocity += 1
|
||||||
|
else:
|
||||||
|
|
||||||
|
if self._calc_next_pitch():
|
||||||
|
self.curVelocity = 0
|
||||||
|
else:
|
||||||
|
doneFl = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
if self._calc_next_pitch():
|
||||||
|
self.curPitch += 1
|
||||||
|
else:
|
||||||
|
if self.curVelocity + 1 < len(self.velMapD[ self.curPitch ]):
|
||||||
|
self.curVelocity += 1
|
||||||
|
self.curPitch = self.curMinPitch
|
||||||
|
else:
|
||||||
|
doneFl = True
|
||||||
|
|
||||||
|
if doneFl:
|
||||||
|
self.audio.record_enable(False)
|
||||||
|
else:
|
||||||
|
usec = self.velMapD[self.curPitch][self.curVelocity]
|
||||||
|
|
||||||
|
dutyPct = self._get_duty_cycle( self.curPitch, usec )
|
||||||
|
|
||||||
|
|
||||||
|
return self.curPitch, usec, dutyPct
|
||||||
|
|
||||||
|
def _note_on( self, ms ):
|
||||||
|
|
||||||
|
pitch,usec,dutyPct = self._get_next_note_params()
|
||||||
|
|
||||||
|
if not usec:
|
||||||
|
return "off"
|
||||||
|
else:
|
||||||
|
print(self.curPitch,self.curVelocity,usec,dutyPct)
|
||||||
|
self.curBegNoteMs = self.audio.buffer_sample_ms().value
|
||||||
|
self.api.set_pwm_duty( pitch, dutyPct )
|
||||||
|
self.api.note_on_us( pitch, usec )
|
||||||
|
self.curEndMs = ms + self.durMs
|
||||||
|
return "playing"
|
||||||
|
|
||||||
|
def _note_off( self, ms ):
|
||||||
|
|
||||||
|
self.curEndNoteMs = self.audio.buffer_sample_ms().value
|
||||||
|
self.rtAnalyzer.analyze_note( self.audio, self.curPitch, self.curBegNoteMs, self.curEndNoteMs, self.cfg.analysisArgs['rmsAnalysisArgs'] )
|
||||||
|
self.api.note_off( self.curPitch )
|
||||||
|
return "note_on"
|
||||||
|
|
||||||
|
|
||||||
|
def _all_notes_off( self ):
|
||||||
|
if self.curPitch == 109:
|
||||||
|
self.state = 'off'
|
||||||
|
print('done')
|
||||||
|
else:
|
||||||
|
self.api.note_off( self.curPitch )
|
||||||
|
self.curPitch += 1
|
2
elbow.py
2
elbow.py
@ -29,7 +29,7 @@ def fit_points_to_reference( usL, dbL, usRefL, dbRefL ):
|
|||||||
|
|
||||||
return dbV
|
return dbV
|
||||||
|
|
||||||
def find_elbow( usL, dbL, pointsPerLine=10 ):
|
def find_elbow( usL, dbL, pointsPerLine=5 ):
|
||||||
|
|
||||||
ppl_2 = int(pointsPerLine/2)
|
ppl_2 = int(pointsPerLine/2)
|
||||||
dL = []
|
dL = []
|
||||||
|
165
p_ac.py
165
p_ac.py
@ -19,6 +19,10 @@ from keyboard import Keyboard
|
|||||||
from calibrate import Calibrate
|
from calibrate import Calibrate
|
||||||
from rms_analysis import rms_analyze_one_rt_note_wrap
|
from rms_analysis import rms_analyze_one_rt_note_wrap
|
||||||
from MidiFilePlayer import MidiFilePlayer
|
from MidiFilePlayer import MidiFilePlayer
|
||||||
|
from VelTablePlayer import VelTablePlayer
|
||||||
|
from NoteTester import NoteTester
|
||||||
|
from PolyNoteTester import PolyNoteTester
|
||||||
|
from ChordTester import ChordTester
|
||||||
|
|
||||||
class AttackPulseSeq:
|
class AttackPulseSeq:
|
||||||
""" Sequence a fixed pitch over a list of attack pulse lengths."""
|
""" Sequence a fixed pitch over a list of attack pulse lengths."""
|
||||||
@ -33,7 +37,7 @@ class AttackPulseSeq:
|
|||||||
self.noteDurMs = noteDurMs # duration of each chord in milliseconds
|
self.noteDurMs = noteDurMs # duration of each chord in milliseconds
|
||||||
self.pauseDurMs = pauseDurMs # duration between end of previous note and start of next
|
self.pauseDurMs = pauseDurMs # duration between end of previous note and start of next
|
||||||
self.holdDutyPctL= None # hold voltage duty cycle table [ (minPulseSeqUsec,dutyCyclePct) ]
|
self.holdDutyPctL= None # hold voltage duty cycle table [ (minPulseSeqUsec,dutyCyclePct) ]
|
||||||
self.holdDutyPctD= None # { us:dutyPct } for each us in self.pulseUsL
|
self.holdDutyPctD= None # { us:dutyPct } for each us in self.pulseUsL
|
||||||
self.silentNoteN = None
|
self.silentNoteN = None
|
||||||
self.pulse_idx = 0 # Index of next pulse
|
self.pulse_idx = 0 # Index of next pulse
|
||||||
self.state = None # 'note_on','note_off'
|
self.state = None # 'note_on','note_off'
|
||||||
@ -45,25 +49,28 @@ class AttackPulseSeq:
|
|||||||
self.rtAnalyzer = RT_Analyzer()
|
self.rtAnalyzer = RT_Analyzer()
|
||||||
|
|
||||||
def start( self, ms, outDir, pitch, pulseUsL, holdDutyPctL, holdDutyPctD, playOnlyFl=False ):
|
def start( self, ms, outDir, pitch, pulseUsL, holdDutyPctL, holdDutyPctD, playOnlyFl=False ):
|
||||||
self.outDir = outDir # directory to write audio file and results
|
self.outDir = outDir # directory to write audio file and results
|
||||||
self.pitch = pitch # note to play
|
self.pitch = pitch # note to play
|
||||||
self.pulseUsL = pulseUsL # one onset pulse length in microseconds per sequence element
|
self.pulseUsL = pulseUsL # one onset pulse length in microseconds per sequence element
|
||||||
self.holdDutyPctL = holdDutyPctL
|
self.holdDutyPctL = holdDutyPctL
|
||||||
self.holdDutyPctD = holdDutyPctD
|
self.holdDutyPctD = holdDutyPctD
|
||||||
self.silentNoteN = 0
|
self.silentNoteN = 0
|
||||||
self.pulse_idx = 0
|
self.pulse_idx = 0
|
||||||
self.state = 'note_on'
|
self.state = 'note_on'
|
||||||
self.prevHoldDutyPct = None
|
self.prevHoldDutyPct = None
|
||||||
self.next_ms = ms + 500 # wait for 500ms to play the first note (this will guarantee that there is some empty space in the audio file before the first note)
|
self.next_ms = ms + 500 # wait for 500ms to play the first note (this will guarantee that there is some empty space in the audio file before the first note)
|
||||||
self.eventTimeL = [[0,0] for _ in range(len(pulseUsL))] # initialize the event time
|
self.eventTimeL = [[0,0] for _ in range(len(pulseUsL))] # initialize the event time
|
||||||
self.beginMs = ms
|
self.beginMs = ms
|
||||||
self.playOnlyFl = playOnlyFl
|
self.playOnlyFl = playOnlyFl
|
||||||
|
|
||||||
# kpl if not playOnlyFl:
|
# kpl if not playOnlyFl:
|
||||||
self.audio.record_enable(True) # start recording audio
|
self.audio.record_enable(True) # start recording audio
|
||||||
|
|
||||||
print("Hold Delay from end of attack:",cfg.defaultHoldDelayUsecs)
|
#print("Hold Delay from end of attack:",cfg.defaultHoldDelayUsecs)
|
||||||
self.api.set_hold_delay(pitch,cfg.defaultHoldDelayUsecs)
|
# self.api.set_hold_delay(pitch,cfg.defaultHoldDelayUsecs)
|
||||||
|
|
||||||
|
self.api.set_hold_duty(pitch,35)
|
||||||
|
print("Hold Duty Cycle=35.")
|
||||||
|
|
||||||
self.tick(ms) # play the first note
|
self.tick(ms) # play the first note
|
||||||
|
|
||||||
@ -128,14 +135,35 @@ class AttackPulseSeq:
|
|||||||
|
|
||||||
def _set_duty_cycle( self, pitch, pulseUsec ):
|
def _set_duty_cycle( self, pitch, pulseUsec ):
|
||||||
|
|
||||||
|
if False:
|
||||||
|
dutyPct = self._get_duty_cycle( pulseUsec )
|
||||||
|
|
||||||
dutyPct = self._get_duty_cycle( pulseUsec )
|
if dutyPct != self.prevHoldDutyPct:
|
||||||
|
# self.api.set_pwm_duty( pitch, dutyPct )
|
||||||
|
# print("Hold Duty:",dutyPct)
|
||||||
|
pass
|
||||||
|
|
||||||
if dutyPct != self.prevHoldDutyPct:
|
self.prevHoldDutyPct = dutyPct
|
||||||
self.api.set_pwm_duty( pitch, dutyPct )
|
|
||||||
print("Hold Duty:",dutyPct)
|
if False:
|
||||||
|
maxLevel = 64 # 225 # 64
|
||||||
|
minLevel = 24 # 89 # 24
|
||||||
|
maxUsec = 10000
|
||||||
|
minUsec = 2500
|
||||||
|
decayLevel = maxLevel
|
||||||
|
|
||||||
|
if pulseUsec < maxUsec and pulseUsec >= minUsec:
|
||||||
|
decayLevel = minLevel + ((pulseUsec-minUsec)/(maxUsec-minUsec)) * (maxLevel-minLevel)
|
||||||
|
else:
|
||||||
|
if pulseUsec < minUsec:
|
||||||
|
decayLevel = minLevel
|
||||||
|
|
||||||
|
decayLevel = int(decayLevel)
|
||||||
|
|
||||||
|
decayLevel = self.api.calc_decay_level( pulseUsec )
|
||||||
|
self.api.set_decay_level( pitch, decayLevel )
|
||||||
|
print("Decay Level:", decayLevel)
|
||||||
|
|
||||||
self.prevHoldDutyPct = dutyPct
|
|
||||||
|
|
||||||
def _note_on( self, ms ):
|
def _note_on( self, ms ):
|
||||||
|
|
||||||
@ -144,9 +172,13 @@ class AttackPulseSeq:
|
|||||||
self.state = 'note_off'
|
self.state = 'note_off'
|
||||||
|
|
||||||
pulse_usec = int(self.pulseUsL[ self.pulse_idx ])
|
pulse_usec = int(self.pulseUsL[ self.pulse_idx ])
|
||||||
self._set_duty_cycle( self.pitch, pulse_usec )
|
|
||||||
|
# decay_level = self.api.calc_decay_level( pulse_usec )
|
||||||
|
|
||||||
|
#self._set_duty_cycle( self.pitch, pulse_usec )
|
||||||
|
|
||||||
self.api.note_on_us( self.pitch, pulse_usec )
|
self.api.note_on_us( self.pitch, pulse_usec )
|
||||||
print("note-on:",self.pitch, self.pulse_idx, pulse_usec)
|
print("note-on:",self.pitch, self.pulse_idx, pulse_usec, "dcy:", decay_level)
|
||||||
|
|
||||||
def _note_off( self, ms ):
|
def _note_off( self, ms ):
|
||||||
self.eventTimeL[ self.pulse_idx ][1] = self.audio.buffer_sample_ms().value
|
self.eventTimeL[ self.pulse_idx ][1] = self.audio.buffer_sample_ms().value
|
||||||
@ -209,7 +241,7 @@ class CalibrateKeys:
|
|||||||
self.pulseUsL = pulseUsL
|
self.pulseUsL = pulseUsL
|
||||||
self.pitchL = pitchL
|
self.pitchL = pitchL
|
||||||
self.pitch_idx = -1
|
self.pitch_idx = -1
|
||||||
self._start_next_note( ms, playOnlyFl )
|
self._start_next_seq( ms, playOnlyFl )
|
||||||
|
|
||||||
|
|
||||||
def stop( self, ms ):
|
def stop( self, ms ):
|
||||||
@ -225,11 +257,11 @@ class CalibrateKeys:
|
|||||||
|
|
||||||
# if the sequencer is done playing
|
# if the sequencer is done playing
|
||||||
if not self.seq.is_enabled():
|
if not self.seq.is_enabled():
|
||||||
self._start_next_note( ms, self.seq.playOnlyFl ) # ... else start the next sequence
|
self._start_next_seq( ms, self.seq.playOnlyFl ) # ... else start the next sequence
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _start_next_note( self, ms, playOnlyFl ):
|
def _start_next_seq( self, ms, playOnlyFl ):
|
||||||
|
|
||||||
self.pitch_idx += 1
|
self.pitch_idx += 1
|
||||||
|
|
||||||
@ -253,8 +285,6 @@ class CalibrateKeys:
|
|||||||
# get the next available output directory id
|
# get the next available output directory id
|
||||||
outDir_id = self._calc_next_out_dir_id( outDir )
|
outDir_id = self._calc_next_out_dir_id( outDir )
|
||||||
|
|
||||||
print(outDir_id,outDir)
|
|
||||||
|
|
||||||
# if this is not the first time this note has been sampled then get the resample locations
|
# if this is not the first time this note has been sampled then get the resample locations
|
||||||
if (outDir_id == 0) or self.cfg.useFullPulseListFl:
|
if (outDir_id == 0) or self.cfg.useFullPulseListFl:
|
||||||
self.pulseUsL = self.cfg.full_pulseL
|
self.pulseUsL = self.cfg.full_pulseL
|
||||||
@ -265,9 +295,10 @@ class CalibrateKeys:
|
|||||||
|
|
||||||
holdDutyPctL = self.cfg.calibrateArgs['holdDutyPctD'][pitch]
|
holdDutyPctL = self.cfg.calibrateArgs['holdDutyPctD'][pitch]
|
||||||
|
|
||||||
|
# if playback of the current calibration was requested
|
||||||
if playOnlyFl:
|
if playOnlyFl:
|
||||||
|
|
||||||
|
# form the calibrated pulse list
|
||||||
self.pulseUsL,_,holdDutyPctL = form_final_pulse_list( baseDir, pitch, self.cfg.analysisArgs, take_id=None )
|
self.pulseUsL,_,holdDutyPctL = form_final_pulse_list( baseDir, pitch, self.cfg.analysisArgs, take_id=None )
|
||||||
|
|
||||||
noteN = cfg.analysisArgs['auditionNoteN']
|
noteN = cfg.analysisArgs['auditionNoteN']
|
||||||
@ -318,6 +349,10 @@ class App:
|
|||||||
self.keyboard = None
|
self.keyboard = None
|
||||||
self.calibrate = None
|
self.calibrate = None
|
||||||
self.midiFilePlayer = None
|
self.midiFilePlayer = None
|
||||||
|
self.velTablePlayer = None
|
||||||
|
self.noteTester = None
|
||||||
|
self.polyNoteTester = None
|
||||||
|
self.chordTester = None
|
||||||
|
|
||||||
def setup( self, cfg ):
|
def setup( self, cfg ):
|
||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
@ -369,6 +404,15 @@ class App:
|
|||||||
|
|
||||||
self.midiFilePlayer = MidiFilePlayer( cfg, self.api, self.midiDev, cfg.midiFileFn )
|
self.midiFilePlayer = MidiFilePlayer( cfg, self.api, self.midiDev, cfg.midiFileFn )
|
||||||
|
|
||||||
|
self.velTablePlayer = VelTablePlayer( cfg, self.api, self.audioDev, self.cfg.calibrateArgs['holdDutyPctD'], "velMapD.json")
|
||||||
|
|
||||||
|
self.noteTester = NoteTester(cfg,self.api)
|
||||||
|
|
||||||
|
self.polyNoteTester = PolyNoteTester(cfg,self.api)
|
||||||
|
|
||||||
|
self.chordTester = ChordTester(cfg,self.api)
|
||||||
|
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def tick( self, ms ):
|
def tick( self, ms ):
|
||||||
@ -388,13 +432,30 @@ class App:
|
|||||||
if self.midiFilePlayer:
|
if self.midiFilePlayer:
|
||||||
self.midiFilePlayer.tick(ms)
|
self.midiFilePlayer.tick(ms)
|
||||||
|
|
||||||
|
if self.midiDev:
|
||||||
|
msgL = self.midiDev.get_input()
|
||||||
|
for msg in msgL:
|
||||||
|
print(msg['value']);
|
||||||
|
|
||||||
|
if self.velTablePlayer:
|
||||||
|
self.velTablePlayer.tick(ms)
|
||||||
|
|
||||||
|
if self.noteTester:
|
||||||
|
self.noteTester.tick(ms)
|
||||||
|
|
||||||
|
if self.polyNoteTester:
|
||||||
|
self.polyNoteTester.tick(ms)
|
||||||
|
|
||||||
|
if self.chordTester:
|
||||||
|
self.chordTester.tick(ms)
|
||||||
|
|
||||||
def audio_dev_list( self, ms ):
|
def audio_dev_list( self, ms ):
|
||||||
|
|
||||||
if self.audioDev is not None:
|
if self.audioDev is not None:
|
||||||
portL = self.audioDev.get_port_list( True )
|
portL = self.audioDev.get_port_list( True )
|
||||||
|
|
||||||
for port in portL:
|
for port in portL:
|
||||||
print("chs:%4i label:%s" % (port['chN'],port['label']))
|
print("chs:%4i label:'%s'" % (port['chN'],port['label']))
|
||||||
|
|
||||||
def midi_dev_list( self, ms ):
|
def midi_dev_list( self, ms ):
|
||||||
d = self.midiDev.get_port_list( True )
|
d = self.midiDev.get_port_list( True )
|
||||||
@ -447,6 +508,33 @@ class App:
|
|||||||
def midi_file_player_stop( self, ms ):
|
def midi_file_player_stop( self, ms ):
|
||||||
self.midiFilePlayer.stop(ms)
|
self.midiFilePlayer.stop(ms)
|
||||||
|
|
||||||
|
def vel_table_updown( self, ms, argL):
|
||||||
|
self.velTablePlayer.start(argL[0],argL[1],"updown")
|
||||||
|
|
||||||
|
def vel_table_across( self, ms, argL ):
|
||||||
|
self.velTablePlayer.start(argL[0],argL[1],"across")
|
||||||
|
|
||||||
|
def vel_table_stop( self, ms ):
|
||||||
|
self.velTablePlayer.stop()
|
||||||
|
|
||||||
|
def note_tester_start( self, ms ):
|
||||||
|
self.noteTester.start();
|
||||||
|
|
||||||
|
def note_tester_stop( self, ms ):
|
||||||
|
self.noteTester.stop();
|
||||||
|
|
||||||
|
def poly_note_tester_start( self, ms ):
|
||||||
|
self.polyNoteTester.start();
|
||||||
|
|
||||||
|
def poly_note_tester_stop( self, ms ):
|
||||||
|
self.polyNoteTester.stop();
|
||||||
|
|
||||||
|
def chord_tester_start( self, ms ):
|
||||||
|
self.chordTester.start()
|
||||||
|
|
||||||
|
def chord_tester_stop( self, ms ):
|
||||||
|
self.chordTester.stop()
|
||||||
|
|
||||||
def pedal_down( self, ms ):
|
def pedal_down( self, ms ):
|
||||||
print("pedal_down")
|
print("pedal_down")
|
||||||
self.midiDev.send_controller(64, 100 )
|
self.midiDev.send_controller(64, 100 )
|
||||||
@ -455,6 +543,12 @@ class App:
|
|||||||
print("pedal_up");
|
print("pedal_up");
|
||||||
self.midiDev.send_controller(64, 0 )
|
self.midiDev.send_controller(64, 0 )
|
||||||
|
|
||||||
|
def all_notes_off(self, ms):
|
||||||
|
self.api.all_notes_off();
|
||||||
|
|
||||||
|
def check_for_errors(self,ms):
|
||||||
|
self.api.check_for_serial_errors()
|
||||||
|
|
||||||
def quit( self, ms ):
|
def quit( self, ms ):
|
||||||
if self.api:
|
if self.api:
|
||||||
self.api.close()
|
self.api.close()
|
||||||
@ -587,8 +681,19 @@ class Shell:
|
|||||||
'R':{ "func":"keyboard_repeat_target_db", "minN":1, "maxN":1, "help":"Repeat db across keyboard with new pulse_idx"},
|
'R':{ "func":"keyboard_repeat_target_db", "minN":1, "maxN":1, "help":"Repeat db across keyboard with new pulse_idx"},
|
||||||
'F':{ "func":"midi_file_player_start", "minN":0, "maxN":0, "help":"Play the MIDI file."},
|
'F':{ "func":"midi_file_player_start", "minN":0, "maxN":0, "help":"Play the MIDI file."},
|
||||||
'f':{ "func":"midi_file_player_stop", "minN":0, "maxN":0, "help":"Stop the MIDI file."},
|
'f':{ "func":"midi_file_player_stop", "minN":0, "maxN":0, "help":"Stop the MIDI file."},
|
||||||
|
'V':{ "func":"vel_table_updown", "minN":2, "maxN":2, "help":"Play Velocity Table up/down - across."},
|
||||||
|
'A':{ "func":"vel_table_across", "minN":2, "maxN":2, "help":"Play Velocity Table across - up/down."},
|
||||||
|
'v':{ "func":"vel_table_stop", "minN":0, "maxN":0, "help":"Stop the velocity table playback."},
|
||||||
|
'N':{ "func":"note_tester_start", "minN":0, "maxN":0, "help":"Play a note using NoteTester."},
|
||||||
|
'n':{ "func":"note_tester_stop", "minN":0, "maxN":0, "help":"Stop NoteTester."},
|
||||||
|
'T':{ "func":"poly_note_tester_start", "minN":0, "maxN":0, "help":"Play random notes using PolyNoteTester."},
|
||||||
|
't':{ "func":"poly_note_tester_stop", "minN":0, "maxN":0, "help":"Stop NoteTester."},
|
||||||
|
'H':{ "func":"chord_tester_start", "minN":0, "maxN":0, "help":"Chord tester start."},
|
||||||
|
'h':{ "func":"chord_tester_stop", "minN":0, "maxN":0, "help":"Chord tester stop."},
|
||||||
'P':{ "func":"pedal_down", "minN":0, "maxN":0, "help":"Pedal down."},
|
'P':{ "func":"pedal_down", "minN":0, "maxN":0, "help":"Pedal down."},
|
||||||
'U':{ "func":"pedal_up", "minN":0, "maxN":0, "help":"Pedal up."},
|
'p':{ "func":"pedal_up", "minN":0, "maxN":0, "help":"Pedal up."},
|
||||||
|
'O':{ "func":"all_notes_off", "minN":0, "maxN":0, "help":"All notes off."},
|
||||||
|
'E':{ "func":"check_for_errors", "minN":0, "maxN":0, "help":"Check for errors."}
|
||||||
}
|
}
|
||||||
|
|
||||||
def _help( self, _=None ):
|
def _help( self, _=None ):
|
||||||
|
355
p_ac.yml
355
p_ac.yml
@ -5,6 +5,7 @@
|
|||||||
# Audio device setup
|
# Audio device setup
|
||||||
audio: {
|
audio: {
|
||||||
inPortLabel: "8 USB Audio CODEC:", #"HDA Intel PCH: CS4208", # "5 USB Audio CODEC:", #"5 USB Sound Device",
|
inPortLabel: "8 USB Audio CODEC:", #"HDA Intel PCH: CS4208", # "5 USB Audio CODEC:", #"5 USB Sound Device",
|
||||||
|
#inPortLabel: "8 Scarlett 18i20 USB: Audio",
|
||||||
outPortLabel: ,
|
outPortLabel: ,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -12,12 +13,62 @@
|
|||||||
inMonitorFl: False,
|
inMonitorFl: False,
|
||||||
outMonitorFl: False,
|
outMonitorFl: False,
|
||||||
throughFl: False,
|
throughFl: False,
|
||||||
inPortLabel: "Fastlane:Fastlane MIDI A",
|
#inPortLabel: "MIDI9/QRS PNOScan:MIDI9/QRS PNOScan MIDI 1",
|
||||||
outPortLabel: "Fastlane:Fastlane MIDI A"
|
#outPortLabel: "MIDI9/QRS PNOScan:MIDI9/QRS PNOScan MIDI 1"
|
||||||
|
#inPortLabel: "Fastlane:Fastlane MIDI A",
|
||||||
|
#outPortLabel: "Fastlane:Fastlane MIDI A",
|
||||||
#inPortLabel: "picadae:picadae MIDI 1",
|
#inPortLabel: "picadae:picadae MIDI 1",
|
||||||
#outPortLabel: "picadae:picadae MIDI 1"
|
#outPortLabel: "picadae:picadae MIDI 1"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NoteTester:
|
||||||
|
{
|
||||||
|
noteCount: 200,
|
||||||
|
minNoteDurMs: 100,
|
||||||
|
maxNoteDurMs: 1000,
|
||||||
|
minPauseDurMs: 5,
|
||||||
|
maxPauseDurMs: 500,
|
||||||
|
pitch: 60,
|
||||||
|
minAttackUsec: 4000,
|
||||||
|
maxAttackUsec: 20000,
|
||||||
|
filename: "note_tester.json"
|
||||||
|
},
|
||||||
|
|
||||||
|
PolyNoteTester:
|
||||||
|
{
|
||||||
|
mode: "simple",
|
||||||
|
noteCount: 11,
|
||||||
|
minPitch: 21,
|
||||||
|
maxPitch: 31,
|
||||||
|
skipPitchL: [22,68,102],
|
||||||
|
minNoteDurMs: 1000,
|
||||||
|
maxNoteDurMs: 2000,
|
||||||
|
minInterOnsetMs: 100,
|
||||||
|
maxInterOnsetMs: 1000,
|
||||||
|
minAttackUsec: 4000,
|
||||||
|
maxAttackUsec: 20000,
|
||||||
|
holdDutyPct: 35,
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
ChordTester:
|
||||||
|
{
|
||||||
|
useVelTableFl: False,
|
||||||
|
#pitchL: [24,36,48,60,72,84,96],
|
||||||
|
#pitchL: [24,96,48,72,36,84,60],
|
||||||
|
#pitchL: [ 36,40,43,47, 48, 52, 55, 59],
|
||||||
|
#pitchL: [ 36,39,41,33 ],
|
||||||
|
pitchL: [ 21,23,24,25,26,27,28,29,30,31],
|
||||||
|
#pitchL: [ 36,33,35,34,37,40,43,42,38,39,41],
|
||||||
|
#pitchL: [ 43,44,45,46,47,48,49,50,51,52,53],
|
||||||
|
#pitchL: [ 54,55,56,57,58,59,60,61,62,63,64 ],
|
||||||
|
repeatCnt: 3,
|
||||||
|
atkUsec: 10000,
|
||||||
|
durMs: 1000,
|
||||||
|
pauseMs: 1000,
|
||||||
|
holdDuty: 35,
|
||||||
|
},
|
||||||
|
|
||||||
# Picadae API args
|
# Picadae API args
|
||||||
serial_dev: "/dev/ttyACM0",
|
serial_dev: "/dev/ttyACM0",
|
||||||
serial_baud: 38400,
|
serial_baud: 38400,
|
||||||
@ -28,11 +79,11 @@
|
|||||||
|
|
||||||
|
|
||||||
# MeasureSeq args
|
# MeasureSeq args
|
||||||
outDir: "~/temp/p_ac_3_of",
|
outDir: "~/temp/p_ac_3_ok",
|
||||||
noteDurMs: 500,
|
noteDurMs: 500,
|
||||||
pauseDurMs: 500,
|
pauseDurMs: 500,
|
||||||
reversePulseListFl: True,
|
reversePulseListFl: True,
|
||||||
useFullPulseListFl: True,
|
useFullPulseListFl: True, # don't select a new set of resample points based on the previous samples from this pitch
|
||||||
maxSilentNoteCount: 4,
|
maxSilentNoteCount: 4,
|
||||||
silentNoteMaxPulseUs: 15000,
|
silentNoteMaxPulseUs: 15000,
|
||||||
silentNoteMinDurMs: 180, #250,
|
silentNoteMinDurMs: 180, #250,
|
||||||
@ -40,7 +91,7 @@
|
|||||||
defaultHoldDelayUsecs: 1000,
|
defaultHoldDelayUsecs: 1000,
|
||||||
|
|
||||||
# Midi file player
|
# Midi file player
|
||||||
midiFileFn: "/home/kevin/media/audio/midi/txt/round4.txt",
|
midiFileFn: "/home/kevin/media/audio/midi/txt/988-v25.txt",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -94,7 +145,26 @@
|
|||||||
full_pulse22L: [ 3500, 3750, 4000, 4250, 4500, 4750, 5000, 5250, 5500, 5750, 6000, 6250, 6500, 6750, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000 ],
|
full_pulse22L: [ 3500, 3750, 4000, 4250, 4500, 4750, 5000, 5250, 5500, 5750, 6000, 6250, 6500, 6750, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000 ],
|
||||||
|
|
||||||
# 60,72,84
|
# 60,72,84
|
||||||
full_pulseL: [ 2000, 2250, 2500,2750, 3000, 3250, 3500, 3750, 4000, 4250, 4500, 4750, 5000, 5250, 5500, 5750, 6000, 6250, 6500, 6750, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000, 22000 ],
|
full_pulse23L: [ 2000, 2250, 2500,2750, 3000, 3250, 3500, 3750, 4000, 4250, 4500, 4750, 5000, 5250, 5500, 5750, 6000, 6250, 6500, 6750, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000, 22000 ],
|
||||||
|
|
||||||
|
full_pulseL24: [ 5000, 5125, 5250, 5375, 5500, 5625, 5750, 5875, 6000, 6125, 6250, 6500, 6750, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000, 22000 ],
|
||||||
|
|
||||||
|
# 23-40
|
||||||
|
full_pulseL25: [ 3500, 3625, 3750, 3875, 4000, 4125, 4250, 4375, 4500, 4625, 4750, 4875, 5000, 5125, 5250, 5375, 5500, 5625, 5750, 5875, 6000, 6125, 6250, 6375, 6500, 6625, 6750, 6875, 7000, 7250, 7500, 7750, 8000, 8250, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000 ],
|
||||||
|
|
||||||
|
full_pulse25aL: [ 2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350, 2400, 2450, 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750, 3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150, 4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550, 4600, 4650, 4700, 4750, 4800, 4850, 4900, 4950, 5000, 5050, 5100, 5150, 5200, 5250, 5300, 5350, 5400, 5450, 5500, 5550, 5600, 5650, 5700, 5750, 5800, 5850, 5900, 5950, 6000, 6125, 6250, 6375, 6500, 6625, 6750, 6875, 7000, 7250, 7500, 7750, 8000, 8250, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000 ],
|
||||||
|
|
||||||
|
# 21-
|
||||||
|
full_pulse26L: [ 1500, 1625, 1750, 1875, 2000, 2125, 2250, 2375, 2500, 2625, 2750, 2875, 3000, 3125, 3250, 3375,3500, 3625, 3750, 3875, 4000, 4125, 4250, 4375, 4500, 4625, 4750, 4875, 5000, 5125, 5250, 5375, 5500, 5625, 5750, 5875, 6000, 6125, 6250, 6375, 6500, 6625, 6750, 6875, 7000, 7250, 7500, 7750, 8000, 8250, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000, 22000 ],
|
||||||
|
|
||||||
|
full_pulseL: [ 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3625, 3750, 3875, 4000, 4125, 4250, 4375, 4500, 4625, 4750, 4875, 5000, 5125, 5250, 5375, 5500, 5625, 5750, 5875, 6000, 6125, 6250, 6375, 6500, 6625, 6750, 6875, 7000, 7250, 7500, 7750, 8000, 8250, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000, 22000 ],
|
||||||
|
|
||||||
|
# 92
|
||||||
|
full_pulse27L: [ 1500, 1625, 1750, 1875, 2000, 2125, 2250, 2375, 2500, 2625, 2750, 2875, 3000, 3125, 3250, 3375, 3500, 3625, 3750, 3875, 4000, 4125, 4250, 4375, 4500, 4625, 4750, 4875, 5000, 5125, 5250, 5375, 5500, 5625, 5750, 5875, 6000, 6125, 6250, 6375, 6500, 6625, 6750, 6875, 7000, 7250, 7500, 7750, 8000, 8250, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 14000, 15000, 16000, 17000, 18000, 19000 ],
|
||||||
|
|
||||||
|
full_pulse28L: [ 4000, 8000, 12000, 16000 ],
|
||||||
|
|
||||||
|
full_pulse29L: [ 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000, 10500, 11000, 11500, 12000, 12500, 13000, 13500, 14000, 14500, 15000, 15500, 16000, 16500, 17000, 17500, 18000, 18500, 19000, 19500, 20000 ],
|
||||||
|
|
||||||
# RMS analysis args
|
# RMS analysis args
|
||||||
analysisArgs: {
|
analysisArgs: {
|
||||||
@ -112,28 +182,113 @@
|
|||||||
resampleMinDurMs: 150, # notes's whose duration is less than this will be skipped
|
resampleMinDurMs: 150, # notes's whose duration is less than this will be skipped
|
||||||
|
|
||||||
useLastTakeOnlyFl: True,
|
useLastTakeOnlyFl: True,
|
||||||
minAttkDb: -5.0, # threshold of silence level
|
minAttkDb: -5.0, # threshold of silence level
|
||||||
maxDbOffset: 0.25, # travel down the from the max. note level by at most this amount to locate the max. peak
|
maxDbOffset: 0.25, # travel down the from the max. note level by at most this amount to locate the max. peak
|
||||||
maxDeltaDb: 1.5, # maximum db change between volume samples (changes greater than this will trigger resampling)
|
maxDeltaDb: 1.5, # maximum db change between volume samples (changes greater than this will trigger resampling)
|
||||||
samplesPerDb: 4, # count of samples per dB to resample ranges whose range is less than maxDeltaDb
|
samplesPerDb: 4, # count of samples per dB to resample ranges whose range is less than maxDeltaDb
|
||||||
minSampleDistUs: 50, # minimum distance between sample points in microseconds
|
minSampleDistUs: 50, # minimum distance between sample points in microseconds
|
||||||
auditionNoteN: 19, # count of notes to play for audition
|
auditionNoteN: 19, # count of notes to play for audition
|
||||||
|
|
||||||
finalPulseListCacheFn: "/home/kevin/temp/final_pulse_list_cache.pickle",
|
finalPulseListCacheFn: "/home/kevin/temp/final_pulse_list_cache.pickle",
|
||||||
rmsAnalysisCacheFn: "/home/kevin/temp/rms_analysis_cache.pickle"
|
rmsAnalysisCacheFn: "/home/kevin/temp/rms_analysis_cache.pickle"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# used by plot_seq_1.gen_vel_map()
|
||||||
|
velTableDbL: [ 2, 7, 10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29 ],
|
||||||
|
|
||||||
manualMinD: {
|
manualMinD: {
|
||||||
36: [2, 10],
|
21:[-1,6],
|
||||||
48: [2, 10],
|
23:[-1,1], # 10
|
||||||
60: [2, 10],
|
24:[-1,11], # 11
|
||||||
72: [2, 10],
|
25:[-1,8],
|
||||||
84: [2, 10]
|
26:[-1,9], # 13
|
||||||
},
|
27:[-1,11],
|
||||||
|
28:[-1,2],
|
||||||
|
29:[-1,16],
|
||||||
|
30:[-1,4],
|
||||||
|
31:[-1,8],
|
||||||
|
32:[-1,9],
|
||||||
|
33:[-1,10],
|
||||||
|
34:[-1,9], # 15
|
||||||
|
35:[-1,9],
|
||||||
|
36:[-1,4],
|
||||||
|
37:[-1,7],
|
||||||
|
38:[-1,5],
|
||||||
|
39:[-1,5],
|
||||||
|
40:[-1,6], # 2 lwr
|
||||||
|
41:[-1,10], # 24 lwr
|
||||||
|
42:[-1,2],
|
||||||
|
43:[-1,4],
|
||||||
|
44:[-1,5],
|
||||||
|
45:[-1,10],
|
||||||
|
46:[-1,4],
|
||||||
|
47:[-1,7],
|
||||||
|
48:[-1,9],
|
||||||
|
49:[-1,2],
|
||||||
|
50:[-1,5],
|
||||||
|
51:[-1,4],
|
||||||
|
52:[-1,8],
|
||||||
|
53:[-1,0], # 16
|
||||||
|
54:[-1,8],
|
||||||
|
55:[-1,14],
|
||||||
|
56:[-1,8],
|
||||||
|
57:[-1,9],
|
||||||
|
58:[-1,10],
|
||||||
|
59:[-1,7],
|
||||||
|
60:[-1,7], # 14
|
||||||
|
61:[-1,10], # 14
|
||||||
|
62:[-1,1], # 7
|
||||||
|
63:[-1,5],
|
||||||
|
64:[-1,2],
|
||||||
|
65:[-1,8],
|
||||||
|
66:[-1,3],
|
||||||
|
67:[-1,3], # 17 lwr
|
||||||
|
68:[-1,3],
|
||||||
|
69:[-1,9],
|
||||||
|
70:[-1,15], # 15 lwr
|
||||||
|
71:[-1,0], # 7 lwr
|
||||||
|
72:[-1,3],# 12 lwr
|
||||||
|
73:[-1,0],# 21 lwr
|
||||||
|
74:[-1,0],# 24 lwr
|
||||||
|
75:[-1,0],# 18 lwr
|
||||||
|
76:[-1,0],# 13 lwr
|
||||||
|
77:[-1,0],# 22 lwr
|
||||||
|
78:[-1,0],# 14 lwr
|
||||||
|
79:[-1,8],
|
||||||
|
80:[-1,3],
|
||||||
|
81:[-1,2], # 14 lwr
|
||||||
|
82:[-1,5], # 11
|
||||||
|
83:[-1,7],
|
||||||
|
84:[-1,3], # 13
|
||||||
|
85:[-1,5],
|
||||||
|
86:[-1,4],
|
||||||
|
87:[-1,7],
|
||||||
|
88:[-1,5], # 22
|
||||||
|
89:[-1,19],
|
||||||
|
90:[-1,2], # 10
|
||||||
|
91:[-1,10],
|
||||||
|
92:[-1,8],
|
||||||
|
93:[-1,7],
|
||||||
|
94:[-1,5], # 10
|
||||||
|
95:[-1,9],
|
||||||
|
96:[-1,13],
|
||||||
|
97:[-1,12],
|
||||||
|
98:[-1,14],
|
||||||
|
99:[-1,14],
|
||||||
|
100:[-1,18],
|
||||||
|
101:[-1,18],
|
||||||
|
103:[-1,25],
|
||||||
|
104:[-1,26],
|
||||||
|
105:[-1,18],
|
||||||
|
106:[-1,26],
|
||||||
|
107:[-1,29],
|
||||||
|
108:[-1,28],
|
||||||
|
},
|
||||||
|
|
||||||
manualAnchorPitchMinDbL: [ 36,48,72,84 ],
|
manualAnchorPitchMinDbL: [ 24, 36,48,60,72,84,96 ],
|
||||||
manualAnchorPitchMaxDbL: [ 36,48,60,72,84 ],
|
manualAnchorPitchMaxDbL: [ 24, 36,48,60,72,84,96 ],
|
||||||
|
|
||||||
|
manualLastFl: true,
|
||||||
|
|
||||||
manualMinD_0: {
|
manualMinD_0: {
|
||||||
23: [2, 24],
|
23: [2, 24],
|
||||||
@ -256,85 +411,93 @@
|
|||||||
dbSrcLabel: 'hm', # source of the db measurement 'td' (time-domain) or 'hm' (harmonic)
|
dbSrcLabel: 'hm', # source of the db measurement 'td' (time-domain) or 'hm' (harmonic)
|
||||||
|
|
||||||
holdDutyPctD: {
|
holdDutyPctD: {
|
||||||
23: [[0, 40]],
|
21: [[0, 50]],
|
||||||
24: [[0, 40]],
|
23: [[0, 50]],
|
||||||
25: [[0, 40]],
|
24: [[0, 50]],
|
||||||
26: [[0, 40]],
|
25: [[0, 50]],
|
||||||
27: [[0, 40]],
|
26: [[0, 50]],
|
||||||
28: [[0, 40]],
|
27: [[0, 50]],
|
||||||
29: [[0, 40]],
|
28: [[0, 50]],
|
||||||
30: [[0, 40]],
|
29: [[0, 50]],
|
||||||
31: [[0, 40]],
|
30: [[0, 50]],
|
||||||
32: [[0, 40]],
|
31: [[0, 50]],
|
||||||
33: [[0, 40]],
|
32: [[0, 50]],
|
||||||
34: [[0, 40]],
|
33: [[0, 50]],
|
||||||
35: [[0, 40]],
|
34: [[0, 50]],
|
||||||
36: [[0, 40]],
|
35: [[0, 50]],
|
||||||
37: [[0, 40]],
|
36: [[0, 50]],
|
||||||
38: [[0, 40]],
|
37: [[0, 50]],
|
||||||
39: [[0, 40]],
|
38: [[0, 50]],
|
||||||
40: [[0, 40]],
|
39: [[0, 50]],
|
||||||
41: [[0, 40]],
|
40: [[0, 50]],
|
||||||
42: [[0, 40]],
|
41: [[0, 45]],
|
||||||
43: [[0, 40]],
|
42: [[0, 45]],
|
||||||
44: [[0, 40]],
|
43: [[0, 45]],
|
||||||
45: [[0, 40]],
|
44: [[0, 45]],
|
||||||
46: [[0, 40]],
|
45: [[0, 45]],
|
||||||
47: [[0, 40]],
|
46: [[0, 40],[10000,45]],
|
||||||
48: [[0, 40]],
|
47: [[0, 40],[10000,45]],
|
||||||
49: [[0, 40]],
|
48: [[0, 40],[10000,45]],
|
||||||
50: [[0, 40]],
|
49: [[0, 40],[10000,45]],
|
||||||
51: [[0, 40]],
|
50: [[0, 40],[10000,45]],
|
||||||
52: [[0, 40]],
|
51: [[0, 40],[10000,45]],
|
||||||
53: [[0, 40]],
|
52: [[0, 40],[10000,45]],
|
||||||
54: [[0, 40]],
|
53: [[0, 40],[10000,45]],
|
||||||
55: [[0, 40]],
|
54: [[0, 40],[10000,45]],
|
||||||
56: [[0, 40]],
|
55: [[0, 40],[10000,45]],
|
||||||
57: [[0, 40]],
|
56: [[0, 40],[10000,45]],
|
||||||
58: [[0, 40]],
|
57: [[0, 40],[10000,45]],
|
||||||
59: [[0, 45]],
|
58: [[0, 40],[10000,45]],
|
||||||
60: [[0, 40],[10000,50]],
|
59: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
61: [[0, 40],[10000,50]],
|
60: [[0, 40],[10000,43],[11000,45],[12000,45], [13000,50],[14000,55],[15000,60],[16000,65]],
|
||||||
62: [[0, 40],[10000,50]],
|
61: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
63: [[0, 40],[10000,50]],
|
62: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
64: [[0, 40],[10000,50]],
|
63: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
65: [[0, 99]],
|
64: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
66: [[0, 40]],
|
65: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
67: [[0, 40],[14000, 45],[15000,50],[16000,55],[17000,60],[18000,65],[19000,55]],
|
66: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
68: [[0, 40],[14000, 45],[15000,50],[16000,55],[17000,60],[18000,65],[19000,55]],
|
67: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
69: [[0, 40],[14000, 45],[15000,50],[16000,55],[17000,60],[18000,65],[19000,55]],
|
68: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
70: [[0, 40],[14000, 45],[15000,50],[16000,55],[17000,60],[18000,65],[19000,55]],
|
69: [[0, 32],[5000,64] ],
|
||||||
71: [[0, 40],[14000, 45],[15000,50],[16000,55],[17000,60],[18000,65],[19000,55]],
|
70: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
72: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
71: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
73: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
72: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
74: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
73: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
75: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
74: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
76: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
75: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
77: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
76: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
78: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
77: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55],[15000,60]],
|
||||||
79: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
78: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
80: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
79: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
81: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
80: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
82: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
81: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
83: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
82: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
84: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
83: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
85: [[0, 42],[8000,44],[9000,46],[10000, 48],[11000,50],[12000,52],[13000,54],[14000,56],[15000,58],[16000,60],[17000,60],[18000,60],[19000,60],[20000,60] ],
|
84: [[0, 35],[8000,40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
86: [[0, 40]],
|
85: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
87: [[0, 40]],
|
86: [[0, 40],[10000,45],[12000,48],[13000,50],[14000,55]],
|
||||||
88: [[0, 40]],
|
87: [[0, 40],[10000,45],[12000,48],[13000,50]],
|
||||||
89: [[0, 40]],
|
88: [[0, 40],[10000,45],[12000,48],[13000,50]],
|
||||||
91: [[0, 40]],
|
89: [[0, 40],[10000,45],[12000,48],[13000,50]],
|
||||||
92: [[0, 40]],
|
90: [[0, 40],[10000,45],[12000,48],[13000,50]],
|
||||||
93: [[0, 40]],
|
91: [[0, 40],[10000,45],[12000,48],[13000,50]],
|
||||||
94: [[0, 40]],
|
92: [[0, 37]],
|
||||||
95: [[0, 40]],
|
93: [[0, 37]],
|
||||||
96: [[0, 40]],
|
94: [[0, 37]],
|
||||||
|
95: [[0, 37]],
|
||||||
|
96: [[0, 37]],
|
||||||
97: [[0, 40]],
|
97: [[0, 40]],
|
||||||
98: [[0, 40]],
|
98: [[0, 40]],
|
||||||
99: [[0, 40]],
|
99: [[0, 37]],
|
||||||
100: [[0, 40]],
|
100: [[0, 37]],
|
||||||
101: [[0, 40]],
|
101: [[0, 37]],
|
||||||
106: [[0, 40]]
|
102: [[0, 37]],
|
||||||
|
103: [[0, 40],[10000,45],[15000,50]],
|
||||||
|
104: [[0, 40],[7500,45],[15000,50]],
|
||||||
|
105: [[0, 40],[10000,45],[15000,50]],
|
||||||
|
106: [[0, 37]],
|
||||||
|
107: [[0, 37]],
|
||||||
|
108: [[0, 37]],
|
||||||
},
|
},
|
||||||
|
|
||||||
# Final for Matt's piano
|
# Final for Matt's piano
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.7.5"
|
"version": "3.8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.7.5"
|
"version": "3.8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
180
plot_seq_1.py
180
plot_seq_1.py
@ -1,6 +1,6 @@
|
|||||||
##| Copyright: (C) 2019-2020 Kevin Larke <contact AT larke DOT org>
|
##| Copyright: (C) 2019-2020 Kevin Larke <contact AT larke DOT org>
|
||||||
##| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
|
##| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
|
||||||
import os, sys,json
|
import os, sys,json,math
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from common import parse_yaml_cfg
|
from common import parse_yaml_cfg
|
||||||
@ -458,11 +458,21 @@ def _plot_us_db_takes( inDir, cfg, pitchL, takeIdL, printDir="", printFn="" ):
|
|||||||
|
|
||||||
usL, dbL, durMsL, _, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, analysisArgsD['rmsAnalysisArgs'], takeId=takeId )
|
usL, dbL, durMsL, _, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, analysisArgsD['rmsAnalysisArgs'], takeId=takeId )
|
||||||
|
|
||||||
|
|
||||||
ax.plot(usL,dbL, marker='.',label="%i:%i %s %s" % (midi_pitch,takeId,keyMapD[midi_pitch]['class'],keyMapD[midi_pitch]['type']))
|
ax.plot(usL,dbL, marker='.',label="%i:%i %s %s" % (midi_pitch,takeId,keyMapD[midi_pitch]['class'],keyMapD[midi_pitch]['type']))
|
||||||
|
|
||||||
# for i,(x,y) in enumerate(zip(usL,dbL)):
|
for i,(x,y) in enumerate(zip(usL,dbL)):
|
||||||
# ax.text(x,y,str(i))
|
ax.text(x,y,str(i))
|
||||||
|
|
||||||
|
f_usL,f_dbL = filter_us_db(usL,dbL)
|
||||||
|
|
||||||
|
ax.plot(f_usL,f_dbL, marker='.')
|
||||||
|
|
||||||
|
|
||||||
|
elbow_us,elbow_db = elbow.find_elbow(usL,dbL)
|
||||||
|
ax.plot([elbow_us],[elbow_db],marker='*',markersize=12,color='red',linestyle='None')
|
||||||
|
|
||||||
|
elb_idx = nearest_sample_point( dbL, usL, elbow_db, elbow_us )
|
||||||
|
|
||||||
if printDir:
|
if printDir:
|
||||||
plt.savefig(os.path.join(printDir,printFn),format="png")
|
plt.savefig(os.path.join(printDir,printFn),format="png")
|
||||||
@ -470,6 +480,22 @@ def _plot_us_db_takes( inDir, cfg, pitchL, takeIdL, printDir="", printFn="" ):
|
|||||||
plt.legend()
|
plt.legend()
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
def get_pitches_and_takes( inDir ):
|
||||||
|
|
||||||
|
pitchD = {}
|
||||||
|
inDirL = os.listdir( inDir )
|
||||||
|
|
||||||
|
for pitch in inDirL:
|
||||||
|
path = os.path.join( inDir, pitch )
|
||||||
|
takeIdL = os.listdir( path )
|
||||||
|
|
||||||
|
takeIdL = sorted([ int(takeId) for takeId in takeIdL ])
|
||||||
|
takeIdL = [ str(x) for x in takeIdL ]
|
||||||
|
pitchD[int(pitch)] = takeIdL
|
||||||
|
|
||||||
|
|
||||||
|
return pitchD
|
||||||
|
|
||||||
def plot_us_db_takes( inDir, cfg, pitchL, printDir=""):
|
def plot_us_db_takes( inDir, cfg, pitchL, printDir=""):
|
||||||
|
|
||||||
takeIdL = None
|
takeIdL = None
|
||||||
@ -480,14 +506,11 @@ def plot_us_db_takes( inDir, cfg, pitchL, printDir=""):
|
|||||||
|
|
||||||
def plot_us_db_takes_last( inDir, cfg, pitchL, printDir ):
|
def plot_us_db_takes_last( inDir, cfg, pitchL, printDir ):
|
||||||
|
|
||||||
|
pitchD = get_pitches_and_takes(inDir)
|
||||||
|
|
||||||
takeIdL = []
|
takeIdL = []
|
||||||
for pitch in pitchL:
|
for pitch in pitchL:
|
||||||
|
takeIdL.append( int(pitchD[pitch][-1]) )
|
||||||
inDirL = os.listdir( os.path.join(inDir,str(pitch)))
|
|
||||||
|
|
||||||
inDirL = sorted(inDirL)
|
|
||||||
|
|
||||||
takeIdL.append( int(inDirL[-1]) )
|
|
||||||
|
|
||||||
return _plot_us_db_takes( inDir, cfg, pitchL, takeIdL, printDir, "us_db_takes_last.png")
|
return _plot_us_db_takes( inDir, cfg, pitchL, takeIdL, printDir, "us_db_takes_last.png")
|
||||||
|
|
||||||
@ -535,17 +558,21 @@ def plot_all_noise_curves( inDir, cfg, pitchL=None ):
|
|||||||
plt.legend()
|
plt.legend()
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
def nearest_sample_point( dbL, usL, db0, us0 ):
|
||||||
|
xL = np.array([ abs(us-us0) for db,us in zip(dbL,usL) ])
|
||||||
|
|
||||||
|
return np.argmin(xL)
|
||||||
|
|
||||||
|
|
||||||
def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
||||||
|
|
||||||
|
takeIdArg = takeId
|
||||||
|
pitchTakeD = get_pitches_and_takes(inDir)
|
||||||
|
|
||||||
pitchFolderL = os.listdir(inDir)
|
pitchFolderL = os.listdir(inDir)
|
||||||
|
|
||||||
print(pitchL)
|
|
||||||
|
|
||||||
if pitchL is None:
|
if pitchL is None:
|
||||||
pitchL = [ int( int(pitchFolder) ) for pitchFolder in pitchFolderL ]
|
pitchL = [ int( int(pitchFolder) ) for pitchFolder in pitchFolderL ]
|
||||||
|
|
||||||
print(pitchL)
|
|
||||||
|
|
||||||
okL = []
|
okL = []
|
||||||
outPitchL = []
|
outPitchL = []
|
||||||
minDbL = []
|
minDbL = []
|
||||||
@ -553,9 +580,11 @@ def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
|||||||
|
|
||||||
for midi_pitch in pitchL:
|
for midi_pitch in pitchL:
|
||||||
|
|
||||||
print(midi_pitch)
|
takeId = None
|
||||||
|
if takeIdArg == -1:
|
||||||
|
takeId = pitchTakeD[midi_pitch][-1]
|
||||||
|
|
||||||
usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'] )
|
usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'], takeId )
|
||||||
|
|
||||||
okL.append(False)
|
okL.append(False)
|
||||||
|
|
||||||
@ -571,6 +600,9 @@ def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
|||||||
minDbL.append(elbow_db)
|
minDbL.append(elbow_db)
|
||||||
outPitchL.append(midi_pitch)
|
outPitchL.append(midi_pitch)
|
||||||
|
|
||||||
|
smp_idx = nearest_sample_point( dbL, usL, elbow_db, elbow_us )
|
||||||
|
|
||||||
|
print(" %i:[-1,%i], " % (midi_pitch,smp_idx))
|
||||||
|
|
||||||
|
|
||||||
p_dL = sorted( zip(outPitchL,minDbL,maxDbL,okL), key=lambda x: x[0] )
|
p_dL = sorted( zip(outPitchL,minDbL,maxDbL,okL), key=lambda x: x[0] )
|
||||||
@ -593,7 +625,9 @@ def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
|||||||
|
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
def plot_min_db_manual( inDir, cfg, printDir=None ):
|
def plot_min_db_manual( inDir, cfg, printDir=None, absMaxDb=27, absMinDb=3 ):
|
||||||
|
|
||||||
|
pitchTakeD = get_pitches_and_takes(inDir)
|
||||||
|
|
||||||
pitchL = list(cfg.manualMinD.keys())
|
pitchL = list(cfg.manualMinD.keys())
|
||||||
|
|
||||||
@ -606,29 +640,39 @@ def plot_min_db_manual( inDir, cfg, printDir=None ):
|
|||||||
|
|
||||||
for midi_pitch in pitchL:
|
for midi_pitch in pitchL:
|
||||||
|
|
||||||
manual_take_id = cfg.manualMinD[midi_pitch][0]
|
if cfg.manualLastFl:
|
||||||
|
manual_take_id = pitchTakeD[midi_pitch][-1]
|
||||||
|
takeId = manual_take_id
|
||||||
|
else:
|
||||||
|
manual_take_id = cfg.manualMinD[midi_pitch][0]
|
||||||
|
takeId = None
|
||||||
|
|
||||||
manual_sample_idx = cfg.manualMinD[midi_pitch][1]
|
manual_sample_idx = cfg.manualMinD[midi_pitch][1]
|
||||||
|
|
||||||
usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'] )
|
usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'], takeId )
|
||||||
|
|
||||||
okL.append(False)
|
okL.append(False)
|
||||||
|
|
||||||
takeId = len(set(takeIdL))-1
|
if takeId is None:
|
||||||
|
takeId = len(set(takeIdL))-1
|
||||||
|
|
||||||
|
# most pitches have 3 sample takes that do not
|
||||||
|
if len(set(takeIdL)) == 3 and manual_take_id == takeId:
|
||||||
|
okL[-1] = True
|
||||||
|
else:
|
||||||
|
okL[-1] = True
|
||||||
|
|
||||||
# maxDb is computed on all takes (not just the specified take)
|
# maxDb is computed on all takes (not just the specified take)
|
||||||
db_maxL = sorted(dbL)
|
db_maxL = sorted(dbL)
|
||||||
max_db = np.mean(db_maxL[-4:])
|
max_db = min(absMaxDb,np.mean(db_maxL[-4:]))
|
||||||
maxDbL.append( max_db )
|
maxDbL.append( max_db )
|
||||||
|
|
||||||
# get the us,db values for the specified take
|
# get the us,db values for the specified take
|
||||||
usL,dbL = zip(*[(usL[i],dbL[i]) for i in range(len(usL)) if takeIdL[i]==manual_take_id ])
|
usL,dbL = zip(*[(usL[i],dbL[i]) for i in range(len(usL)) if takeIdL[i]==manual_take_id ])
|
||||||
|
|
||||||
# most pitches have 3 sample takes that do not
|
|
||||||
if len(set(takeIdL)) == 3 and manual_take_id == takeId:
|
|
||||||
okL[-1] = True
|
|
||||||
|
|
||||||
# min db from the sample index manually specified in cfg
|
# min db from the sample index manually specified in cfg
|
||||||
manualMinDb = dbL[ manual_sample_idx ]
|
manualMinDb = max(absMinDb,dbL[ manual_sample_idx ])
|
||||||
|
|
||||||
minDbL.append( manualMinDb )
|
minDbL.append( manualMinDb )
|
||||||
outPitchL.append(midi_pitch)
|
outPitchL.append(midi_pitch)
|
||||||
@ -642,8 +686,6 @@ def plot_min_db_manual( inDir, cfg, printDir=None ):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Form the complete set of min/max db levels for each pitch by interpolating the
|
# Form the complete set of min/max db levels for each pitch by interpolating the
|
||||||
# db values between the manually selected anchor points.
|
# db values between the manually selected anchor points.
|
||||||
interpMinDbL = np.interp( pitchL, cfg.manualAnchorPitchMinDbL, anchorMinDbL )
|
interpMinDbL = np.interp( pitchL, cfg.manualAnchorPitchMinDbL, anchorMinDbL )
|
||||||
@ -861,27 +903,67 @@ def report_take_ids( inDir ):
|
|||||||
if len(takeDirL) == 0:
|
if len(takeDirL) == 0:
|
||||||
print(pitch," directory empty")
|
print(pitch," directory empty")
|
||||||
else:
|
else:
|
||||||
with open( os.path.join(pitchDir,'0','seq.json'), "rb") as f:
|
|
||||||
r = json.load(f)
|
|
||||||
|
|
||||||
if len(r['eventTimeL']) != 81:
|
fn = os.path.join(pitchDir,'0','seq.json')
|
||||||
print(pitch," ",len(r['eventTimeL']))
|
|
||||||
|
|
||||||
if len(takeDirL) != 3:
|
if not os.path.isfile(fn):
|
||||||
print("***",pitch,len(takeDirL))
|
print("Missing sequence file:",fn)
|
||||||
|
else:
|
||||||
|
with open( fn, "rb") as f:
|
||||||
|
r = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
if len(r['eventTimeL']) != 81:
|
||||||
|
print(pitch," ",len(r['eventTimeL']))
|
||||||
|
|
||||||
|
if len(takeDirL) != 3:
|
||||||
|
print("***",pitch,len(takeDirL))
|
||||||
|
|
||||||
|
def filter_us_db( us0L, db0L ):
|
||||||
|
|
||||||
|
us1L = [us0L[-1]]
|
||||||
|
db1L = [db0L[-1]]
|
||||||
|
dDb = 0
|
||||||
|
lastIdx = 0
|
||||||
|
for i,(us,db) in enumerate(zip( us0L[::-1],db0L[::-1])):
|
||||||
|
db1 = db1L[-1]
|
||||||
|
if db < db1 and db1-db >= dDb/2:
|
||||||
|
dDb = db1 - db
|
||||||
|
us1L.append(us)
|
||||||
|
db1L.append(db)
|
||||||
|
lastIdx = i
|
||||||
|
|
||||||
|
|
||||||
|
lastIdx = len(us0L) - lastIdx - 1
|
||||||
|
|
||||||
|
|
||||||
|
usL = [ us0L[lastIdx] ]
|
||||||
|
dbL = [ db0L[lastIdx] ]
|
||||||
|
dDb = 0
|
||||||
|
for us,db in zip(us0L[lastIdx::],db0L[lastIdx::]):
|
||||||
|
db1 = dbL[-1]
|
||||||
|
if db > db1:
|
||||||
|
dDb = db-db1
|
||||||
|
usL.append(us)
|
||||||
|
dbL.append(db)
|
||||||
|
|
||||||
|
return usL,dbL
|
||||||
|
|
||||||
def cache_us_db( inDir, cfg, outFn ):
|
def cache_us_db( inDir, cfg, outFn ):
|
||||||
|
|
||||||
|
pitchTakeD = get_pitches_and_takes(inDir)
|
||||||
|
|
||||||
pitch_usDbD = {}
|
pitch_usDbD = {}
|
||||||
pitchDirL = os.listdir(inDir)
|
pitchDirL = os.listdir(inDir)
|
||||||
|
|
||||||
for pitch in pitchDirL:
|
for pitch,takeIdL in pitchTakeD.items():
|
||||||
|
|
||||||
pitch = int(pitch)
|
pitch = int(pitch)
|
||||||
|
takeId = takeIdL[-1]
|
||||||
|
|
||||||
print(pitch)
|
print(pitch)
|
||||||
|
|
||||||
usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, pitch, cfg.analysisArgs['rmsAnalysisArgs'] )
|
usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, pitch, cfg.analysisArgs['rmsAnalysisArgs'], takeId )
|
||||||
|
|
||||||
pitch_usDbD[pitch] = { 'usL':usL, 'dbL':dbL, 'durMsL':durMsL, 'takeIdL':takeIdL, 'holdDutyPctL': holdDutyPctL }
|
pitch_usDbD[pitch] = { 'usL':usL, 'dbL':dbL, 'durMsL':durMsL, 'takeIdL':takeIdL, 'holdDutyPctL': holdDutyPctL }
|
||||||
|
|
||||||
@ -897,10 +979,12 @@ def gen_vel_map( inDir, cfg, minMaxDbFn, dynLevelN, cacheFn ):
|
|||||||
|
|
||||||
pitchDirL = os.listdir(inDir)
|
pitchDirL = os.listdir(inDir)
|
||||||
|
|
||||||
|
# pitchUsDbD = { pitch:
|
||||||
with open(cacheFn,"r") as f:
|
with open(cacheFn,"r") as f:
|
||||||
pitchUsDbD = json.load(f)
|
pitchUsDbD = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
# form minMaxDb = { pitch:(minDb,maxDb) }
|
||||||
with open("minInterpDb.json","r") as f:
|
with open("minInterpDb.json","r") as f:
|
||||||
r = json.load(f)
|
r = json.load(f)
|
||||||
minMaxDbD = { pitch:(minDb,maxDb) for pitch,minDb,maxDb in zip(r['pitchL'],r['minDbL'],r['maxDbL']) }
|
minMaxDbD = { pitch:(minDb,maxDb) for pitch,minDb,maxDb in zip(r['pitchL'],r['minDbL'],r['maxDbL']) }
|
||||||
@ -908,17 +992,31 @@ def gen_vel_map( inDir, cfg, minMaxDbFn, dynLevelN, cacheFn ):
|
|||||||
|
|
||||||
pitchL = sorted( [ int(pitch) for pitch in pitchUsDbD.keys()] )
|
pitchL = sorted( [ int(pitch) for pitch in pitchUsDbD.keys()] )
|
||||||
|
|
||||||
|
# for each pitch
|
||||||
for pitch in pitchL:
|
for pitch in pitchL:
|
||||||
|
|
||||||
|
# get the us/db map for this
|
||||||
d = pitchUsDbD[str(pitch)]
|
d = pitchUsDbD[str(pitch)]
|
||||||
|
|
||||||
usL = d['usL']
|
|
||||||
dbL = np.array(d['dbL'])
|
usL, dbL = filter_us_db( d['usL'], d['dbL'] )
|
||||||
|
#usL = d['usL']
|
||||||
|
#dbL = np.array(d['dbL'])
|
||||||
|
dbL = np.array(dbL)
|
||||||
|
|
||||||
|
|
||||||
velMapD[pitch] = []
|
velMapD[pitch] = []
|
||||||
|
|
||||||
for i in range(dynLevelN+1):
|
maxDb = minMaxDbD[pitch][1]
|
||||||
|
minDb = minMaxDbD[pitch][0]
|
||||||
|
|
||||||
db = minMaxDbD[pitch][0] + (i * (minMaxDbD[pitch][1] - minMaxDbD[pitch][0])/ dynLevelN)
|
dynLevelN = len(cfg.velTableDbL)
|
||||||
|
|
||||||
|
# for each dynamic level
|
||||||
|
for i in range(dynLevelN):
|
||||||
|
|
||||||
|
#db = minDb + (i * (maxDb - minDb)/ dynLevelN)
|
||||||
|
db = cfg.velTableDbL[i]
|
||||||
|
|
||||||
usIdx = np.argmin( np.abs(dbL - db) )
|
usIdx = np.argmin( np.abs(dbL - db) )
|
||||||
|
|
||||||
@ -946,7 +1044,7 @@ def gen_vel_map( inDir, cfg, minMaxDbFn, dynLevelN, cacheFn ):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
printDir = None #os.path.expanduser( "~/src/picadae_ac_3/doc")
|
printDir = os.path.expanduser("~/temp") # os.path.expanduser( "~/src/picadae_ac_3/doc")
|
||||||
cfgFn = sys.argv[1]
|
cfgFn = sys.argv[1]
|
||||||
inDir = sys.argv[2]
|
inDir = sys.argv[2]
|
||||||
mode = sys.argv[3]
|
mode = sys.argv[3]
|
||||||
@ -981,7 +1079,7 @@ if __name__ == "__main__":
|
|||||||
elif mode == 'manual_db':
|
elif mode == 'manual_db':
|
||||||
plot_min_db_manual( inDir, cfg, printDir=printDir )
|
plot_min_db_manual( inDir, cfg, printDir=printDir )
|
||||||
elif mode == 'gen_vel_map':
|
elif mode == 'gen_vel_map':
|
||||||
gen_vel_map( inDir, cfg, "minInterpDb.json", 9, "cache_us_db.json" )
|
gen_vel_map( inDir, cfg, "minInterpDb.json", 12, "cache_us_db.json" )
|
||||||
elif mode == 'cache_us_db':
|
elif mode == 'cache_us_db':
|
||||||
cache_us_db( inDir, cfg, "cache_us_db.json")
|
cache_us_db( inDir, cfg, "cache_us_db.json")
|
||||||
else:
|
else:
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.7.5"
|
"version": "3.8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
@ -254,7 +254,7 @@ def note_stats( r, decay_pct=50.0, extraDurSearchMs=500 ):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def locate_peak_indexes( xV, xV_srate, eventMsL, audioFn ):
|
def locate_peak_indexes( xV, xV_srate, eventMsL, audioFn="" ):
|
||||||
|
|
||||||
pkIdxL = []
|
pkIdxL = []
|
||||||
for i, (begMs, endMs) in enumerate(eventMsL):
|
for i, (begMs, endMs) in enumerate(eventMsL):
|
||||||
@ -601,6 +601,9 @@ def write_audacity_label_files( inDir, analysisArgsD, reverseFl=True ):
|
|||||||
|
|
||||||
takeDir = os.path.join(pitchDir,takeFolder)
|
takeDir = os.path.join(pitchDir,takeFolder)
|
||||||
|
|
||||||
|
if not os.path.isfile(os.path.join(takeDir,"seq.json")):
|
||||||
|
continue
|
||||||
|
|
||||||
r = rms_analysis_main( takeDir, midi_pitch, **analysisArgsD )
|
r = rms_analysis_main( takeDir, midi_pitch, **analysisArgsD )
|
||||||
|
|
||||||
labelFn = os.path.join(takeDir,"audacity.txt")
|
labelFn = os.path.join(takeDir,"audacity.txt")
|
||||||
|
Loading…
Reference in New Issue
Block a user