# HG changeset patch # User Chris Cannam # Date 1317420522 -3600 # Node ID 1c1e98cd1b2e536f62d8d11bbb8de2e135d1cdcd # Parent 4f6626f9ffac7c550a7963bad7ff8d2f0f404692 Fixes so as to run and, in theory, return results without crashing -- still doesn't actually produce meaningful data though diff -r 4f6626f9ffac -r 1c1e98cd1b2e AgentList.h --- a/AgentList.h Fri Sep 30 15:39:17 2011 +0100 +++ b/AgentList.h Fri Sep 30 23:08:42 2011 +0100 @@ -88,7 +88,7 @@ if (itr->phaseScore < 0.0) // already flagged for deletion continue; iterator itr2 = itr; - for (++itr2; itr != end(); ++itr) { + for (++itr2; itr2 != end(); ++itr2) { if (itr2->beatInterval - itr->beatInterval > DEFAULT_BI) break; if (fabs(itr->beatTime - itr2->beatTime) > DEFAULT_BT) @@ -168,6 +168,7 @@ double best = -1.0; Agent *bestAg = 0; for (iterator itr = begin(); itr != end(); ++itr) { + if (itr->events.empty()) continue; double startTime = itr->events.begin()->time; double conf = (itr->phaseScore + itr->tempoScore) / (useAverageSalience? (double)itr->beatCount: 1.0); diff -r 4f6626f9ffac -r 1c1e98cd1b2e BeatRootProcessor.cpp --- a/BeatRootProcessor.cpp Fri Sep 30 15:39:17 2011 +0100 +++ b/BeatRootProcessor.cpp Fri Sep 30 23:08:42 2011 +0100 @@ -18,15 +18,3 @@ bool BeatRootProcessor::silent = true; -double -BeatRootProcessor::silenceThreshold = 0.0004; - -double -BeatRootProcessor::rangeThreshold = 10; - -int -BeatRootProcessor::normaliseMode = 2; - -//int -//BeatRootProcessor::energyOversampleFactor = 2; - diff -r 4f6626f9ffac -r 1c1e98cd1b2e BeatRootProcessor.h --- a/BeatRootProcessor.h Fri Sep 30 15:39:17 2011 +0100 +++ b/BeatRootProcessor.h Fri Sep 30 23:08:42 2011 +0100 @@ -51,15 +51,6 @@ /** The size of an FFT frame in samples (see fftTime) */ int fftSize; - /** The number of overlapping frames of audio data which have been read. */ - int frameCount; - - /** RMS amplitude of the current frame. */ - double frameRMS; - - /** Long term average frame energy (in frequency domain representation). */ - double ltAverage; - /** Spectral flux onset detection function, indexed by frame. */ vector spectralFlux; @@ -79,16 +70,7 @@ /** The magnitude spectrum of the most recent frame. Used for * calculating the spectral flux. */ vector prevFrame; - - /** The magnitude spectrum of the current frame. */ - vector newFrame; - /** The magnitude spectra of all frames, used for plotting the spectrogram. */ - vector > frames; //!!! do we need this? much cheaper to lose it if we don't - - /** The RMS energy of all frames. */ -// vector energy; //!!! unused in beat tracking? - /** The estimated onset times from peak-picking the onset * detection function(s). */ vector onsets; @@ -99,38 +81,12 @@ /** Flag for suppressing all standard output messages except results. */ static bool silent; - /** RMS frame energy below this value results in the frame being - * set to zero, so that normalisation does not have undesired - * side-effects. */ - static double silenceThreshold; //!!!??? energy of what? should not be static? - - /** For dynamic range compression, this value is added to the log - * magnitude in each frequency bin and any remaining negative - * values are then set to zero. - */ - static double rangeThreshold; //!!! sim - - /** Determines method of normalisation. Values can be:
    - *
  • 0: no normalisation
  • - *
  • 1: normalisation by current frame energy
  • - *
  • 2: normalisation by exponential average of frame energy
  • - *
