Преглед на файлове

Added min/max volume note and skip note detection.

master
kpl преди 4 години
родител
ревизия
ac9061a72d
променени са 1 файла, в които са добавени 82 реда и са изтрити 45 реда
  1. 82
    45
      plot_seq.py

+ 82
- 45
plot_seq.py Целия файл

@@ -11,6 +11,49 @@ def is_nanV( xV ):
11 11
             return True
12 12
         
13 13
     return False
14
+
15
+def find_min_max_peak_index( rmsV, pkIdxL, minDb, maxDbOffs=0.5 ):
16
+
17
+    # select only the peaks from rmsV[] to work with
18
+    yV = rmsV[ pkIdxL ]
19
+
20
+    # get the max volume note
21
+    max_i = np.argmax( yV )
22
+    maxDb = yV[ max_i ]
23
+
24
+    min_i = max_i
25
+
26
+    # starting from the max volume peak go backwards
27
+    for i in range( max_i, 0, -1 ):
28
+
29
+        # if this peak is within maxDbOffs of the loudest then choose this one instead
30
+        if maxDb - yV[i] < maxDbOffs:
31
+            max_i = i
32
+
33
+        # if this peak is less than minDb then the previous note is the min note
34
+        if yV[i] < minDb:
35
+            break
36
+        
37
+        min_i = i
38
+
39
+    assert( min_i < max_i )
40
+    
41
+    return min_i, max_i
42
+
43
+def find_skip_peaks( rmsV, pkIdxL, min_pk_idx, max_pk_idx ):
44
+    skipPkIdxL = []
45
+    yV         = rmsV[pkIdxL]
46
+    refPkDb    = yV[min_pk_idx]
47
+
48
+    for i in range( min_pk_idx+1, max_pk_idx+1 ):
49
+        if yV[i] > refPkDb:
50
+            refPkDb = yV[i]
51
+        else:
52
+            skipPkIdxL.append(i)
53
+            
54
+            
55
+    return skipPkIdxL
56
+
14 57
         
15 58
 def calc_harm_bins( srate, binHz, midiPitch, harmN ):
16 59
 
@@ -33,9 +76,14 @@ def calc_harm_bins( srate, binHz, midiPitch, harmN ):
33 76
     
34 77
     return fund_l_binL, fund_m_binL, fund_u_binL
35 78
     
79
+def rms_to_db( xV, rms_srate, refWndMs ):
80
+    dbWndN = int(round(refWndMs * rms_srate / 1000.0))
81
+    dbRef = ref = np.mean(xV[0:dbWndN])
82
+    rmsDbV = 20.0 * np.log10( xV / dbRef )
36 83
 
84
+    return rmsDbV
37 85
 
38
-def audio_rms( srate, xV, rmsWndMs, hopMs  ):
86
+def audio_rms( srate, xV, rmsWndMs, hopMs, refWndMs  ):
39 87
 
40 88
     wndSmpN = int(round( rmsWndMs * srate / 1000.0))
41 89
     hopSmpN = int(round( hopMs    * srate / 1000.0))
@@ -60,19 +108,12 @@ def audio_rms( srate, xV, rmsWndMs, hopMs  ):
60 108
 
61 109
         i += hopSmpN
62 110
         j += 1
63
-        
64
-    return yV, srate / hopSmpN
65
-
66
-def audio_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs ):
67 111
 
68
-    rmsV, rms_srate = audio_rms( srate, xV, rmsWndMs, hopMs )
69
-    dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
70
-    dbRef = ref = np.mean(rmsV[0:dbWndN])
71
-    return 20.0 * np.log10( rmsV / dbRef ), rms_srate
112
+    rms_srate = srate / hopSmpN
113
+    return rms_to_db( yV, rms_srate, refWndMs ), rms_srate
72 114
 
73 115
 
74
-
75
-def audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx ):
116
+def audio_stft_rms( srate, xV, rmsWndMs, hopMs, refWndMs, spectrumIdx ):
76 117
     
