Mercurial > hg > vamp-live-host
view host/Processor.cpp @ 1:4342352b8ef3
* run more than one plugin, etc
| author | cannam |
|---|---|
| date | Fri, 20 Oct 2006 15:31:00 +0000 |
| parents | a6020bf991cd |
| children | f0e9092bd3e4 |
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, 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_nextReader(0), m_havePlugins(false), m_minBlockSize(0), m_maxBlockSize(0) { } Processor::~Processor() { m_exiting = true; wait(); } void Processor::run() { while (!m_exiting) { if (!m_havePlugins) { msleep(100); continue; } size_t nframes = 0; for (StepSizeReaderMap::iterator i = m_stepSizeReaderMap.begin(); i != m_stepSizeReaderMap.end(); ++i) { size_t here = m_audioRecordTarget->samplesReady(i->second); if (here > nframes) { nframes = here; } } if (nframes > m_minBlockSize) { if (!runPlugins()) { msleep(10); } } else { msleep(50); } } } bool Processor::runPlugins() { QMutexLocker locker(&m_mutex); static std::map<int, size_t> frame; // reader -> frame if (frame.empty()) { for (int i = 0; i < MAX_DISTINCT_STEP_SIZES; ++i) { frame[i] = 0; } } size_t sr = m_audioRecordTarget->getSourceSampleRate(); // cerr << "max block size " << m_maxBlockSize << endl; //!!! size_t ch = m_audioRecordTarget->getChannelCount(); float **buffers = new float *[ch]; float **transformed = new float *[ch]; for (size_t c = 0; c < ch; ++c) { buffers[c] = new float[m_maxBlockSize]; transformed[c] = new float[m_maxBlockSize]; } bool doneWork = false; for (StepSizePluginMap::iterator i = m_processingMap.begin(); i != m_processingMap.end(); ++i) { size_t step = i->first; if (m_stepSizeReaderMap.find(step) == m_stepSizeReaderMap.end()) { cerr << "ERROR: Unrecorded step size " << step << endl; continue; } int reader = m_stepSizeReaderMap[step]; size_t maxBlock = 0; for (BlockSizePluginMap::iterator j = i->second.begin(); j != i->second.end(); ++j) { if (j == i->second.begin() || j->first > maxBlock) { maxBlock = j->first; } } if (maxBlock == 0) { cerr << "ERROR: maxBlock == 0 for step " << step << endl; continue; } // int counter = 0; while (m_audioRecordTarget->samplesReady(reader) >= maxBlock) { // && counter < 10) { // ++counter; // cerr << "enough samples for max block " << maxBlock // << " for step " << step << endl; for (size_t c = 0; c < ch; ++c) { m_audioRecordTarget->peekSamples(c, maxBlock, buffers[c], reader); m_audioRecordTarget->skipSamples(c, step, reader); } for (BlockSizePluginMap::iterator j = i->second.begin(); j != i->second.end(); ++j) { size_t block = j->first; size_t toUse = maxBlock; size_t off = 0; while (toUse >= block) { bool haveTransformed = false; for (PluginSet::iterator k = j->second.begin(); k != j->second.end(); ++k) { // cerr << "block inner loop for block " << block // << " (toUse = " << toUse << ")" << endl; Vamp::Plugin *plugin = *k; Vamp::Plugin::FeatureSet fs; Vamp::RealTime timestamp = Vamp::RealTime::frame2RealTime(frame[reader], sr); if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { if (!haveTransformed) { for (size_t c = 0; c < ch; ++c) { for (size_t s = 0; s < block; ++s) { transformed[c][s] = buffers[c][s + off]; } transformInput(transformed[c], block); } haveTransformed = true; } // cerr << "running " << plugin->getName() << " (transformed) frame = " << frame[reader] << endl; fs = plugin->process(transformed, timestamp); } else { // cerr << "running " << plugin->getName() << " frame = " << frame[reader] << endl; float *tmp[10]; for (size_t c = 0; c < ch; ++c) { tmp[c] = buffers[c] + off; fs = plugin->process(tmp, timestamp); } } for (Vamp::Plugin::FeatureSet::iterator fi = fs.begin(); fi != fs.end(); ++fi) { printFeatures(int(plugin), frame[reader], sr, fi->first, fs); } doneWork = true; } toUse -= block; off += block; } } frame[reader] += step; } } for (size_t c = 0; c < ch; ++c) { delete[] buffers[c]; delete[] transformed[c]; } delete[] buffers; delete[] transformed; return doneWork; } 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 block = plugin->getPreferredBlockSize(); if (block == 0) block = m_audioRecordTarget->getSourceBlockSize(); size_t step = plugin->getPreferredStepSize(); if (step == 0) { if (plugin->getInputDomain() == Vamp::Plugin::TimeDomain) { step = block; } else { step = block/2; } } if (m_stepSizeReaderMap.find(step) == m_stepSizeReaderMap.end()) { if (m_nextReader == MAX_DISTINCT_STEP_SIZES) { cerr << "ERROR: Processor::addPlugin: Run out of distinct step size slots: increase MAX_DISTINCT_STEP_SIZES and recompile" << endl; delete plugin; return 0; } m_stepSizeReaderMap[step] = m_nextReader++; } size_t ch = m_audioRecordTarget->getChannelCount(); if (ch > plugin->getMaxChannelCount()) ch = plugin->getMaxChannelCount(); if (!plugin->initialise(ch, step, block)) { cerr << "ERROR: Processor::addPlugin: Initialisation failed with step size " << step << ", block size " << block << ", channels " << ch << endl; delete plugin; return 0; } if (!m_havePlugins || block < m_minBlockSize) m_minBlockSize = block; if (!m_havePlugins || block > m_maxBlockSize) m_maxBlockSize = block; int number = m_nextNumber++; m_plugins[number] = plugin; m_processingMap[step][block].insert(plugin); m_havePlugins = true; 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]; bool done = false; for (StepSizePluginMap::iterator i = m_processingMap.begin(); i != m_processingMap.end(); ++i) { BlockSizePluginMap::iterator j; for (j = i->second.begin(); j != i->second.end(); ++j) { if (j->second.find(plugin) != j->second.end()) { j->second.erase(plugin); if (j->second.empty()) { // no plugins with this step & block i->second.erase(j->first); if (i->second.empty()) { // no plugins with this step m_processingMap.erase(i->first); m_stepSizeReaderMap.erase(i->first); //!!! need to make it possible to use that //reader again, but we can't without having a //reader bitset rather than a next reader //count } } done = true; break; } } if (done) break; } m_plugins.erase(number); if (m_plugins.empty()) m_havePlugins = false; delete plugin; } void printFeatures(int plugno, 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 << plugno << ":" << output << " -" << 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; } } }
