Mercurial > hg > vamp-live-host
view host/Processor.cpp @ 0:a6020bf991cd
* Initial import of what may or may not become a simple live visual-response
host for causal Vamp plugins
author | cannam |
---|---|
date | Thu, 19 Oct 2006 16:53:48 +0000 |
parents | |
children | 4342352b8ef3 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ #include "Processor.h" #include "plugin/FeatureExtractionPluginFactory.h" using std::cout; using std::cerr; using std::endl; void printFeatures(int, int, int, Vamp::Plugin::FeatureSet &); void transformInput(float *, size_t); void fft(unsigned int, bool, double *, double *, double *, double *); Processor::Processor(BufferingAudioCallbackRecordTarget *audioRecordTarget) : m_exiting(false), m_audioRecordTarget(audioRecordTarget), m_nextNumber(1), m_pluginBlockSize(0) { } Processor::~Processor() { m_exiting = true; wait(); } void Processor::run() { while (!m_exiting) { size_t bs = m_pluginBlockSize; if (bs == 0) { msleep(100); continue; } size_t nframes = m_audioRecordTarget->samplesReady(); cout << "Have " << nframes << endl; if (nframes > bs) { runPlugins(); nframes = m_audioRecordTarget->samplesReady(); if (nframes > 0) msleep(10); else msleep(50); } else { msleep(50); } } } void Processor::runPlugins() { QMutexLocker locker(&m_mutex); static size_t frame = 0; size_t bs = m_pluginBlockSize; size_t sr = m_audioRecordTarget->getSourceSampleRate(); size_t ch = m_audioRecordTarget->getChannelCount(); float **buffers = new float *[ch]; for (size_t c = 0; c < ch; ++c) { buffers[c] = new float[bs]; if (m_audioRecordTarget->getSamples(c, bs, buffers[c]) < bs) { cerr << "ERROR: not enough samples from record in" << endl; } } // run one plugin for now -- question -- can the plugin modify its input buffers? PluginMap::iterator i = m_plugins.begin(); if (i != m_plugins.end()) { for (size_t c = 0; c < ch; ++c) { if (i->second->getInputDomain() == Vamp::Plugin::FrequencyDomain) { transformInput(buffers[c], bs); } } Vamp::Plugin::FeatureSet fs = i->second->process(buffers, Vamp::RealTime::frame2RealTime(frame, sr)); for (Vamp::Plugin::FeatureSet::iterator j = fs.begin(); j != fs.end(); ++j) { printFeatures(frame, sr, j->first, fs); } } frame += bs; for (size_t c = 0; c < ch; ++c) { delete[] buffers[c]; } delete[] buffers; } int Processor::addPlugin(QString pluginId) { QMutexLocker locker(&m_mutex); size_t sr = m_audioRecordTarget->getSourceSampleRate(); if (!sr) { cerr << "ERROR: Processor::addPlugin: Source sample rate is not defined" << endl; return 0; } FeatureExtractionPluginFactory *factory = FeatureExtractionPluginFactory::instanceFor(pluginId); if (!factory) { cerr << "ERROR: Processor::addPlugin: No factory for plugin \"" << pluginId.toStdString() << "\"" << endl; return 0; } Vamp::Plugin *plugin = factory->instantiatePlugin(pluginId, sr); if (!plugin) { cerr << "ERROR: Processor::addPlugin: Failed to instantiate plugin \"" << pluginId.toStdString() << "\"" << endl; return 0; } size_t bs = plugin->getPreferredBlockSize(); if (m_pluginBlockSize != 0) bs = m_pluginBlockSize; if (bs == 0) bs = m_audioRecordTarget->getSourceBlockSize(); size_t step = bs; //!!! fix -- separate peek and advance in bufferer int ch = m_audioRecordTarget->getChannelCount(); if (ch > plugin->getMaxChannelCount()) ch = plugin->getMaxChannelCount(); if (!plugin->initialise(ch, bs, step)) { cerr << "ERROR: Processor::addPlugin: Initialisation failed with step size " << step << ", block size " << bs << ", channels " << ch << endl; delete plugin; return 0; } m_pluginBlockSize = bs; int number = m_nextNumber++; m_plugins[number] = plugin; return number; } void Processor::removePlugin(int number) { QMutexLocker locker(&m_mutex); if (m_plugins.find(number) == m_plugins.end()) { cerr << "ERROR: Processor::removePlugin: No such plugin number " << number << endl; return; } Vamp::Plugin *plugin = m_plugins[number]; m_plugins.erase(number); delete plugin; } void printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet &features) { for (unsigned int i = 0; i < features[output].size(); ++i) { Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr); if (features[output][i].hasTimestamp) { rt = features[output][i].timestamp; } cout << rt.toString() << ":"; for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { cout << " " << features[output][i].values[j]; } cout << endl; } } void transformInput(float *buffer, size_t size) { double *inbuf = new double[size * 2]; double *outbuf = new double[size * 2]; // Copy across with Hanning window for (size_t i = 0; i < size; ++i) { inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size)); inbuf[i + size] = 0.0; } for (size_t i = 0; i < size/2; ++i) { double temp = inbuf[i]; inbuf[i] = inbuf[i + size/2]; inbuf[i + size/2] = temp; } fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size); for (size_t i = 0; i < size/2; ++i) { buffer[i * 2] = outbuf[i]; buffer[i * 2 + 1] = outbuf[i + size]; } delete inbuf; delete outbuf; } void fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io) { if (!ri || !ro || !io) return; unsigned int bits; unsigned int i, j, k, m; unsigned int blockSize, blockEnd; double tr, ti; if (n < 2) return; if (n & (n-1)) return; double angle = 2.0 * M_PI; if (inverse) angle = -angle; for (i = 0; ; ++i) { if (n & (1 << i)) { bits = i; break; } } static unsigned int tableSize = 0; static int *table = 0; if (tableSize != n) { delete[] table; table = new int[n]; for (i = 0; i < n; ++i) { m = i; for (j = k = 0; j < bits; ++j) { k = (k << 1) | (m & 1); m >>= 1; } table[i] = k; } tableSize = n; } if (ii) { for (i = 0; i < n; ++i) { ro[table[i]] = ri[i]; io[table[i]] = ii[i]; } } else { for (i = 0; i < n; ++i) { ro[table[i]] = ri[i]; io[table[i]] = 0.0; } } blockEnd = 1; for (blockSize = 2; blockSize <= n; blockSize <<= 1) { double delta = angle / (double)blockSize; double sm2 = -sin(-2 * delta); double sm1 = -sin(-delta); double cm2 = cos(-2 * delta); double cm1 = cos(-delta); double w = 2 * cm1; double ar[3], ai[3]; for (i = 0; i < n; i += blockSize) { ar[2] = cm2; ar[1] = cm1; ai[2] = sm2; ai[1] = sm1; for (j = i, m = 0; m < blockEnd; j++, m++) { ar[0] = w * ar[1] - ar[2]; ar[2] = ar[1]; ar[1] = ar[0]; ai[0] = w * ai[1] - ai[2]; ai[2] = ai[1]; ai[1] = ai[0]; k = j + blockEnd; tr = ar[0] * ro[k] - ai[0] * io[k]; ti = ar[0] * io[k] + ai[0] * ro[k]; ro[k] = ro[j] - tr; io[k] = io[j] - ti; ro[j] += tr; io[j] += ti; } } blockEnd = blockSize; } if (inverse) { double denom = (double)n; for (i = 0; i < n; i++) { ro[i] /= denom; io[i] /= denom; } } }