From 0aaf61396643d7884b792b6d1a053c7dae7390b2 Mon Sep 17 00:00:00 2001 From: John Glover Date: Fri, 24 Dec 2010 12:37:39 +0000 Subject: Updated MQ and SndObj peak detection and partial tracking to simpl 0.2 --- mq.py | 2 +- sndobj.py | 46 +++++------ sndobj/SinAnal.cpp | 230 +++++++++++++++++++++++++++++------------------------ 3 files changed, 144 insertions(+), 134 deletions(-) diff --git a/mq.py b/mq.py index 537b383..8640eab 100644 --- a/mq.py +++ b/mq.py @@ -144,7 +144,7 @@ class MQPeakDetection(simpl.PeakDetection): self._max_peaks peaks.""" self._current_peaks = [] # fft of frame - f = np.fft.rfft(frame * self._window) + f = np.fft.rfft(frame.audio * self._window) spectrum = abs(f) # find all peaks in the spectrum prev_mag = np.abs(spectrum[0]) diff --git a/sndobj.py b/sndobj.py index 8f279b3..2159028 100644 --- a/sndobj.py +++ b/sndobj.py @@ -75,8 +75,8 @@ class SndObjPeakDetection(simpl.PeakDetection): def find_peaks_in_frame(self, frame): "Find and return all spectral peaks in a given frame of audio" - current_peaks = [] - self._input.PushIn(frame) + peaks = [] + self._input.PushIn(frame.audio) self._input.DoProcess() self._ifgram.DoProcess() num_peaks_found = self._analysis.FindPeaks() @@ -86,24 +86,24 @@ class SndObjPeakDetection(simpl.PeakDetection): p.amplitude = self._analysis.Output(i*3) p.frequency = self._analysis.Output((i*3)+1) p.phase = self._analysis.Output((i*3)+2) - if not current_peaks: - current_peaks.append(p) + if not peaks: + peaks.append(p) else: - if np.abs(p.frequency - current_peaks[-1].frequency) > self._min_peak_separation: - current_peaks.append(p) + if np.abs(p.frequency - peaks[-1].frequency) > self._min_peak_separation: + peaks.append(p) else: - if p.amplitude > current_peaks[-1].amplitude: - current_peaks.remove(current_peaks[-1]) - current_peaks.append(p) - return current_peaks + if p.amplitude > peaks[-1].amplitude: + peaks.remove(peaks[-1]) + peaks.append(p) + return peaks class SndObjPartialTracking(simpl.PartialTracking): "Partial tracking using the algorithm from the Sound Object Library" def __init__(self): simpl.PartialTracking.__init__(self) - self._threshold = 0.003 # todo: property - self._num_bins = 1025 # todo: property + self._threshold = 0.003 # TODO: make this a property + self._num_bins = 1025 # TODO: make this a property self._analysis = simplsndobj.SinAnal(simplsndobj.SndObj(), self._num_bins, self._threshold, self.max_partials) @@ -111,16 +111,16 @@ class SndObjPartialTracking(simpl.PartialTracking): self._analysis.Set("max tracks", num_partials) self._max_partials = num_partials - def update_partials(self, frame, frame_number): + def update_partials(self, frame): "Streamable (real-time) partial-tracking." - frame_partials = [] + partials = [] # load Peak amplitudes, frequencies and phases into arrays - num_peaks = len(frame) + num_peaks = len(frame.peaks) amps = simpl.zeros(num_peaks) freqs = simpl.zeros(num_peaks) phases = simpl.zeros(num_peaks) for i in range(num_peaks): - peak = frame[i] + peak = frame.peaks[i] amps[i] = peak.amplitude freqs[i] = peak.frequency phases[i] = peak.phase @@ -135,18 +135,8 @@ class SndObjPartialTracking(simpl.PartialTracking): peak.amplitude = self._analysis.Output(i*3) peak.frequency = self._analysis.Output((i*3)+1) peak.phase = self._analysis.Output((i*3)+2) - id = self._analysis.GetTrackID(i) - # if this is a continuing partial, create a peak and append it - if id >= 0 and id <= len(self.partials) - 1: - self.partials[id].add_peak(peak) - # if not, make a new partial - else: - partial = simpl.Partial() - partial.starting_frame = frame_number - partial.add_peak(peak) - self.partials.append(partial) - frame_partials.append(peak) - return frame_partials + partials.append(peak) + return partials class SimplSndObjAnalysisWrapper(simplsndobj.SinAnal): diff --git a/sndobj/SinAnal.cpp b/sndobj/SinAnal.cpp index 510d2db..e5c19c7 100644 --- a/sndobj/SinAnal.cpp +++ b/sndobj/SinAnal.cpp @@ -57,14 +57,14 @@ SinAnal::SinAnal(SndObj* input, double threshold, int maxtracks, m_numpeaks = 0; m_numbins = ((FFT *)m_input)->GetFFTSize()/2 + 1; - m_bndx = new double*[minpoints+2]; - m_pkmags = new double*[minpoints+2]; - m_adthresh = new double*[minpoints+2]; - m_tstart = new unsigned int*[minpoints+2]; - m_lastpk = new unsigned int*[minpoints+2]; - m_trkid = new unsigned int*[minpoints+2]; + m_bndx = new double*[m_minpoints+2]; + m_pkmags = new double*[m_minpoints+2]; + m_adthresh = new double*[m_minpoints+2]; + m_tstart = new unsigned int*[m_minpoints+2]; + m_lastpk = new unsigned int*[m_minpoints+2]; + m_trkid = new unsigned int*[m_minpoints+2]; int i; - for(i = 0; i < minpoints+2; i++){ + for(i = 0; i < m_minpoints+2; i++){ m_bndx[i] = new double[m_maxtracks]; memset(m_bndx[i], 0, sizeof(double) * m_maxtracks); m_pkmags[i] = new double[m_maxtracks]; @@ -129,20 +129,20 @@ SinAnal::SinAnal(SndObj* input, int numbins, double threshold, int maxtracks, m_numpeaks = 0; m_numbins = numbins; - m_bndx = new double*[minpoints+2]; - m_pkmags = new double*[minpoints+2]; - m_adthresh = new double*[minpoints+2]; - m_tstart = new unsigned int*[minpoints+2]; - m_lastpk = new unsigned int*[minpoints+2]; - m_trkid = new unsigned int*[minpoints+2]; + m_bndx = new double*[m_minpoints+2]; + m_pkmags = new double*[m_minpoints+2]; + m_adthresh = new double*[m_minpoints+2]; + m_tstart = new unsigned int*[m_minpoints+2]; + m_lastpk = new unsigned int*[m_minpoints+2]; + m_trkid = new unsigned int*[m_minpoints+2]; int i; - for(i=0; i tmp2 ? tmp1 : tmp2); - } // else - } // if difference - // if check - } + // if difference smaller than 1 bin + double tempf = F - m_binmax[bestix]; + tempf = (tempf < 0 ? -tempf : tempf); + if(tempf < 1.){ + // if amp jump is too great (check) + if(m_adthresh[m_prev][j] < + (dbstep = 20*log10(m_magmax[bestix]/m_pkmags[m_prev][j]))){ + // mark for discontinuation; + m_contflag[j] = false; + } + else{ + m_bndx[m_prev][j] = m_binmax[bestix]; + m_pkmags[m_prev][j] = m_magmax[bestix]; + // track index keeps track history + // so we know which ones continue + m_contflag[j] = true; + m_binmax[bestix] = m_magmax[bestix] = 0.f; + m_lastpk[m_prev][j] = m_timecount; + foundcont = 1; + count++; + + // update the adaptive mag threshold + double tmp1 = dbstep*1.5f; + double tmp2 = m_adthresh[m_prev][j] - + (m_adthresh[m_prev][j] - 1.5f)*0.048770575f; + m_adthresh[m_prev][j] = (tmp1 > tmp2 ? tmp1 : tmp2); + } // else + } // if difference + } // if check // if we did not find a continuation // we'll check if the magnitudes around it are below @@ -511,17 +536,14 @@ SinAnal::PartialTracking(){ // old if(!foundcont){ if((exp(m_mags[int(m_bndx[m_prev][j]+0.5)]) < 0.2*m_pkmags[m_prev][j]) - || ((m_timecount - m_lastpk[m_prev][j]) > (unsigned int) m_maxgap)) - { + || ((m_timecount - m_lastpk[m_prev][j]) > (unsigned int) m_maxgap)){ m_contflag[j] = false; - - } else { + } + else{ m_contflag[j] = true; count++; } - } - } // for loop // compress the arrays @@ -544,9 +566,9 @@ SinAnal::PartialTracking(){ // create new tracks for all new peaks for(j=0; j< m_numbins && count < m_maxtracks; j++){ if(m_magmax[j] > m_startupThresh){ - m_bndx[m_cur][count] = m_binmax[j]; - m_pkmags[m_cur][count] = m_magmax[j]; - m_adthresh[m_cur][count] = 400.f; + m_bndx[m_cur][count] = m_binmax[j]; + m_pkmags[m_cur][count] = m_magmax[j]; + m_adthresh[m_cur][count] = 400.f; // track ID is a positive number in the // range of 0 - maxtracks*3 - 1 // it is given when the track starts @@ -567,16 +589,15 @@ SinAnal::PartialTracking(){ // count is the number of continuing tracks + new tracks // now we check for tracks that have been there for more // than minpoints hop periods and output them - m_tracks = 0; for(i=0; i < count; i++){ int curpos = m_timecount-m_minpoints; if(curpos >= 0 && m_tstart[m_cur][i] <= (unsigned int)curpos){ int tpoint = m_cur-m_minpoints; - - if(tpoint < 0) { + if(tpoint < 0){ tpoint += m_minpoints+2; } + m_bins[i] = m_bndx[tpoint][i]; m_mags[i] = m_pkmags[tpoint][i]; m_trndx[i] = m_trkid[tpoint][i]; @@ -586,9 +607,8 @@ SinAnal::PartialTracking(){ // end track-selecting // current arrays become previous - //int tmp = m_prev; - m_prev = m_cur; - m_cur = (m_cur < m_minpoints+1 ? m_cur+1 : 0); + m_prev = m_cur; + m_cur = (m_cur < m_minpoints+1 ? m_cur+1 : 0); m_timecount++; // Output -- cgit v1.2.3