77 118
     wndSmpN = int(round( rmsWndMs * srate / 1000.0))
78 119
     hopSmpN = int(round( hopMs    * srate / 1000.0))
@@ -88,18 +129,14 @@ def audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx ):
88 129
     for i in range(xM.shape[1]):
89 130
         mV[i] = np.max(np.sqrt(np.abs(xM[:,i])))
90 131
 
91
-    return mV, srate / hopSmpN, specV, specHopIdx, binHz
92 132
 
93
-def audio_stft_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs, spectrumIdx ):
94
-    rmsV, rms_srate, specV, specHopIdx, binHz = audio_stft_rms( srate, xV, rmsWndMs, hopMs, spectrumIdx )
95
-    
96
-    dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
97
-    dbRef = ref = np.mean(rmsV[0:dbWndN])
98
-    rmsDbV = 20.0 * np.log10( rmsV / dbRef )
133
+    rms_srate = srate / hopSmpN
134
+    mV = rms_to_db( mV, rms_srate, refWndMs )
135
+        
136
+    return mV, rms_srate, specV, specHopIdx, binHz
99 137
 
100
-    return rmsDbV, rms_srate, specV, specHopIdx, binHz
101 138
 
102
-def audio_harm_rms( srate, xV, rmsWndMs, hopMs, midiPitch, harmCandN, harmN  ):
139
+def audio_harm_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs, midiPitch, harmCandN, harmN  ):
103 140
 
104 141
     wndSmpN   = int(round( rmsWndMs * srate / 1000.0))
105 142
     hopSmpN   = int(round( hopMs    * srate / 1000.0))
@@ -125,20 +162,9 @@ def audio_harm_rms( srate, xV, rmsWndMs, hopMs, midiPitch, harmCandN, harmN  ):
125 162
             
126 163
             
127 164
         
128
-
129
-    return rmsV, srate / hopSmpN, binHz
130
-
131
-
132
-    
133
-def audio_harm_db_rms( srate, xV, rmsWndMs, hopMs, dbRefWndMs, midiPitch, harmCandN, harmN  ):
134
-    
135
-    rmsV, rms_srate, binHz = audio_harm_rms( srate, xV, rmsWndMs, hopMs, midiPitch, harmCandN, harmN )
136
-    
137
-    dbWndN = int(round(dbRefWndMs * rms_srate / 1000.0))
138
-    dbRef = ref = np.mean(rmsV[0:dbWndN])
139
-    rmsDbV = 20.0 * np.log10( rmsV / dbRef )
140
-
141
-    return rmsDbV, rms_srate, binHz
165
+    rms_srate = srate / hopSmpN
166
+    rmsV = rms_to_db( rmsV, rms_srate, dbRefWndMs )
167
+    return rmsV, rms_srate, binHz
142 168
     
143 169
     
144 170
                
@@ -156,7 +182,8 @@ def locate_peak_indexes( xV, xV_srate, eventMsL ):
156 182
 
157 183
 
158 184
 def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
159
-
185
+    """ Plot a single spectrum, 'specV' and the harmonic peak location boundaries."""
186
+    
160 187
     binN      = specV.shape[0]
161 188
     harmLBinL,harmMBinL,harmUBinL = calc_harm_bins( srate, binHz, midiPitch, harmN )
162 189
 
@@ -178,7 +205,8 @@ def plot_spectrum( ax, srate, binHz, specV, midiPitch, harmN ):
178 205
     ax.set_ylabel(str(midiPitch))
179 206
         
180 207
 def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbRefWndMs=500 ):
181
-
208
+    """ Plot the spectrum from one note (7th from last) in each attack pulse length sequence referred to by pitchL."""
209
+    
182 210
     plotN = len(pitchL)
183 211
     fig,axL = plt.subplots(plotN,1)
184 212
 
@@ -197,7 +225,7 @@ def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbR
197 225
         sigV  = signalM / float(0x7fff)
