Added multiple PWM values per note.
Misc. changes to plot_seq.py
This commit is contained in:
parent
f69c71c498
commit
919ecadf8d
52
p_ac.py
52
p_ac.py
@ -9,11 +9,12 @@ from AudioDevice import AudioDevice
|
|||||||
from result import Result
|
from result import Result
|
||||||
from common import parse_yaml_cfg
|
from common import parse_yaml_cfg
|
||||||
from plot_seq import form_resample_pulse_time_list
|
from plot_seq import form_resample_pulse_time_list
|
||||||
|
from plot_seq import form_final_pulse_list
|
||||||
|
|
||||||
class AttackPulseSeq:
|
class AttackPulseSeq:
|
||||||
""" Sequence a fixed chord over a list of attack pulse lengths."""
|
""" Sequence a fixed chord over a list of attack pulse lengths."""
|
||||||
|
|
||||||
def __init__(self, audio, api, noteDurMs=1000, pauseDurMs=1000, holdDutyPct=50 ):
|
def __init__(self, audio, api, noteDurMs=1000, pauseDurMs=1000, holdDutyPctL=[(0,50)] ):
|
||||||
self.audio = audio
|
self.audio = audio
|
||||||
self.api = api
|
self.api = api
|
||||||
self.outDir = None # directory to write audio file and results
|
self.outDir = None # directory to write audio file and results
|
||||||
@ -21,12 +22,13 @@ class AttackPulseSeq:
|
|||||||
self.pulseUsL = [] # one onset pulse length in microseconds per sequence element
|
self.pulseUsL = [] # one onset pulse length in microseconds per sequence element
|
||||||
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.holdDutyPct = holdDutyPct # hold voltage duty cycle as a percentage (0-100)
|
self.holdDutyPctL= holdDutyPctL # hold voltage duty cycle table [ (minPulseSeqUsec,dutyCyclePct) ]
|
||||||
|
|
||||||
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'
|
||||||
|
self.prevHoldDutyPct = None
|
||||||
self.next_ms = 0 # Time of next event (note-on or note_off)
|
self.next_ms = 0 # Time of next event (note-on or note_off)
|
||||||
self.eventTimeL = [] # Onset/offset time of each note [ [onset_ms,offset_ms] ]
|
self.eventTimeL = [] # Onset/offset time of each note [ [onset_ms,offset_ms] ] (used to locate the note in the audio file)
|
||||||
self.beginMs = 0
|
self.beginMs = 0
|
||||||
self.playOnlyFl = False
|
self.playOnlyFl = False
|
||||||
|
|
||||||
@ -37,13 +39,15 @@ class AttackPulseSeq:
|
|||||||
|
|
||||||
self.pulse_idx = 0
|
self.pulse_idx = 0
|
||||||
self.state = 'note_on'
|
self.state = 'note_on'
|
||||||
|
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
|
||||||
|
|
||||||
for pitch in pitchL:
|
#for pitch in pitchL:
|
||||||
self.api.set_pwm( pitch, self.holdDutyPct )
|
# self.api.set_pwm_duty( pitch, self.holdDutyPct )
|
||||||
|
# print("set PWM:%i"%(self.holdDutyPct))
|
||||||
|
|
||||||
if not playOnlyFl:
|
if not playOnlyFl:
|
||||||
self.audio.record_enable(True) # start recording audio
|
self.audio.record_enable(True) # start recording audio
|
||||||
@ -87,19 +91,38 @@ class AttackPulseSeq:
|
|||||||
assert(0)
|
assert(0)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_duty_cycle( self, pulseUsec ):
|
||||||
|
dutyPct = self.holdDutyPctL[0][1]
|
||||||
|
for refUsec,refDuty in self.holdDutyPctL:
|
||||||
|
if pulseUsec < refUsec:
|
||||||
|
break
|
||||||
|
dutyPct = refDuty
|
||||||
|
|
||||||
|
return dutyPct
|
||||||
|
|
||||||
|
def _set_duty_cycle( self, pitch, pulseUsec ):
|
||||||
|
|
||||||
|
dutyPct = self._get_duty_cycle( pulseUsec )
|
||||||
|
|
||||||
|
if dutyPct != self.prevHoldDutyPct:
|
||||||
|
self.api.set_pwm_duty( pitch, dutyPct )
|
||||||
|
print("Hold Duty:",dutyPct)
|
||||||
|
|
||||||
|
self.prevHoldDutyPct = dutyPct
|
||||||
|
|
||||||
def _note_on( self, ms ):
|
def _note_on( self, ms ):
|
||||||
|
|
||||||
#self.eventTimeL[ self.pulse_idx ][0] = ms - self.beginMs
|
|
||||||
self.eventTimeL[ self.pulse_idx ][0] = self.audio.buffer_sample_ms().value
|
self.eventTimeL[ self.pulse_idx ][0] = self.audio.buffer_sample_ms().value
|
||||||
self.next_ms = ms + self.noteDurMs
|
self.next_ms = ms + self.noteDurMs
|
||||||
self.state = 'note_off'
|
self.state = 'note_off'
|
||||||
|
|
||||||
for pitch in self.pitchL:
|
for pitch in self.pitchL:
|
||||||
self.api.note_on_us( pitch, int(self.pulseUsL[ self.pulse_idx ]) )
|
pulse_usec = int(self.pulseUsL[ self.pulse_idx ])
|
||||||
|
self._set_duty_cycle( pitch, pulse_usec )
|
||||||
|
self.api.note_on_us( pitch, pulse_usec )
|
||||||
print("note-on:",pitch,self.pulse_idx)
|
print("note-on:",pitch,self.pulse_idx)
|
||||||
|
|
||||||
def _note_off( self, ms ):
|
def _note_off( self, ms ):
|
||||||
#self.eventTimeL[ self.pulse_idx ][1] = ms - self.beginMs
|
|
||||||
self.eventTimeL[ self.pulse_idx ][1] = self.audio.buffer_sample_ms().value
|
self.eventTimeL[ self.pulse_idx ][1] = self.audio.buffer_sample_ms().value
|
||||||
self.next_ms = ms + self.pauseDurMs
|
self.next_ms = ms + self.pauseDurMs
|
||||||
self.state = 'note_on'
|
self.state = 'note_on'
|
||||||
@ -123,7 +146,7 @@ class AttackPulseSeq:
|
|||||||
"pitchL":self.pitchL,
|
"pitchL":self.pitchL,
|
||||||
"noteDurMs":self.noteDurMs,
|
"noteDurMs":self.noteDurMs,
|
||||||
"pauseDurMs":self.pauseDurMs,
|
"pauseDurMs":self.pauseDurMs,
|
||||||
"holdDutyPct":self.holdDutyPct,
|
"holdDutyPctL":self.holdDutyPctL,
|
||||||
"eventTimeL":self.eventTimeL,
|
"eventTimeL":self.eventTimeL,
|
||||||
"beginMs":self.beginMs
|
"beginMs":self.beginMs
|
||||||
}
|
}
|
||||||
@ -144,7 +167,7 @@ class AttackPulseSeq:
|
|||||||
class CalibrateKeys:
|
class CalibrateKeys:
|
||||||
def __init__(self, cfg, audioDev, api):
|
def __init__(self, cfg, audioDev, api):
|
||||||
self.cfg = cfg
|
self.cfg = cfg
|
||||||
self.seq = AttackPulseSeq( audioDev, api, noteDurMs=1000, pauseDurMs=1000, holdDutyPct=50 )
|
self.seq = AttackPulseSeq( audioDev, api, noteDurMs=cfg.noteDurMs, pauseDurMs=cfg.pauseDurMs, holdDutyPctL=cfg.holdDutyPctL )
|
||||||
|
|
||||||
self.pulseUsL = None
|
self.pulseUsL = None
|
||||||
self.chordL = None
|
self.chordL = None
|
||||||
@ -198,14 +221,14 @@ class CalibrateKeys:
|
|||||||
|
|
||||||
outDir = os.path.join(outDir, dirStr )
|
outDir = os.path.join(outDir, dirStr )
|
||||||
|
|
||||||
print(outDir)
|
|
||||||
if not os.path.isdir(outDir):
|
if not os.path.isdir(outDir):
|
||||||
os.mkdir(outDir)
|
os.mkdir(outDir)
|
||||||
|
|
||||||
|
|
||||||
# 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:
|
if outDir_id != 0:
|
||||||
self.pulseUsL,_,_ = form_resample_pulse_time_list( outDir, self.cfg.analysisArgs )
|
self.pulseUsL,_,_ = form_resample_pulse_time_list( outDir, self.cfg.analysisArgs )
|
||||||
@ -213,7 +236,10 @@ class CalibrateKeys:
|
|||||||
if playOnlyFl:
|
if playOnlyFl:
|
||||||
self.pulseUsL,_ = form_final_pulse_list( outDir, pitchL[0], self.cfg.analysisArgs, take_id=None )
|
self.pulseUsL,_ = form_final_pulse_list( outDir, pitchL[0], self.cfg.analysisArgs, take_id=None )
|
||||||
|
|
||||||
|
noteN = cfg.analysisArgs['auditionNoteN']
|
||||||
|
self.pulseUsL = [ self.pulseUsL[ int(round(i*126.0/(noteN-1)))] for i in range(noteN) ]
|
||||||
|
|
||||||
|
else:
|
||||||
outDir = os.path.join( outDir, str(outDir_id) )
|
outDir = os.path.join( outDir, str(outDir_id) )
|
||||||
|
|
||||||
if not os.path.isdir(outDir):
|
if not os.path.isdir(outDir):
|
||||||
@ -533,7 +559,7 @@ def parse_args():
|
|||||||
ap = argparse.ArgumentParser(description=descStr)
|
ap = argparse.ArgumentParser(description=descStr)
|
||||||
|
|
||||||
|
|
||||||
ap.add_argument("-c","--config", default="cfg/p_ac.yml", help="YAML configuration file.")
|
ap.add_argument("-c","--config", default="p_ac.yml", help="YAML configuration file.")
|
||||||
ap.add_argument("-l","--log_level",choices=logL, default="warning", help="Set logging level: debug,info,warning,error,critical. Default:warning")
|
ap.add_argument("-l","--log_level",choices=logL, default="warning", help="Set logging level: debug,info,warning,error,critical. Default:warning")
|
||||||
|
|
||||||
return ap.parse_args()
|
return ap.parse_args()
|
||||||
|
29
p_ac.yml
29
p_ac.yml
@ -18,14 +18,28 @@
|
|||||||
|
|
||||||
|
|
||||||
# MeasureSeq args
|
# MeasureSeq args
|
||||||
outDir: "~/temp/p_ac_3",
|
outDir: "~/temp/p_ac_3c",
|
||||||
noteDurMs: 1000,
|
noteDurMs: 1000,
|
||||||
pauseDurMs: 1000,
|
pauseDurMs: 1000,
|
||||||
holdDutyPct: 50,
|
holdDutyPctL: [ [0,50], [17000,65] ],
|
||||||
|
|
||||||
full_pulse0L: [ 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000, 8000, 9000, 10000, 12000, 14000, 18000, 22000, 26000, 30000, 34000, 40000],
|
full_pulse0L: [ 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000, 8000, 9000, 10000, 12000, 14000, 18000, 22000, 26000, 30000, 34000, 40000],
|
||||||
full_pulse1L: [ 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 20000, 22000, 24000, 26000, 30000, 32000, 34000, 36000, 40000],
|
full_pulse1L: [ 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 20000, 22000, 24000, 26000, 30000, 32000, 34000, 36000, 40000],
|
||||||
full_pulseL: [ 10000, 10500, 11000, 11500, 12000, 12500, 13000, 13500, 14000, 14500, 15000, 15500, 16000, 16500, 17000, 17500, 18000, 18500, 20000, 22000, 24000, 26000, 30000, 32000, 34000, 36000, 40000],
|
full_pulse2L: [ 10000, 10500, 11000, 11500, 12000, 12500, 13000, 13500, 14000, 14500, 15000, 15500, 16000, 16500, 17000, 17500, 18000, 18500, 20000, 22000, 24000, 26000, 30000, 32000, 34000, 36000, 40000],
|
||||||
|
|
||||||
|
full_pulse3L: [ 10000, 10125, 10250, 10500, 10625, 10750, 10875, 11000, 11125, 11250, 11500, 11625, 11750, 11875, 12000, 12125, 12250, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13500, 13625, 13750, 13875, 14000, 14125, 14250, 14500, 14625, 14750, 14875, 15000, 15500, 16000, 16500, 17000, 17500, 18000, 18500, 20000, 22000, 24000, 26000, 30000, 32000, 34000, 36000, 40000],
|
||||||
|
|
||||||
|
full_pulse4L: [ 8000, 8125, 8250, 8375, 8500, 8625, 8750, 8875, 9000, 9125, 9250, 9375, 9500, 9625, 9750, 9875, 10000, 10125, 10250, 10375, 10500, 10625, 10750, 10875, 11000, 11125, 11250, 11375, 11500, 11625, 11750, 11875, 12000, 12125, 12250, 12375, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13375, 13500, 13625, 13750, 13875, 14000, 14125, 14375, 14250, 14500, 14625, 14750, 14875, 15000, 15250, 15375, 15500, 15750, 16000, 16250, 16500, 16750, 17000, 17250, 17500, 17750, 18000, 18250, 18500, 18750, 20000, 21000, 22000, 23000, 24000, 25000, 26000, 27000, 28000, 30000, 32000, 34000, 36000, 40000],
|
||||||
|
|
||||||
|
full_pulse5L: [ 10000, 10125, 10250, 10375, 10500, 10625, 10750, 10875, 11000, 11125, 11250, 11375, 11500, 11625, 11750, 11875, 12000, 12125, 12250, 12375, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13375, 13500, 13625, 13750, 13875, 14000, 14125, 14250, 14375, 14500, 14625, 14750, 14875, 15000, 15250, 15375, 15500, 15750, 16000, 16250, 16500, 16750, 17000, 17250, 17500, 17750, 18000, 18250, 18500, 18750, 20000, 21000, 22000, 23000, 24000, 25000, 26000, 27000, 28000, 30000, 32000, 34000, 36000, 40000],
|
||||||
|
|
||||||
|
full_pulse6L: [ 12000, 12125, 12250, 12375, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13375, 13500, 13625, 13750, 13875, 14000, 14125, 14250, 14375, 14500, 14625, 14750, 14875, 15000, 15250, 15375, 15500, 15750, 16000, 16250, 16500, 16750, 17000, 17250, 17500, 17750, 18000, 18250, 18500, 18750, 19000, 19500, 20000, 20500, 21000, 21500, 22000, 22500, 23000, 23500, 24000, 24500, 25000, 25500, 26000, 26500, 27000, 27500, 28000, 28500, 29000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, 38000, 39000, 40000 ],
|
||||||
|
|
||||||
|
full_pulse7L: [ 11000, 11125, 11250, 11375, 11500, 11625, 11750, 11875, 12000, 12125, 12250, 12375, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13375, 13500, 13625, 13750, 13875, 14000, 14125, 14250, 14375, 14500, 14625, 14750, 14875, 15000, 15250, 15375, 15500, 15750, 16000, 16250, 16500, 16750, 17000, 17250, 17500, 17750, 18000, 18250, 18500, 18750, 19000, 19500, 20000, 20500, 21000, 21500, 22000, 22500, 23000, 23500, 24000, 24500, 25000, 25500, 26000, 26500, 27000, 27500, 28000, 28500, 29000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, 38000, 39000, 40000 ],
|
||||||
|
|
||||||
|
full_pulseL: [ 10000, 10050, 10100, 10150, 10200, 10250, 10300, 10350, 10400, 10450, 10500, 10550, 10600, 10650, 10700, 10750, 10800, 10850, 10900, 10950, 11000, 11125, 11250, 11375, 11500, 11625, 11750, 11875, 12000, 12125, 12250, 12375, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13375, 13500, 13625, 13750, 13875, 14000, 14125, 14250, 14375, 14500, 14625, 14750, 14875, 15000, 15250, 15375, 15500, 15750, 16000, 16250, 16500, 16750, 17000, 17250, 17500, 17750, 18000, 18250, 18500, 18750, 19000, 19500, 20000, 20500, 21000, 21500, 22000, 22500, 23000, 23500, 24000, 24500, 25000, 25500, 26000, 26500, 27000, 27500, 28000, 28500, 29000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, 38000, 39000, 40000 ],
|
||||||
|
|
||||||
|
full_pulse9L: [ 8750, 8800, 8850, 8900, 8950, 9000, 9050, 9100, 9150, 9200, 9250, 9300, 9350, 9400, 9450,9500, 9550, 9600, 9650, 9700, 9750, 9800, 9850, 9900, 9950, 10000, 10050, 10100, 10150, 10200, 10250, 10300, 10350, 10400, 10450, 10500, 10550, 10600, 10650, 10700, 10750, 10800, 10850, 10900, 10950, 11000, 11125, 11250, 11375, 11500, 11625, 11750, 11875, 12000, 12125, 12250, 12375, 12500, 12625, 12750, 12875, 13000, 13125, 13250, 13375, 13500, 13625, 13750, 13875, 14000, 14125, 14250, 14375, 14500, 14625, 14750, 14875, 15000, 15250, 15375, 15500, 15750, 16000, 16250, 16500, 16750, 17000, 17250, 17500, 17750, 18000, 18250, 18500, 18750, 19000, 19500, 20000, 20500, 21000, 21500, 22000, 22500, 23000, 23500, 24000, 24500, 25000, 25500, 26000, 26500, 27000, 27500, 28000, 28500, 29000, 30000, 31000, 32000, 33000, 34000, 35000, 36000, 37000, 38000, 39000, 40000 ],
|
||||||
|
|
||||||
# RMS analysis args
|
# RMS analysis args
|
||||||
analysisArgs: {
|
analysisArgs: {
|
||||||
@ -37,11 +51,12 @@
|
|||||||
harmN: 3, # count of harmonics to use to calculate harmonic based RMS analysis
|
harmN: 3, # count of harmonics to use to calculate harmonic based RMS analysis
|
||||||
},
|
},
|
||||||
|
|
||||||
minAttkDb: 5.0, # threshold of silence level
|
minAttkDb: 7.0, # threshold of silence level
|
||||||
maxDbOffset: 0.5, # 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: 2.0, # 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: 500 # 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
|
||||||
},
|
},
|
||||||
|
|
||||||
key_mapL: [
|
key_mapL: [
|
||||||
|
59
plot_seq.py
59
plot_seq.py
@ -120,7 +120,8 @@ def form_final_pulse_list( inDir, midi_pitch, analysisArgsD, take_id=None ):
|
|||||||
multValL.append((out_idx,multi_value_count))
|
multValL.append((out_idx,multi_value_count))
|
||||||
|
|
||||||
if len(multValL) > 0:
|
if len(multValL) > 0:
|
||||||
print("Multi-value pulse locations were found during velocity table formation: ",multValL)
|
# print("Multi-value pulse locations were found during velocity table formation: ",multValL)
|
||||||
|
pass
|
||||||
|
|
||||||
return pulseUsL,pulseDbL
|
return pulseUsL,pulseDbL
|
||||||
|
|
||||||
@ -158,8 +159,18 @@ def merge_close_sample_points( pkDbUsL, minSampleDistanceUs ):
|
|||||||
return pkDbUsL
|
return pkDbUsL
|
||||||
|
|
||||||
|
|
||||||
|
def _calc_resample_points( dPkDb, pkUs0, pkUs1, samplePerDb, minSampleDistUs ):
|
||||||
|
|
||||||
def calc_resample_ranges( pkDbL, pkUsL, min_pk_idx, max_pk_idx, maxDeltaDb, samplePerDb ):
|
dPkUs = pkUs1 - pkUs0
|
||||||
|
sampleCnt = max(int(round(abs(dPkDb) * samplePerDb)),samplePerDb)
|
||||||
|
dUs = max(int(round(dPkUs/sampleCnt)),minSampleDistUs)
|
||||||
|
sampleCnt = int(round(dPkUs/dUs))
|
||||||
|
dUs = int(round(dPkUs/sampleCnt))
|
||||||
|
usL = [ pkUs0 + dUs*j for j in range(sampleCnt+1)]
|
||||||
|
|
||||||
|
return usL
|
||||||
|
|
||||||
|
def calc_resample_ranges( pkDbL, pkUsL, min_pk_idx, max_pk_idx, maxDeltaDb, samplePerDb, minSampleDistUs ):
|
||||||
|
|
||||||
if min_pk_idx == 0:
|
if min_pk_idx == 0:
|
||||||
print("No silent notes were generated. Decrease the minimum peak level or the hold voltage.")
|
print("No silent notes were generated. Decrease the minimum peak level or the hold voltage.")
|
||||||
@ -180,16 +191,13 @@ def calc_resample_ranges( pkDbL, pkUsL, min_pk_idx, max_pk_idx, maxDeltaDb, samp
|
|||||||
# it is below the previous max peak
|
# it is below the previous max peak
|
||||||
if d > maxDeltaDb or d <= 0 or pkDbL[i] < refPkDb:
|
if d > maxDeltaDb or d <= 0 or pkDbL[i] < refPkDb:
|
||||||
|
|
||||||
sampleCnt = max(int(round(abs(d) * samplePerDb)),samplePerDb)
|
usL = _calc_resample_points( d, pkUsL[i-1], pkUsL[i], samplePerDb, minSampleDistUs )
|
||||||
dUs = int(round((pkUsL[i] - pkUsL[i-1])/sampleCnt))
|
|
||||||
usL = [ pkUsL[i-1] + dUs*j for j in range(sampleCnt)]
|
|
||||||
|
|
||||||
if i + 1 < len(pkDbL):
|
if d <= 0 and i + 1 < len(pkDbL):
|
||||||
d = pkDbL[i+1] - pkDbL[i]
|
d = pkDbL[i+1] - pkDbL[i]
|
||||||
|
|
||||||
sampleCnt = max(int(round(abs(d) * samplePerDb)),samplePerDb)
|
usL += _calc_resample_points( d, pkUsL[i-1], pkUsL[i], samplePerDb, minSampleDistUs )
|
||||||
dUs = int(round((pkUsL[i+1] - pkUsL[i])/sampleCnt))
|
|
||||||
usL += [ pkUsL[i] + dUs*j for j in range(sampleCnt)]
|
|
||||||
|
|
||||||
if pkDbL[i] > refPkDb:
|
if pkDbL[i] > refPkDb:
|
||||||
refPkDb = pkDbL[i]
|
refPkDb = pkDbL[i]
|
||||||
@ -239,10 +247,12 @@ def form_resample_pulse_time_list( inDir, analysisArgsD ):
|
|||||||
min_pk_idx, max_pk_idx = find_min_max_peak_index( pkDbL, analysisArgsD['minAttkDb'], analysisArgsD['maxDbOffset'] )
|
min_pk_idx, max_pk_idx = find_min_max_peak_index( pkDbL, analysisArgsD['minAttkDb'], analysisArgsD['maxDbOffset'] )
|
||||||
|
|
||||||
# estimate the microsecond locations to resample
|
# estimate the microsecond locations to resample
|
||||||
resampleUsSet = calc_resample_ranges( pkDbL, pkUsL, min_pk_idx, max_pk_idx, analysisArgsD['maxDeltaDb'], analysisArgsD['samplesPerDb'] )
|
resampleUsSet = calc_resample_ranges( pkDbL, pkUsL, min_pk_idx, max_pk_idx, analysisArgsD['maxDeltaDb'], analysisArgsD['samplesPerDb'], analysisArgsD['minSampleDistUs'] )
|
||||||
|
|
||||||
resampleUsL = sorted( list(resampleUsSet) )
|
resampleUsL = sorted( list(resampleUsSet) )
|
||||||
|
|
||||||
|
#print(resampleUsL)
|
||||||
|
|
||||||
return resampleUsL, pkDbL, pkUsL
|
return resampleUsL, pkDbL, pkUsL
|
||||||
|
|
||||||
|
|
||||||
@ -282,8 +292,8 @@ def find_min_max_peak_index( pkDbL, minDb, maxDbOffs ):
|
|||||||
for i in range( max_i, 0, -1 ):
|
for i in range( max_i, 0, -1 ):
|
||||||
|
|
||||||
# if this peak is within maxDbOffs of the loudest then choose this one instead
|
# if this peak is within maxDbOffs of the loudest then choose this one instead
|
||||||
if maxDb - yV[i] < maxDbOffs:
|
#if maxDb - yV[i] < maxDbOffs:
|
||||||
max_i = i
|
# max_i = i
|
||||||
|
|
||||||
# if this peak is less than minDb then the previous note is the min note
|
# if this peak is less than minDb then the previous note is the min note
|
||||||
if yV[i] < minDb:
|
if yV[i] < minDb:
|
||||||
@ -291,7 +301,10 @@ def find_min_max_peak_index( pkDbL, minDb, maxDbOffs ):
|
|||||||
|
|
||||||
min_i = i
|
min_i = i
|
||||||
|
|
||||||
assert( min_i < max_i )
|
if min_i >= max_i:
|
||||||
|
min_i = 0
|
||||||
|
max_i = len(pkDbL)-1
|
||||||
|
|
||||||
|
|
||||||
if min_i == 0:
|
if min_i == 0:
|
||||||
print("No silent notes were generated. Decrease the minimum peak level or the hold voltage.")
|
print("No silent notes were generated. Decrease the minimum peak level or the hold voltage.")
|
||||||
@ -423,7 +436,7 @@ def td_plot( ax, inDir, midi_pitch, id, analysisArgsD ):
|
|||||||
ax.axvline( x=endMs/1000.0, color="red")
|
ax.axvline( x=endMs/1000.0, color="red")
|
||||||
ax.text(begMs/1000.0, 20.0, str(i) )
|
ax.text(begMs/1000.0, 20.0, str(i) )
|
||||||
|
|
||||||
return
|
|
||||||
# plot peak markers
|
# plot peak markers
|
||||||
for i,pki in enumerate(r.pkIdxL):
|
for i,pki in enumerate(r.pkIdxL):
|
||||||
marker = 4 if i==min_pk_idx or i==max_pk_idx else 5
|
marker = 4 if i==min_pk_idx or i==max_pk_idx else 5
|
||||||
@ -434,18 +447,19 @@ def td_plot( ax, inDir, midi_pitch, id, analysisArgsD ):
|
|||||||
ax.plot( [pki / r.rms_srate], [ r.rmsDbV[pki] ], marker=6, color="blue")
|
ax.plot( [pki / r.rms_srate], [ r.rmsDbV[pki] ], marker=6, color="blue")
|
||||||
|
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
def do_td_plot( inDir, analysisArgs ):
|
def do_td_plot( inDir, analysisArgs ):
|
||||||
|
|
||||||
fig,ax = plt.subplots()
|
fig,axL = plt.subplots(2,1)
|
||||||
fig.set_size_inches(18.5, 10.5, forward=True)
|
fig.set_size_inches(18.5, 10.5, forward=True)
|
||||||
|
|
||||||
|
|
||||||
id = int(inDir.split("/")[-1])
|
id = int(inDir.split("/")[-1])
|
||||||
midi_pitch = int(inDir.split("/")[-2])
|
midi_pitch = int(inDir.split("/")[-2])
|
||||||
|
|
||||||
td_plot(ax,inDir,midi_pitch,id,analysisArgs)
|
r = td_plot(axL[0],inDir,midi_pitch,id,analysisArgs)
|
||||||
|
|
||||||
|
axL[1].plot( r.pkUsL, r.pkDbL, marker='.' )
|
||||||
|
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
@ -469,12 +483,15 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
inDir = sys.argv[1]
|
inDir = sys.argv[1]
|
||||||
cfgFn = sys.argv[2]
|
cfgFn = sys.argv[2]
|
||||||
|
take_id = None if len(sys.argv)<4 else sys.argv[3]
|
||||||
|
|
||||||
cfg = parse_yaml_cfg( cfgFn )
|
cfg = parse_yaml_cfg( cfgFn )
|
||||||
|
|
||||||
#do_td_plot(inDir,cfg.analysisArgs)
|
if take_id is not None:
|
||||||
|
inDir = os.path.join(inDir,take_id)
|
||||||
#o_td_multi_plot(inDir,cfg.analysisArgs)
|
do_td_plot(inDir,cfg.analysisArgs)
|
||||||
|
else:
|
||||||
|
#do_td_multi_plot(inDir,cfg.analysisArgs)
|
||||||
|
|
||||||
#plot_spectral_ranges( inDir, [ 24, 36, 48, 60, 72, 84, 96, 104] )
|
#plot_spectral_ranges( inDir, [ 24, 36, 48, 60, 72, 84, 96, 104] )
|
||||||
|
|
||||||
|
@ -148,6 +148,8 @@ def rms_analysis_main( inDir, midi_pitch, rmsWndMs=300, rmsHopMs=30, dbRefWndMs=
|
|||||||
|
|
||||||
tdRmsDbV, rms0_srate = audio_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
|
tdRmsDbV, rms0_srate = audio_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
|
||||||
|
|
||||||
|
tdPkIdxL = locate_peak_indexes( tdRmsDbV, rms0_srate, r['eventTimeL'])
|
||||||
|
|
||||||
rmsDbV, rms_srate, binHz = audio_harm_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, midi_pitch, harmCandN, harmN )
|
rmsDbV, rms_srate, binHz = audio_harm_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, midi_pitch, harmCandN, harmN )
|
||||||
|
|
||||||
pkIdxL = locate_peak_indexes( rmsDbV, rms_srate, r['eventTimeL'] )
|
pkIdxL = locate_peak_indexes( rmsDbV, rms_srate, r['eventTimeL'] )
|
||||||
@ -155,6 +157,8 @@ def rms_analysis_main( inDir, midi_pitch, rmsWndMs=300, rmsHopMs=30, dbRefWndMs=
|
|||||||
r = types.SimpleNamespace(**{
|
r = types.SimpleNamespace(**{
|
||||||
"audio_srate":srate,
|
"audio_srate":srate,
|
||||||
"tdRmsDbV": tdRmsDbV,
|
"tdRmsDbV": tdRmsDbV,
|
||||||
|
"tdPkIdxL": tdPkIdxL,
|
||||||
|
"tdPkDbL": [ tdRmsDbV[i] for i in tdPkIdxL ],
|
||||||
"binHz": binHz,
|
"binHz": binHz,
|
||||||
"rmsDbV":rmsDbV,
|
"rmsDbV":rmsDbV,
|
||||||
"rms_srate":rms_srate,
|
"rms_srate":rms_srate,
|
||||||
|
Loading…
Reference in New Issue
Block a user