Added min/max volume note and skip note detection.
This commit is contained in:
parent
c3db8c8ab6
commit
ac9061a72d
127
plot_seq.py
127
plot_seq.py
@ -11,6 +11,49 @@ def is_nanV( xV ):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
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 ):
|
def calc_harm_bins( srate, binHz, midiPitch, harmN ):
|
||||||
|
|
||||||
@ -33,9 +76,14 @@ def calc_harm_bins( srate, binHz, midiPitch, harmN ):
|
|||||||
|
|
||||||
return fund_l_binL, fund_m_binL, fund_u_binL
|
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))
|
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
||||||
hopSmpN = int(round( hopMs * srate / 1000.0))
|
hopSmpN = int(round( hopMs * srate / 1000.0))
|
||||||
@ -60,19 +108,12 @@ def audio_rms( srate, xV, rmsWndMs, hopMs ):
|
|||||||
|
|
||||||
i += hopSmpN
|
i += hopSmpN
|
||||||
j += 1
|
j += 1
|
||||||
|
|
||||||
return yV, srate / hopSmpN
|
|
||||||
|
|
||||||
def audio_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs ):
|
rms_srate = srate / hopSmpN
|
||||||
|
return rms_to_db( yV, rms_srate, refWndMs ), rms_srate
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
def audio_stft_rms( srate, xV, rmsWndMs, hopMs, refWndMs, spectrumIdx ):
|
||||||
def audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx ):
|
|
||||||
|
|
||||||
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
||||||
hopSmpN = int(round( hopMs * 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]):
|
for i in range(xM.shape[1]):
|
||||||
mV[i] = np.max(np.sqrt(np.abs(xM[:,i])))
|
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 ):
|
rms_srate = srate / hopSmpN
|
||||||
rmsV, rms_srate, specV, specHopIdx, binHz = audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx )
|
mV = rms_to_db( mV, rms_srate, refWndMs )
|
||||||
|
|
||||||
dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
|
return mV, rms_srate, specV, specHopIdx, binHz
|
||||||
dbRef = ref = np.mean(rmsV[0:dbWndN])
|
|
||||||
rmsDbV = 20.0 * np.log10( rmsV / dbRef )
|
|
||||||
|
|
||||||
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))
|
wndSmpN = int(round( rmsWndMs * srate / 1000.0))
|
||||||
hopSmpN = int(round( hopMs * 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 ):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
rms_srate = srate / hopSmpN
|
||||||
return rmsV, srate / hopSmpN, binHz
|
rmsV = rms_to_db( rmsV, rms_srate, dbRefWndMs )
|
||||||
|
return rmsV, rms_srate, 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -156,7 +182,8 @@ def locate_peak_indexes( xV, xV_srate, eventMsL ):
|
|||||||
|
|
||||||
|
|
||||||
def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
|
def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
|
||||||
|
""" Plot a single spectrum, 'specV' and the harmonic peak location boundaries."""
|
||||||
|
|
||||||
binN = specV.shape[0]
|
binN = specV.shape[0]
|
||||||
harmLBinL,harmMBinL,harmUBinL = calc_harm_bins( srate, binHz, midiPitch, harmN )
|
harmLBinL,harmMBinL,harmUBinL = calc_harm_bins( srate, binHz, midiPitch, harmN )
|
||||||
|
|
||||||
@ -178,7 +205,8 @@ def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
|
|||||||
ax.set_ylabel(str(midiPitch))
|
ax.set_ylabel(str(midiPitch))
|
||||||
|
|
||||||
def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbRefWndMs=500 ):
|
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)
|
plotN = len(pitchL)
|
||||||
fig,axL = plt.subplots(plotN,1)
|
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)
|
sigV = signalM / float(0x7fff)
|
||||||
|
|
||||||
# calc. the RMS envelope in the time domain
|
# 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
|
# locate the sample index of the peak of each note attack
|
||||||
pkIdx0L = locate_peak_indexes( rms0DbV, rms0_srate, r['eventTimeL'] )
|
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
|
# 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
|
# 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 ):
|
def do_td_plot( inDir ):
|
||||||
|
|
||||||
rmsWndMs = 300
|
rmsWndMs = 300
|
||||||
rmsHopMs = 30
|
rmsHopMs = 30
|
||||||
dbRefWndMs = 500
|
dbRefWndMs = 500
|
||||||
harmCandN = 5
|
harmCandN = 5
|
||||||
harmN = 3
|
harmN = 3
|
||||||
|
minAttkDb = 5.0
|
||||||
|
|
||||||
seqFn = os.path.join( inDir, "seq.json")
|
seqFn = os.path.join( inDir, "seq.json")
|
||||||
audioFn = os.path.join( inDir, "audio.wav")
|
audioFn = os.path.join( inDir, "audio.wav")
|
||||||
@ -241,12 +269,17 @@ def do_td_plot( inDir ):
|
|||||||
srate, signalM = wavfile.read(audioFn)
|
srate, signalM = wavfile.read(audioFn)
|
||||||
sigV = signalM / float(0x7fff)
|
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'] )
|
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,ax = plt.subplots()
|
||||||
fig.set_size_inches(18.5, 10.5, forward=True)
|
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( secV, rmsDbV )
|
||||||
ax.plot( np.arange(0,len(rms0DbV)) / rms0_srate, rms0DbV, color="black" )
|
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=begMs/1000.0, color="green")
|
||||||
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) )
|
||||||
|
|
||||||
|
# plot peak markers
|
||||||
for i,pki in enumerate(pkIdxL):
|
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()
|
plt.show()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user