void enumeratePlugins(Verbosity verbosity) { PluginLoader *loader = PluginLoader::getInstance(); if (verbosity == PluginInformation) { cout << "\nVamp plugin libraries found in search path:" << endl; } vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); typedef multimap<string, PluginLoader::PluginKey> LibraryMap; LibraryMap libraryMap; for (size_t i = 0; i < plugins.size(); ++i) { string path = loader->getLibraryPathForPlugin(plugins[i]); libraryMap.insert(LibraryMap::value_type(path, plugins[i])); } string prevPath = ""; int index = 0; for (LibraryMap::iterator i = libraryMap.begin(); i != libraryMap.end(); ++i) { string path = i->first; PluginLoader::PluginKey key = i->second; if (path != prevPath) { prevPath = path; index = 0; if (verbosity == PluginInformation) { cout << "\n " << path << ":" << endl; } else if (verbosity == PluginInformationDetailed) { string::size_type ki = i->second.find(':'); string text = "Library \"" + i->second.substr(0, ki) + "\""; cout << "\n" << header(text, 1); } } Plugin *plugin = loader->loadPlugin(key, 48000); if (plugin) { char c = char('A' + index); if (c > 'Z') c = char('a' + (index - 26)); PluginLoader::PluginCategoryHierarchy category = loader->getPluginCategory(key); string catstr; if (!category.empty()) { for (size_t ci = 0; ci < category.size(); ++ci) { if (ci > 0) catstr += " > "; catstr += category[ci]; } } if (verbosity == PluginInformation) { cout << " [" << c << "] [v" << plugin->getVampApiVersion() << "] " << plugin->getName() << ", \"" << plugin->getIdentifier() << "\"" << " [" << plugin->getMaker() << "]" << endl; if (catstr != "") { cout << " > " << catstr << endl; } if (plugin->getDescription() != "") { cout << " - " << plugin->getDescription() << endl; } } else if (verbosity == PluginInformationDetailed) { cout << header(plugin->getName(), 2); cout << " - Identifier: " << key << endl; cout << " - Plugin Version: " << plugin->getPluginVersion() << endl; cout << " - Vamp API Version: " << plugin->getVampApiVersion() << endl; cout << " - Maker: \"" << plugin->getMaker() << "\"" << endl; cout << " - Copyright: \"" << plugin->getCopyright() << "\"" << endl; cout << " - Description: \"" << plugin->getDescription() << "\"" << endl; cout << " - Input Domain: " << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ? "Time Domain" : "Frequency Domain") << endl; cout << " - Default Step Size: " << plugin->getPreferredStepSize() << endl; cout << " - Default Block Size: " << plugin->getPreferredBlockSize() << endl; cout << " - Minimum Channels: " << plugin->getMinChannelCount() << endl; cout << " - Maximum Channels: " << plugin->getMaxChannelCount() << endl; } else if (verbosity == PluginIds) { cout << "vamp:" << key << endl; } Plugin::OutputList outputs = plugin->getOutputDescriptors(); if (verbosity == PluginInformationDetailed) { Plugin::ParameterList params = plugin->getParameterDescriptors(); for (size_t j = 0; j < params.size(); ++j) { Plugin::ParameterDescriptor &pd(params[j]); cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl; cout << " - Identifier: " << pd.identifier << endl; cout << " - Description: \"" << pd.description << "\"" << endl; if (pd.unit != "") { cout << " - Unit: " << pd.unit << endl; } cout << " - Range: "; cout << pd.minValue << " -> " << pd.maxValue << endl; cout << " - Default: "; cout << pd.defaultValue << endl; if (pd.isQuantized) { cout << " - Quantize Step: " << pd.quantizeStep << endl; } if (!pd.valueNames.empty()) { cout << " - Value Names: "; for (size_t k = 0; k < pd.valueNames.size(); ++k) { if (k > 0) cout << ", "; cout << "\"" << pd.valueNames[k] << "\""; } cout << endl; } } if (outputs.empty()) { cout << "\n** Note: This plugin reports no outputs!" << endl; } for (size_t j = 0; j < outputs.size(); ++j) { Plugin::OutputDescriptor &od(outputs[j]); cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl; cout << " - Identifier: " << od.identifier << endl; cout << " - Description: \"" << od.description << "\"" << endl; if (od.unit != "") { cout << " - Unit: " << od.unit << endl; } if (od.hasFixedBinCount) { cout << " - Default Bin Count: " << od.binCount << endl; } if (!od.binNames.empty()) { bool have = false; for (size_t k = 0; k < od.binNames.size(); ++k) { if (od.binNames[k] != "") { have = true; break; } } if (have) { cout << " - Bin Names: "; for (size_t k = 0; k < od.binNames.size(); ++k) { if (k > 0) cout << ", "; cout << "\"" << od.binNames[k] << "\""; } cout << endl; } } if (od.hasKnownExtents) { cout << " - Default Extents: "; cout << od.minValue << " -> " << od.maxValue << endl; } if (od.isQuantized) { cout << " - Quantize Step: " << od.quantizeStep << endl; } cout << " - Sample Type: " << (od.sampleType == Plugin::OutputDescriptor::OneSamplePerStep ? "One Sample Per Step" : od.sampleType == Plugin::OutputDescriptor::FixedSampleRate ? "Fixed Sample Rate" : "Variable Sample Rate") << endl; if (od.sampleType != Plugin::OutputDescriptor::OneSamplePerStep) { cout << " - Default Rate: " << od.sampleRate << endl; } cout << " - Has Duration: " << (od.hasDuration ? "Yes" : "No") << endl; } } if (outputs.size() > 1 || verbosity == PluginOutputIds) { for (size_t j = 0; j < outputs.size(); ++j) { if (verbosity == PluginInformation) { cout << " (" << j << ") " << outputs[j].name << ", \"" << outputs[j].identifier << "\"" << endl; if (outputs[j].description != "") { cout << " - " << outputs[j].description << endl; } } else if (verbosity == PluginOutputIds) { cout << "vamp:" << key << ":" << outputs[j].identifier << endl; } } } ++index; delete plugin; } } if (verbosity == PluginInformation || verbosity == PluginInformationDetailed) { cout << endl; } }
int runPlugin(string myname, string soname, string id, string output, int outputNo, string wavname, string outfilename, bool useFrames, map<string,float> parameters) { PluginLoader *loader = PluginLoader::getInstance(); PluginLoader::PluginKey key = loader->composePluginKey(soname, id); SNDFILE *sndfile; SF_INFO sfinfo; memset(&sfinfo, 0, sizeof(SF_INFO)); if (wavname == "") sndfile = sf_open_fd(0, SFM_READ, &sfinfo, true); else sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); if (!sndfile) { cerr << myname << ": ERROR: Failed to open input file \"" << wavname << "\": " << sf_strerror(sndfile) << endl; return 1; } ofstream *out = 0; if (outfilename != "") { out = new ofstream(outfilename.c_str(), ios::out); if (!*out) { cerr << myname << ": ERROR: Failed to open output file \"" << outfilename << "\" for writing" << endl; delete out; return 1; } } Plugin *plugin = loader->loadPlugin (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE); if (!plugin) { cerr << myname << ": ERROR: Failed to load plugin \"" << id << "\" from library \"" << soname << "\"" << endl; sf_close(sndfile); if (out) { out->close(); delete out; } return 1; } cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; // parameters for (map<string,float>::iterator iter = parameters.begin(); iter!=parameters.end(); iter++) { plugin->setParameter(iter->first, iter->second); cerr << "Set parameter " << iter->first << " = " << iter->second << endl; } // Note that the following would be much simpler if we used a // PluginBufferingAdapter as well -- i.e. if we had passed // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead // of ADAPT_ALL_SAFE. Then we could simply specify our own block // size, keep the step size equal to the block size, and ignore // the plugin's bleatings. However, there are some issues with // using a PluginBufferingAdapter that make the results sometimes // technically different from (if effectively the same as) the // un-adapted plugin, so we aren't doing that here. See the // PluginBufferingAdapter documentation for details. int blockSize = plugin->getPreferredBlockSize(); int stepSize = plugin->getPreferredStepSize(); if (blockSize == 0) { blockSize = 1024; } if (stepSize == 0) { if (plugin->getInputDomain() == Plugin::FrequencyDomain) { stepSize = blockSize/2; } else { stepSize = blockSize; } } else if (stepSize > blockSize) { cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; if (plugin->getInputDomain() == Plugin::FrequencyDomain) { blockSize = stepSize * 2; } else { blockSize = stepSize; } cerr << blockSize << endl; } int overlapSize = blockSize - stepSize; sf_count_t currentStep = 0; int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF int channels = sfinfo.channels; float *filebuf = new float[blockSize * channels]; float **plugbuf = new float*[channels]; for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; cerr << "Using block size = " << blockSize << ", step size = " << stepSize << endl; // The channel queries here are for informational purposes only -- // a PluginChannelAdapter is being used automatically behind the // scenes, and it will take case of any channel mismatch int minch = plugin->getMinChannelCount(); int maxch = plugin->getMaxChannelCount(); cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; Plugin::OutputList outputs = plugin->getOutputDescriptors(); Plugin::OutputDescriptor od; int returnValue = 1; int progress = 0; RealTime rt; PluginWrapper *wrapper = 0; RealTime adjustment = RealTime::zeroTime; if (outputs.empty()) { cerr << "ERROR: Plugin has no outputs!" << endl; goto done; } if (outputNo < 0) { for (size_t oi = 0; oi < outputs.size(); ++oi) { if (outputs[oi].identifier == output) { outputNo = oi; break; } } if (outputNo < 0) { cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; goto done; } } else { if (int(outputs.size()) <= outputNo) { cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; goto done; } } od = outputs[outputNo]; cerr << "Output is: \"" << od.identifier << "\"" << endl; if (!plugin->initialise(channels, stepSize, blockSize)) { cerr << "ERROR: Plugin initialise (channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << ") failed." << endl; goto done; } wrapper = dynamic_cast<PluginWrapper *>(plugin); if (wrapper) { // See documentation for // PluginInputDomainAdapter::getTimestampAdjustment PluginInputDomainAdapter *ida = wrapper->getWrapper<PluginInputDomainAdapter>(); if (ida) adjustment = ida->getTimestampAdjustment(); } // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input. do { int count; if ((blockSize==stepSize) || (currentStep==0)) { // read a full fresh block if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; break; } if (count != blockSize) --finalStepsRemaining; } else { // otherwise shunt the existing data down and read the remainder. memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float)); if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) { cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; break; } if (count != stepSize) --finalStepsRemaining; count += overlapSize; } for (int c = 0; c < channels; ++c) { int j = 0; while (j < count) { plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; ++j; } while (j < blockSize) { plugbuf[c][j] = 0.0f; ++j; } } rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); printFeatures (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt), out, useFrames); if (sfinfo.frames > 0){ int pp = progress; progress = (int)((float(currentStep * stepSize) / sfinfo.frames) * 100.f + 0.5f); if (progress != pp && out) { cerr << "\r" << progress << "%"; } } ++currentStep; } while (finalStepsRemaining > 0); if (out) cerr << "\rDone" << endl; rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), sfinfo.samplerate, outputNo, plugin->getRemainingFeatures(), out, useFrames); returnValue = 0; done: delete plugin; if (out) { out->close(); delete out; } sf_close(sndfile); return returnValue; }
int runPlugin(string myname, string soname, string id, string output, int outputNo, bool useFrames, PaStreamParameters inputParameters) { float *recordedSamples; float *fifo; PaStream* stream; PaError err = paNoError; int elapsed = 0; int returnValue = 1; RealTime rt; PluginWrapper *wrapper = 0; RealTime adjustment = RealTime::zeroTime; PluginLoader *loader = PluginLoader::getInstance(); PluginLoader::PluginKey key = loader->composePluginKey(soname, id); // load plugin Plugin *plugin = loader->loadPlugin(key, SAMPLE_RATE, PluginLoader::ADAPT_ALL_SAFE); if (!plugin) { cerr << myname << ": ERROR: Failed to load plugin \"" << id << "\" from library \"" << soname << "\"" << endl; return 1; } // Find block/step size int blockSize = plugin->getPreferredBlockSize(); int stepSize = plugin->getPreferredStepSize(); if (blockSize == 0) { blockSize = 1024; } if (stepSize == 0) { if (plugin->getInputDomain() == Plugin::FrequencyDomain) { stepSize = blockSize/2; } else { stepSize = blockSize; } } else if (stepSize > blockSize) { cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; if (plugin->getInputDomain() == Plugin::FrequencyDomain) { blockSize = stepSize * 2; } else { blockSize = stepSize; } cerr << blockSize << endl; } // set up port audio fifo = new float[blockSize](); recordedSamples = new float[stepSize](); ofstream *out = 0; cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; cerr << "Using block size = " << blockSize << ", step size = " << stepSize << endl; // display output name Plugin::OutputList outputs = plugin->getOutputDescriptors(); Plugin::OutputDescriptor od; if (outputs.empty()) { cerr << "ERROR: Plugin has no outputs!" << endl; goto done; } if (outputNo < 0) { for (size_t oi = 0; oi < outputs.size(); ++oi) { if (outputs[oi].identifier == output) { outputNo = oi; break; } } if (outputNo < 0) { cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; goto done; } } else { if (int(outputs.size()) <= outputNo) { cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; goto done; } } od = outputs[outputNo]; cerr << "Output is: \"" << od.identifier << "\"" << endl; // Initialise plugin if (!plugin->initialise(1, stepSize, blockSize)) { cerr << "ERROR: Plugin initialise (stepSize = " << stepSize << ", blockSize = " << blockSize << ") failed." << endl; goto done; } // Compensate timestamp if in freq domain wrapper = dynamic_cast<PluginWrapper *>(plugin); if (wrapper) { PluginInputDomainAdapter *ida = wrapper->getWrapper<PluginInputDomainAdapter>(); if (ida) adjustment = ida->getTimestampAdjustment(); } // Open portaudio stream err = Pa_OpenStream( &stream, &inputParameters, NULL, SAMPLE_RATE, stepSize, paClipOff, NULL, NULL ); if( err != paNoError ) throwError(err); // Start the audio stream err = Pa_StartStream( stream ); if( err != paNoError ) throwError(err); // printf("Now recording!!\n"); fflush(stdout); // do until interruptFlag is true while (1) { // read step of audio data err = Pa_ReadStream( stream, recordedSamples, stepSize ); if( err != paNoError ) throwError(err); // shift buffer along a step size for (int i=stepSize; i<blockSize; i++) fifo[i-stepSize] = fifo[i]; // add new step onto end for (int i=0; i<stepSize; i++) fifo[blockSize-stepSize+i] = recordedSamples[i]; // process and print features rt = RealTime::frame2RealTime(elapsed*stepSize, SAMPLE_RATE); printFeatures(RealTime::realTime2Frame(rt + adjustment, SAMPLE_RATE), SAMPLE_RATE, outputNo, plugin->process(&fifo, rt), out, useFrames); // note number of blocks processed elapsed++; // break out of loop if (interruptFlag) break; } // stop the audio stream err = Pa_CloseStream( stream ); if( err != paNoError ) throwError(err); // clean up variables delete [] recordedSamples; delete [] fifo; returnValue = 0; done: delete plugin; return returnValue; }
bool VampAnalyser::Init(const QString pluginlibrary, const QString pluginid, const int samplerate, const int TotalSamples, bool bFastAnalysis) { m_iRemainingSamples = TotalSamples; m_rate = samplerate; if (samplerate <= 0.0) { qDebug() << "VampAnalyser: Track has non-positive samplerate"; return false; } if (TotalSamples <= 0) { qDebug() << "VampAnalyser: Track has non-positive # of samples"; return false; } if (m_plugin != NULL) { delete m_plugin; m_plugin = NULL; qDebug() << "VampAnalyser: kill plugin"; } VampPluginLoader *loader = VampPluginLoader::getInstance(); QStringList pluginlist = pluginid.split(":"); if (pluginlist.size() != 2) { qDebug() << "VampAnalyser: got malformed pluginid: " << pluginid; return false; } bool isNumber = false; int outputnumber = (pluginlist.at(1)).toInt(&isNumber); if (!isNumber) { qDebug() << "VampAnalyser: got malformed pluginid: " << pluginid; return false; } QString plugin = pluginlist.at(0); m_key = loader->composePluginKey(pluginlibrary.toStdString(), plugin.toStdString()); m_plugin = loader->loadPlugin(m_key, m_rate, Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE); if (!m_plugin) { qDebug() << "VampAnalyser: Cannot load Vamp Plug-in."; qDebug() << "Please copy libmixxxminimal.so from build dir to one of the following:"; std::vector<std::string> path = PluginHostAdapter::getPluginPath(); for (unsigned int i = 0; i < path.size(); i++) { qDebug() << QString::fromStdString(path[i]); } return false; } Plugin::OutputList outputs = m_plugin->getOutputDescriptors(); if (outputs.empty()) { qDebug() << "VampAnalyser: Plugin has no outputs!"; return false; } SelectOutput(outputnumber); m_iBlockSize = m_plugin->getPreferredBlockSize(); qDebug() << "Vampanalyser BlockSize: " << m_iBlockSize; if (m_iBlockSize == 0) { // A plugin that can handle any block size may return 0. The final block // size will be set in the initialise() call. Since 0 means it is // accepting any size, 1024 should be good m_iBlockSize = 1024; qDebug() << "Vampanalyser: setting m_iBlockSize to 1024"; } m_iStepSize = m_plugin->getPreferredStepSize(); qDebug() << "Vampanalyser StepSize: " << m_iStepSize; if (m_iStepSize == 0 || m_iStepSize > m_iBlockSize) { // A plugin may return 0 if it has no particular interest in the step // size. In this case, the host should make the step size equal to the // block size if the plugin is accepting input in the time domain. If // the plugin is accepting input in the frequency domain, the host may // use any step size. The final step size will be set in the // initialise() call. m_iStepSize = m_iBlockSize; qDebug() << "Vampanalyser: setting m_iStepSize to" << m_iStepSize; } if (!m_plugin->initialise(2, m_iStepSize, m_iBlockSize)) { qDebug() << "VampAnalyser: Cannot initialise plugin"; return false; } // Here we are using m_iBlockSize: it cannot be 0 m_pluginbuf[0] = new CSAMPLE[m_iBlockSize]; m_pluginbuf[1] = new CSAMPLE[m_iBlockSize]; m_FastAnalysisEnabled = bFastAnalysis; if (m_FastAnalysisEnabled) { qDebug() << "Using fast analysis methods for BPM and Replay Gain."; m_iMaxSamplesToAnalyse = 120 * m_rate; //only consider the first minute } return true; }