198 226
 
199 227
         # calc. the RMS envelope in the time domain
200
-        rms0DbV, rms0_srate = audio_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
228
+        rms0DbV, rms0_srate = audio_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
201 229
 
202 230
         # locate the sample index of the peak of each note attack 
203 231
         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
211 239
 
212 240
 
213 241
         # calc. the RMS envelope by taking the max spectral peak in each STFT window 
214
-        rmsDbV, rms_srate, specV, specHopIdx, binHz = audio_stft_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, spectrumSmpIdx)
242
+        rmsDbV, rms_srate, specV, specHopIdx, binHz = audio_stft_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, spectrumSmpIdx)
215 243
 
216 244
         # specV[] is the spectrum of the note at spectrumSmpIdx
217 245
 
@@ -222,12 +250,12 @@ def plot_spectral_ranges( inDir, pitchL, rmsWndMs=300, rmsHopMs=30, harmN=5, dbR
222 250
         
223 251
         
224 252
 def do_td_plot( inDir ):
225
-
226 253
     rmsWndMs = 300
227 254
     rmsHopMs = 30
228 255
     dbRefWndMs = 500
229 256
     harmCandN = 5
230 257
     harmN     = 3
258
+    minAttkDb = 5.0
231 259
     
232 260
     seqFn = os.path.join( inDir, "seq.json")
233 261
     audioFn = os.path.join( inDir, "audio.wav")
@@ -241,12 +269,17 @@ def do_td_plot( inDir ):
241 269
     srate, signalM  = wavfile.read(audioFn)
242 270
     sigV  = signalM / float(0x7fff)
243 271
         
244
-    rms0DbV, rms0_srate = audio_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
272
+    rms0DbV, rms0_srate = audio_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs )
245 273
 
246
-    rmsDbV, rms_srate, binHz = audio_harm_db_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, midiPitch, harmCandN, harmN  )
274
+    rmsDbV, rms_srate, binHz = audio_harm_rms( srate, sigV, rmsWndMs, rmsHopMs, dbRefWndMs, midiPitch, harmCandN, harmN  )
247 275
     
248 276
     pkIdxL = locate_peak_indexes( rmsDbV, rms_srate, r['eventTimeL'] )
249
-        
277
+
278
+
279
+    min_pk_idx, max_pk_idx = find_min_max_peak_index( rmsDbV, pkIdxL, minAttkDb )
280
+
281
+    skipPkIdxL = find_skip_peaks( rmsDbV, pkIdxL, min_pk_idx, max_pk_idx )
282
+    
250 283
     fig,ax = plt.subplots()
251 284
     fig.set_size_inches(18.5, 10.5, forward=True)
252 285
 
@@ -255,13 +288,17 @@ def do_td_plot( inDir ):
255 288
     ax.plot( secV, rmsDbV )
256 289
     ax.plot( np.arange(0,len(rms0DbV)) / rms0_srate, rms0DbV, color="black" )
257 290
 
258
-    for begMs, endMs in r['eventTimeL']:
291
+    # print beg/end boundaries
292
+    for i,(begMs, endMs) in enumerate(r['eventTimeL']):
259 293
         ax.axvline( x=begMs/1000.0, color="green")
260 294
         ax.axvline( x=endMs/1000.0, color="red")
295
+        ax.text(begMs/1000.0, 20.0, str(i) )
261 296
 
262
-        
297
+    # plot peak markers
263 298
     for i,pki in enumerate(pkIdxL):
264
-        ax.plot( [pki / rms_srate], [ rmsDbV[pki] ], marker='.', color="black")
299
+        marker = "o" if i==min_pk_idx or i==max_pk_idx else "."
300
+        color  = "red" if i in skipPkIdxL else "black"
301
+        ax.plot( [pki / rms_srate], [ rmsDbV[pki] ], marker=marker, color=color)
265 302
 
266 303
     plt.show()
267 304
 

Loading…
Отказ
Запис