Mercurial > hg > lowfreq
view LowFreq.cpp @ 2:a84bae4ee627
Fill in most of the implementation
author | Chris Cannam |
---|---|
date | Fri, 07 Mar 2014 08:23:48 +0000 |
parents | 411c5c28fc43 |
children | 2fc53e089662 |
line wrap: on
line source
#include "LowFreq.h" #include "dsp/rateconversion/Resampler.h" #include "dsp/transforms/FFT.h" #include <cmath> using std::cerr; using std::endl; using std::vector; static float minP = 0.01; static float maxP = 10; static float defaultP = 0.1; static int minN = 1; static int maxN = 16384; static int defaultN = 64; LowFreq::LowFreq(float inputSampleRate) : Plugin(inputSampleRate), m_p(defaultP), m_n(defaultN), m_blockSize(0), m_resampler(0), m_fft(0) { } LowFreq::~LowFreq() { delete m_resampler; delete m_fft; } string LowFreq::getIdentifier() const { return "lowfreq"; } string LowFreq::getName() const { return "Low-frequency Spectrogram"; } string LowFreq::getDescription() const { //!!! Return something helpful here! return ""; } string LowFreq::getMaker() const { return "Queen Mary, University of London"; } int LowFreq::getPluginVersion() const { return 1; } string LowFreq::getCopyright() const { return "GPL"; } LowFreq::InputDomain LowFreq::getInputDomain() const { return TimeDomain; } size_t LowFreq::getPreferredBlockSize() const { return 1024; } size_t LowFreq::getPreferredStepSize() const { return 1024; } size_t LowFreq::getMinChannelCount() const { return 1; } size_t LowFreq::getMaxChannelCount() const { return 1; } LowFreq::ParameterList LowFreq::getParameterDescriptors() const { ParameterList list; ParameterDescriptor d; d.identifier = "p"; d.name = "Shortest Period"; d.description = "Period in seconds of the highest-frequency component to include in the spectrogram. That is, 1/f where f is the highest frequency (in Hz) spanned by the spectrogram."; d.unit = "s"; d.minValue = minP; d.maxValue = maxP; d.defaultValue = defaultP; d.isQuantized = false; list.push_back(d); d.identifier = "n"; d.name = "Number of bins"; d.description = "Number of spectrogram bins to calculate."; d.unit = ""; d.minValue = minN; d.maxValue = maxN; d.defaultValue = defaultN; d.isQuantized = true; d.quantizeStep = 1; list.push_back(d); return list; } float LowFreq::getParameter(string identifier) const { if (identifier == "p") { return m_p; } else if (identifier == "n") { return m_n; } return 0; } void LowFreq::setParameter(string identifier, float value) { if (identifier == "p") { m_p = value; } else if (identifier == "n") { m_n = int(value + 0.01); } } LowFreq::ProgramList LowFreq::getPrograms() const { ProgramList list; return list; } string LowFreq::getCurrentProgram() const { return ""; // no programs } void LowFreq::selectProgram(string name) { } LowFreq::OutputList LowFreq::getOutputDescriptors() const { OutputList list; OutputDescriptor d; d.identifier = "spectrogram"; d.name = "Spectrogram"; d.description = ""; d.unit = ""; d.hasFixedBinCount = true; d.binCount = m_n/2 + 1; d.hasKnownExtents = false; d.isQuantized = false; d.sampleType = OutputDescriptor::OneSamplePerStep; d.hasDuration = false; list.push_back(d); return list; } bool LowFreq::initialise(size_t channels, size_t stepSize, size_t blockSize) { if (channels < getMinChannelCount() || channels > getMaxChannelCount()) { cerr << "LowFreq::initialise: ERROR: channels " << channels << " out of acceptable range " << getMinChannelCount() << " -> " << getMaxChannelCount() << endl; return false; } if (stepSize != blockSize) { // We don't actually care what the block size is, but there // must be no overlap cerr << "LowFreq::initialise: ERROR: step size and block size must be " << "equal (" << stepSize << " != " << blockSize << ")" << endl; return false; } if (m_n < minN || m_n > maxN) { cerr << "LowFreq::initialise: ERROR: bin count " << m_n << " out of acceptable range " << minN << " -> " << maxN << endl; return false; } if (m_p < minP || m_n > maxP) { cerr << "LowFreq::initialise: ERROR: shortest period " << m_p << " out of acceptable range " << minP << " -> " << maxP << endl; return false; } if (fabs(m_inputSampleRate - round(m_inputSampleRate)) > 1e-6) { cerr << "LowFreq::initialise: WARNING: input sample rate " << m_inputSampleRate << " is non-integral, output frequencies " << "will be skewed by rounding it to nearest integer" << endl; } m_blockSize = blockSize; reset(); return true; } void LowFreq::reset() { delete m_resampler; delete m_fft; // We have shortest period p and number of bins n. The bin // frequency for the highest bin of a spectrogram is fs/2 where fs // is the sample rate of the signal. So we must downsample to a // sample rate of (1/p)*2 and then run an n-point FFT. int targetRate = int(ceil(2.0 / m_p)); cerr << "LowFreq::reset: target rate for p = " << m_p << " is " << targetRate << endl; m_resampler = new Resampler(int(round(m_inputSampleRate)), targetRate); m_fft = new FFT(m_n); m_buffer = std::vector<double>(); } LowFreq::FeatureSet LowFreq::process(const float *const *inputBuffers, Vamp::RealTime timestamp) { double *data = new double[m_blockSize]; for (int i = 0; i < m_blockSize; ++i) { data[i] = inputBuffers[0][i]; } vector<double> resampled = m_resampler->process(data, m_blockSize); m_buffer.insert(m_buffer.end(), resampled.begin(), resampled.end()); delete[] data; //!!! ah, our processing block size and step size must be equal -- //!!! any overlap must be handled here by us FeatureSet fs; while (int(m_buffer.size()) >= m_n) { Feature f = processColumn(); fs[0].push_back(f); } return fs; } LowFreq::FeatureSet LowFreq::getRemainingFeatures() { FeatureSet fs; while (int(m_buffer.size()) >= m_n) { Feature f = processColumn(); fs[0].push_back(f); } return fs; } LowFreq::Feature LowFreq::processColumn() { Feature f; double *realOut = new double[m_n]; double *imagOut = new double[m_n]; m_fft->process(false, m_buffer.data(), 0, realOut, imagOut); for (int i = 0; i <= m_n/2; ++i) { f.values.push_back(realOut[i] * realOut[i] + imagOut[i] * imagOut[i]); } int step = m_n/2; //!!! std::vector<double> advanced(m_buffer.data() + step, m_buffer.data() + m_buffer.size()); m_buffer = advanced; return f; }