- */ - static int normaliseMode; - - /** Ratio between rate of sampling the signal energy (for the - * amplitude envelope) and the hop size */ -// static int energyOversampleFactor; //!!! not used? - public: /** Constructor: note that streams are not opened until the input * file is set (see setInputFile()). */ BeatRootProcessor(float sr) : sampleRate(sr) { - frameRMS = 0; - ltAverage = 0; - frameCount = 0; hopSize = 0; fftSize = 0; hopTime = 0.010; @@ -143,15 +99,60 @@ init(); } + /** Processes a frame of frequency-domain audio data by mapping + * the frequency bins into a part-linear part-logarithmic array, + * then computing the spectral flux then (optionally) normalising + * and calculating onsets. + */ + void processFrame(const float *const *inputBuffers) { + double flux = 0; + for (int i = 0; i <= fftSize/2; i++) { + double mag = sqrt(inputBuffers[0][i*2] * inputBuffers[0][i*2] + + inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]); + if (mag > prevFrame[i]) flux += mag - prevFrame[i]; + prevFrame[i] = mag; + } + + spectralFlux.push_back(flux); + + } // processFrame() + + /** Tracks beats once all frames have been processed by processFrame + */ + EventList beatTrack() { + + double hop = hopTime; + Peaks::normalise(spectralFlux); + vector peaks = Peaks::findPeaks(spectralFlux, (int)lrint(0.06 / hop), 0.35, 0.84, true); + onsets.clear(); + onsets.resize(peaks.size(), 0); + vector::iterator it = peaks.begin(); + onsetList.clear(); + double minSalience = Peaks::min(spectralFlux); + for (int i = 0; i < onsets.size(); i++) { + int index = *it; + ++it; + onsets[i] = index * hop; + Event e = BeatTracker::newBeat(onsets[i], 0); +// if (debug) +// System.err.printf("Onset: %8.3f %8.3f %8.3f\n", +// onsets[i], energy[index], slope[index]); +// e.salience = slope[index]; // or combination of energy + slope?? + // Note that salience must be non-negative or the beat tracking system fails! + e.salience = spectralFlux[index] - minSalience; + onsetList.push_back(e); + } + + return BeatTracker::beatTrack(onsetList); + + } // processFile() + protected: /** Allocates memory for arrays, based on parameter settings */ void init() { makeFreqMap(fftSize, sampleRate); prevFrame.clear(); - for (int i = 0; i < freqMapSize; i++) prevFrame.push_back(0); - frameCount = 0; - frameRMS = 0; - ltAverage = 0; + for (int i = 0; i <= fftSize/2; i++) prevFrame.push_back(0); spectralFlux.clear(); } // init() @@ -180,136 +181,6 @@ freqMapSize = freqMap[i-1] + 1; } // makeFreqMap() - /** Processes a frame of frequency-domain audio data by mapping - * the frequency bins into a part-linear part-logarithmic array, - * then computing the spectral flux then (optionally) normalising - * and calculating onsets. - */ - void processFrame(const float *const *inputBuffers) { - newFrame.clear(); - for (int i = 0; i < freqMapSize; i++) { - newFrame.push_back(0); - } - double flux = 0; - for (int i = 0; i <= fftSize/2; i++) { - double mag = sqrt(inputBuffers[0][i*2] * inputBuffers[0][i*2] + - inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]); - if (mag > prevFrame[i]) flux += mag - prevFrame[i]; - prevFrame[i] = mag; - newFrame[freqMap[i]] += mag; - } - spectralFlux.push_back(flux); - frames.push_back(newFrame); -// for (int i = 0; i < freqMapSize; i++) -// [frameCount][i] = newFrame[i]; -/* - int index = cbIndex - (fftSize - hopSize); - if (index < 0) - index += fftSize; - int sz = (fftSize - hopSize) / energyOversampleFactor; - for (int j = 0; j < energyOversampleFactor; j++) { - double newEnergy = 0; - for (int i = 0; i < sz; i++) { - newEnergy += circBuffer[index] * circBuffer[index]; - if (++index == fftSize) - index = 0; - } - energy[frameCount * energyOversampleFactor + j] = - newEnergy / sz <= 1e-6? 0: log(newEnergy / sz) + 13.816; - }*/ - - double decay = frameCount >= 200? 0.99: - (frameCount < 100? 0: (frameCount - 100) / 100.0); - - //!!! uh-oh -- frameRMS has not been calculated (it came from time-domain signal) -- will always appear silent - - if (ltAverage == 0) - ltAverage = frameRMS; - else - ltAverage = ltAverage * decay + frameRMS * (1.0 - decay); - if (frameRMS <= silenceThreshold) - for (int i = 0; i < freqMapSize; i++) - frames[frameCount][i] = 0; - else { - if (normaliseMode == 1) - for (int i = 0; i < freqMapSize; i++) - frames[frameCount][i] /= frameRMS; - else if (normaliseMode == 2) - for (int i = 0; i < freqMapSize; i++) - frames[frameCount][i] /= ltAverage; - for (int i = 0; i < freqMapSize; i++) { - frames[frameCount][i] = log(frames[frameCount][i]) + rangeThreshold; - if (frames[frameCount][i] < 0) - frames[frameCount][i] = 0; - } - } -// weightedPhaseDeviation(); -// if (debug) -// System.err.printf("PhaseDev: t=%7.3f phDev=%7.3f RMS=%7.3f\n", -// frameCount * hopTime, -// phaseDeviation[frameCount], -// frameRMS); - frameCount++; - } // processFrame() - - /** Processes a complete file of audio data. */ - void processFile() { -/* - while (pcmInputStream != null) { - // Profile.start(0); - processFrame(); - // Profile.log(0); - if (Thread.currentThread().isInterrupted()) { - System.err.println("info: INTERRUPTED in processFile()"); - return; - } - } -*/ -// double[] x1 = new double[phaseDeviation.length]; -// for (int i = 0; i < x1.length; i++) { -// x1[i] = i * hopTime; -// phaseDeviation[i] = (phaseDeviation[i] - 0.4) * 100; -// } -// double[] x2 = new double[energy.length]; -// for (int i = 0; i < x2.length; i++) -// x2[i] = i * hopTime / energyOversampleFactor; -// // plot.clear(); -// plot.addPlot(x1, phaseDeviation, Color.green, 7); -// plot.addPlot(x2, energy, Color.red, 7); -// plot.setTitle("Test phase deviation"); -// plot.fitAxes(); - -// double[] slope = new double[energy.length]; -// double hop = hopTime / energyOversampleFactor; -// Peaks.getSlope(energy, hop, 15, slope); -// vector peaks = Peaks.findPeaks(slope, (int)lrint(0.06 / hop), 10); - - double hop = hopTime; - Peaks::normalise(spectralFlux); - vector peaks = Peaks::findPeaks(spectralFlux, (int)lrint(0.06 / hop), 0.35, 0.84, true); - onsets.clear(); - onsets.resize(peaks.size(), 0); - vector::iterator it = peaks.begin(); - onsetList.clear(); - double minSalience = Peaks::min(spectralFlux); - for (int i = 0; i < onsets.size(); i++) { - int index = *it; - ++it; - onsets[i] = index * hop; - Event e = BeatTracker::newBeat(onsets[i], 0); -// if (debug) -// System.err.printf("Onset: %8.3f %8.3f %8.3f\n", -// onsets[i], energy[index], slope[index]); -// e.salience = slope[index]; // or combination of energy + slope?? - // Note that salience must be non-negative or the beat tracking system fails! - e.salience = spectralFlux[index] - minSalience; - onsetList.push_back(e); - } - - //!!! This onsetList is then fed in to BeatTrackDisplay::beatTrack - - } // processFile() - }; // class AudioProcessor diff -r 4f6626f9ffac -r 1c1e98cd1b2e BeatRootVampPlugin.cpp --- a/BeatRootVampPlugin.cpp Fri Sep 30 15:39:17 2011 +0100 +++ b/BeatRootVampPlugin.cpp Fri Sep 30 23:08:42 2011 +0100 @@ -16,6 +16,9 @@ #include "BeatRootVampPlugin.h" #include "BeatRootProcessor.h" +#include "Event.h" + +#include #include BeatRootVampPlugin::BeatRootVampPlugin(float inputSampleRate) : @@ -197,14 +200,29 @@ BeatRootVampPlugin::FeatureSet BeatRootVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) { - // Do actual work! + m_processor->processFrame(inputBuffers); return FeatureSet(); } BeatRootVampPlugin::FeatureSet BeatRootVampPlugin::getRemainingFeatures() { - return FeatureSet(); + EventList el = m_processor->beatTrack(); + + Feature f; + f.hasTimestamp = true; + f.hasDuration = false; + f.label = ""; + f.values.clear(); + + FeatureSet fs; + + for (int i = 0; i < el.size(); ++i) { + f.timestamp = Vamp::RealTime::frame2RealTime(el[i].time, m_inputSampleRate); + fs[0].push_back(f); + } + + return fs; }