Added min/max volume note and skip note detection.
This commit is contained in:
parent
c3db8c8ab6
commit
ac9061a72d
119
plot_seq.py
119
plot_seq.py
@ -12,6 +12,49 @@ def is_nanV( xV ):
|
||||
|
||||
return False
|
||||
|
||||
def find_min_max_peak_index( rmsV, pkIdxL, minDb, maxDbOffs=0.5 ):
|
||||
|
||||
# select only the peaks from rmsV[] to work with
|
||||
yV = rmsV[ pkIdxL ]
|
||||
|
||||
# get the max volume note
|
||||
max_i = np.argmax( yV )
|
||||
maxDb = yV[ max_i ]
|
||||
|
||||
min_i = max_i
|
||||
|
||||
# starting from the max volume peak go backwards
|
||||
for i in range( max_i, 0, -1 ):
|
||||
|
||||
# if this peak is within maxDbOffs of the loudest then choose this one instead
|
||||
if maxDb - yV[i] < maxDbOffs:
|
||||
max_i = i
|
||||
|
||||
# if this peak is less than minDb then the previous note is the min note
|
||||
if yV[i] < minDb:
|
||||
break
|
||||
|
||||
min_i = i
|
||||
|
||||
assert( min_i < max_i )
|
||||
|
||||
return min_i, max_i
|
||||
|
||||
def find_skip_peaks( rmsV, pkIdxL, min_pk_idx, max_pk_idx ):
|
||||
skipPkIdxL = []
|
||||
yV = rmsV[pkIdxL]
|
||||
refPkDb = yV[min_pk_idx]
|
||||
|
||||
for i in range( min_pk_idx+1, max_pk_idx+1 ):
|
||||
if yV[i] > refPkDb:
|
||||
refPkDb = yV[i]
|
||||
else:
|
||||
skipPkIdxL.append(i)
|
||||
|
||||
|
||||
return skipPkIdxL
|
||||
|
||||
|
||||
def calc_harm_bins( srate, binHz, midiPitch, harmN ):
|
||||
|
||||
semi_tone = 1.0/12
|
||||
@ -33,9 +76,14 @@ def calc_harm_bins( srate, binHz, midiPitch, harmN ):
|
||||
|
||||
return fund_l_binL, fund_m_binL, fund_u_binL
|
||||
|
||||
def rms_to_db( xV, rms_srate, refWndMs ):
|
||||
dbWndN = int(round(refWndMs * rms_srate / 1000.0))
|
||||
dbRef = ref = np.mean(xV[0:dbWndN])
|
||||
rmsDbV = 20.0 * np.log10( xV / dbRef )
|
||||
|
||||
return rmsDbV
|
||||
|
||||
def audio_rms( srate, xV, rmsWndMs, hopMs ):
|
||||
def audio_rms( srate, xV, rmsWndMs, hopMs, refWndMs ):
|
||||
|
||||
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
||||
hopSmpN = int(round( hopMs * srate / 1000.0))
|
||||
@ -61,18 +109,11 @@ def audio_rms( srate, xV, rmsWndMs, hopMs ):
|
||||
i += hopSmpN
|
||||
j += 1
|
||||
|
||||
return yV, srate / hopSmpN
|
||||
|
||||
def audio_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs ):
|
||||
|
||||
rmsV, rms_srate = audio_rms( srate, xV, rmsWndMs, hopMs )
|
||||
dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
|
||||
dbRef = ref = np.mean(rmsV[0:dbWndN])
|
||||
return 20.0 * np.log10( rmsV / dbRef ), rms_srate
|
||||
rms_srate = srate / hopSmpN
|
||||
return rms_to_db( yV, rms_srate, refWndMs ), rms_srate
|
||||
|
||||
|
||||
|
||||
def audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx ):
|
||||
def audio_stft_rms( srate, xV, rmsWndMs, hopMs, refWndMs, spectrumIdx ):
|
||||
|
||||
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
||||
hopSmpN = int(round( hopMs * srate / 1000.0))
|
||||
@ -88,18 +129,14 @@ def audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx ):
|
||||
for i in range(xM.shape[1]):
|
||||
mV[i] = np.max(np.sqrt(np.abs(xM[:,i])))
|
||||
|
||||
return mV, srate / hopSmpN, specV, specHopIdx, binHz
|
||||
|
||||
def audio_stft_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs, spectrumIdx ):
|
||||
rmsV, rms_srate, specV, specHopIdx, binHz = audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx )
|
||||
rms_srate = srate / hopSmpN
|
||||
mV = rms_to_db( mV, rms_srate, refWndMs )
|
||||
|
||||
dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
|
||||
dbRef = ref = np.mean(rmsV[0:dbWndN])
|
||||
rmsDbV = 20.0 * np.log10( rmsV / dbRef )
|
||||
return mV, rms_srate, specV, specHopIdx, binHz
|
||||
|
||||
return rmsDbV, rms_srate, specV, specHopIdx, binHz
|
||||
|
||||
def audio_harm_rms( srate, xV, rmsWndMs, hopMs, midiPitch, harmCandN, harmN ):
|
||||
def audio_harm_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs, midiPitch, harmCandN, harmN ):
|
||||
|
||||
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
||||
hopSmpN = int(round( hopMs * srate / 1000.0))
|
||||
@ -125,20 +162,9 @@ def audio_harm_rms( srate, xV, rmsWndMs, hopMs, midiPitch, harmCandN, harmN ):
|
||||
|
||||
|
||||
|
||||
|
||||
return rmsV, srate / hopSmpN, binHz
|
||||
|
||||
|
||||
|
||||
def audio_harm_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs, midiPitch, harmCandN, harmN ):
|
||||
|
||||
rmsV, rms_srate, binHz = audio_harm_rms( srate, xV, rmsWndMs, hopMs, midiPitch, harmCandN, harmN )
|
||||
|
||||
dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
|
||||
dbRef = ref = np.mean(rmsV[0:dbWndN])
|
||||
rmsDbV = 20.0 * np.log10( rmsV / dbRef )
|
||||
|
||||
return rmsDbV, rms_srate, binHz
|
||||
rms_srate = srate / hopSmpN
|
||||
rmsV = rms_to_db( rmsV, rms_srate, dbRefWndMs )
|
||||
return rmsV, rms_srate, binHz
|
||||
|
||||
|
||||
|
||||
@ -156,6 +182,7 @@ def locate_peak_indexes( xV, xV_srate, eventMsL ):
|
||||
|
||||
|
||||
def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
|
||||
""" Plot a single spectrum, 'specV' and the harmonic peak location boundaries."""
|
||||
|
||||
binN = specV.shape[0]
|
||||
harmLBinL,harmMBinL,harmUBinL = calc_harm_bins( srate, binHz, midiPitch, harmN )
|
||||
@ -178,6 +205,7 @@ def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
|
||||
ax.set_ylabel(str(midiPitch))
|
||||
|
||||
def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbRefWndMs=500 ):
|
||||
""" Plot the spectrum from one note (7th from last) in each attack pulse length sequence referred to by pitchL."""
|
||||
|
||||
plotN = len(pitchL)
|
||||
fig,axL = plt.subplots(plotN,1)
|
||||
@ -197,7 +225,7 @@ def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbR
|
||||
sigV = signalM / float(0x7fff)
|
||||
|
||||
# calc. the RMS envelope in the time domain
|
||||
rms0DbV, rms0_srate = audio_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
|
||||
rms0DbV, rms0_srate = audio_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
|
||||
|
||||
# locate the sample index of the peak of each note attack
|
||||
pkIdx0L = locate_peak_indexes( rms0DbV, rms0_srate, r['eventTimeL'] )
|
||||
@ -211,7 +239,7 @@ def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbR
|
||||
|
||||
|
||||
# calc. the RMS envelope by taking the max spectral peak in each STFT window
|
||||
rmsDbV, rms_srate, specV, specHopIdx, binHz = audio_stft_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, spectrumSmpIdx)
|
||||
rmsDbV, rms_srate, specV, specHopIdx, binHz = audio_stft_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, spectrumSmpIdx)
|
||||
|
||||
# specV[] is the spectrum of the note at spectrumSmpIdx
|
||||
|
||||
@ -222,12 +250,12 @@ def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbR
|
||||
|
||||
|
||||
def do_td_plot( inDir ):
|
||||
|
||||
rmsWndMs = 300
|
||||
rmsHopMs = 30
|
||||
dbRefWndMs = 500
|
||||
harmCandN = 5
|
||||
harmN = 3
|
||||
minAttkDb = 5.0
|
||||
|
||||
seqFn = os.path.join( inDir, "seq.json")
|
||||
audioFn = os.path.join( inDir, "audio.wav")
|
||||
@ -241,12 +269,17 @@ def do_td_plot( inDir ):
|
||||
srate, signalM = wavfile.read(audioFn)
|
||||
sigV = signalM / float(0x7fff)
|
||||
|
||||
rms0DbV, rms0_srate = audio_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
|
||||
rms0DbV, rms0_srate = audio_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
|
||||
|
||||
rmsDbV, rms_srate, binHz = audio_harm_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, midiPitch, harmCandN, harmN )
|
||||
rmsDbV, rms_srate, binHz = audio_harm_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, midiPitch, harmCandN, harmN )
|
||||
|
||||
pkIdxL = locate_peak_indexes( rmsDbV, rms_srate, r['eventTimeL'] )
|
||||
|
||||
|
||||
min_pk_idx, max_pk_idx = find_min_max_peak_index( rmsDbV, pkIdxL, minAttkDb )
|
||||
|
||||
skipPkIdxL = find_skip_peaks( rmsDbV, pkIdxL, min_pk_idx, max_pk_idx )
|
||||
|
||||
fig,ax = plt.subplots()
|
||||
fig.set_size_inches(18.5, 10.5, forward=True)
|
||||
|
||||
@ -255,13 +288,17 @@ def do_td_plot( inDir ):
|
||||
ax.plot( secV, rmsDbV )
|
||||
ax.plot( np.arange(0,len(rms0DbV)) / rms0_srate, rms0DbV, color="black" )
|
||||
|
||||
for begMs, endMs in r['eventTimeL']:
|
||||
# print beg/end boundaries
|
||||
for i,(begMs, endMs) in enumerate(r['eventTimeL']):
|
||||
ax.axvline( x=begMs/1000.0, color="green")
|
||||
ax.axvline( x=endMs/1000.0, color="red")
|
||||
ax.text(begMs/1000.0, 20.0, str(i) )
|
||||
|
||||
|
||||
# plot peak markers
|
||||
for i,pki in enumerate(pkIdxL):
|
||||
ax.plot( [pki / rms_srate], [ rmsDbV[pki] ], marker='.', color="black")
|
||||
marker = "o" if i==min_pk_idx or i==max_pk_idx else "."
|
||||
color = "red" if i in skipPkIdxL else "black"
|
||||
ax.plot( [pki / rms_srate], [ rmsDbV[pki] ], marker=marker, color=color)
|
||||
|
||||
plt.show()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user