# HG changeset patch # User Chris Cannam # Date 1222098243 0 # Node ID 381ec750eeeec3acf45f112540fb71422a41d196 # Parent 04b7fd31e1c6b4451fac46e8ae0989692e135303 * Add beginnings of transform-search-by-text function diff -r 04b7fd31e1c6 -r 381ec750eeee transform/TransformDescription.h --- a/transform/TransformDescription.h Fri Sep 19 12:55:35 2008 +0000 +++ b/transform/TransformDescription.h Mon Sep 22 15:44:03 2008 +0000 @@ -49,10 +49,12 @@ TransformDescription(QString _type, QString _category, TransformId _identifier, QString _name, QString _friendlyName, QString _description, + QString _longDescription, QString _maker, QString _units, bool _configurable) : type(_type), category(_category), identifier(_identifier), name(_name), friendlyName(_friendlyName), description(_description), + longDescription(_longDescription), maker(_maker), units(_units), configurable(_configurable) { } QString type; // e.g. feature extraction plugin @@ -61,6 +63,7 @@ QString name; // plugin's name if 1 output, else "name: output" QString friendlyName; // short text for layer name QString description; // sentence describing transform + QString longDescription; // description "using" plugin name "by" maker QString maker; QString units; bool configurable; diff -r 04b7fd31e1c6 -r 381ec750eeee transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Fri Sep 19 12:55:35 2008 +0000 +++ b/transform/TransformFactory.cpp Mon Sep 22 15:44:03 2008 +0000 @@ -30,6 +30,9 @@ #include #include +using std::cerr; +using std::endl; + TransformFactory * TransformFactory::m_instance = new TransformFactory; @@ -51,14 +54,14 @@ std::set dset; for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); i != m_transforms.end(); ++i) { -// std::cerr << "inserting transform into set: id = " << i->second.identifier.toStdString() << std::endl; +// cerr << "inserting transform into set: id = " << i->second.identifier.toStdString() << endl; dset.insert(i->second); } TransformList list; for (std::set::const_iterator i = dset.begin(); i != dset.end(); ++i) { -// std::cerr << "inserting transform into list: id = " << i->identifier.toStdString() << std::endl; +// cerr << "inserting transform into list: id = " << i->identifier.toStdString() << endl; list.push_back(*i); } @@ -227,7 +230,7 @@ FeatureExtractionPluginFactory::instanceFor(pluginId); if (!factory) { - std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; + cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << endl; continue; } @@ -235,7 +238,7 @@ factory->instantiatePlugin(pluginId, 44100); if (!plugin) { - std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl; + cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << endl; continue; } @@ -257,21 +260,23 @@ QString maker = plugin->getMaker().c_str(); if (maker == "") maker = tr(""); - if (description == "") { + QString longDescription = description; + + if (longDescription == "") { if (outputs.size() == 1) { - description = tr("Extract features using \"%1\" plugin (from %2)") + longDescription = tr("Extract features using \"%1\" plugin (from %2)") .arg(pluginName).arg(maker); } else { - description = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") + longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); } } else { if (outputs.size() == 1) { - description = tr("%1 using \"%2\" plugin (from %3)") - .arg(description).arg(pluginName).arg(maker); + longDescription = tr("%1 using \"%2\" plugin (from %3)") + .arg(longDescription).arg(pluginName).arg(maker); } else { - description = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") - .arg(description).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); + longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") + .arg(longDescription).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); } } @@ -288,7 +293,7 @@ bool configurable = (!plugin->getPrograms().empty() || !plugin->getParameterDescriptors().empty()); -// std::cerr << "Feature extraction plugin transform: " << transformId.toStdString() << " friendly name: " << friendlyName.toStdString() << std::endl; +// cerr << "Feature extraction plugin transform: " << transformId.toStdString() << " friendly name: " << friendlyName.toStdString() << endl; transforms[transformId] = TransformDescription(tr("Analysis"), @@ -297,6 +302,7 @@ userName, friendlyName, description, + longDescription, maker, units, configurable); @@ -322,7 +328,7 @@ RealTimePluginFactory::instanceFor(pluginId); if (!factory) { - std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; + cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << endl; continue; } @@ -330,14 +336,14 @@ factory->getPluginDescriptor(pluginId); if (!descriptor) { - std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl; + cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << endl; continue; } //!!! if (descriptor->controlOutputPortCount == 0 || // descriptor->audioInputPortCount == 0) continue; -// std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << std::endl; +// std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << endl; QString pluginName = descriptor->name.c_str(); QString category = factory->getPluginCategory(pluginId); @@ -398,6 +404,7 @@ transformId, userName, userName, + "", description, maker, units, @@ -429,6 +436,7 @@ transformId, pluginName, pluginName, + "", description, maker, "", @@ -506,15 +514,15 @@ { Vamp::Plugin *vp = dynamic_cast(plugin); if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << std::endl; +// cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << endl; vp = dynamic_cast(plugin); //!!! why? } if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << std::endl; +// cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << endl; vp = dynamic_cast(plugin); //!!! no, I mean really why? } if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << std::endl; +// cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << endl; } return vp; } @@ -727,10 +735,10 @@ } if (!transform.getStepSize()) { if (domain == Vamp::Plugin::FrequencyDomain) { -// std::cerr << "frequency domain, step = " << blockSize/2 << std::endl; +// cerr << "frequency domain, step = " << blockSize/2 << endl; transform.setStepSize(transform.getBlockSize()/2); } else { -// std::cerr << "time domain, step = " << blockSize/2 << std::endl; +// cerr << "time domain, step = " << blockSize/2 << endl; transform.setStepSize(transform.getBlockSize()); } } @@ -745,9 +753,9 @@ Vamp::PluginBase *plugin = instantiateDefaultPluginFor (t.getIdentifier(), 0); if (!plugin) { - std::cerr << "TransformFactory::getPluginConfigurationXml: " + cerr << "TransformFactory::getPluginConfigurationXml: " << "Unable to instantiate plugin for transform \"" - << t.getIdentifier().toStdString() << "\"" << std::endl; + << t.getIdentifier().toStdString() << "\"" << endl; return xml; } @@ -767,9 +775,9 @@ Vamp::PluginBase *plugin = instantiateDefaultPluginFor (t.getIdentifier(), 0); if (!plugin) { - std::cerr << "TransformFactory::setParametersFromPluginConfigurationXml: " + cerr << "TransformFactory::setParametersFromPluginConfigurationXml: " << "Unable to instantiate plugin for transform \"" - << t.getIdentifier().toStdString() << "\"" << std::endl; + << t.getIdentifier().toStdString() << "\"" << endl; return; } @@ -777,4 +785,137 @@ setParametersFromPlugin(t, plugin); delete plugin; } +/* +TransformFactory::SearchResults +TransformFactory::search(QStringList keywords) +{ + SearchResults results; + SearchResults partial; + for (int i = 0; i < keywords.size(); ++i) { + partial = search(keywords[i]); + for (SearchResults::const_iterator j = partial.begin(); + j != partial.end(); ++j) { + if (results.find(j->first) == results.end()) { + results[j->first] = j->second; + } else { + results[j->first].score += j->second.score; + results[j->first].fragments << j->second.fragments; + } + } + } + return results; +} +*/ +TransformFactory::SearchResults +TransformFactory::search(QString keyword) +{ + QStringList keywords; + keywords << keyword; + return search(keywords); +} + +TransformFactory::SearchResults +TransformFactory::search(QStringList keywords) +{ + if (m_transforms.empty()) populateTransforms(); + + SearchResults results; + + for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); + i != m_transforms.end(); ++i) { + + Match match; + + match.transform = i->first; + + searchTest(match, keywords, i->second.type, tr("Plugin type"), 10); + searchTest(match, keywords, i->second.category, tr("Category"), 20); + searchTest(match, keywords, i->second.identifier, tr("System Identifier"), 5); + searchTest(match, keywords, i->second.name, tr("Name"), 30); + searchTest(match, keywords, i->second.description, tr("Description"), 20); + searchTest(match, keywords, i->second.maker, tr("Maker"), 10); + searchTest(match, keywords, i->second.units, tr("Units"), 10); + + if (match.score > 0) results[i->first] = match; + } + + return results; +} + +void +TransformFactory::searchTest(Match &match, QStringList keywords, QString text, + QString textType, int score) +{ +/* + if (text.toLower() == keyword.toLower()) { + match.score += score * 1.5; + match.fragments << tr("%1: %2").arg(textType).arg(text); + return; + } +*/ + int len = text.length(); + int prevEnd = 0; + QString fragment; + + while (1) { + + bool first = (prevEnd == 0); + + int idx = -1; + QString keyword; + + for (int ki = 0; ki < keywords.size(); ++ki) { + int midx = text.indexOf(keywords[ki], prevEnd, Qt::CaseInsensitive); + if (midx >= 0 && midx < len) { + if (midx < idx || idx == -1) { + idx = midx; + keyword = keywords[ki]; + } + } + } + + if (idx < 0 || idx >= len) break; + + int klen = keyword.length(); + + if (first) { + match.score += score; + } else { + match.score += score / 4; + } + + int start = idx; + int end = start + klen; + + if (start == 0) match.score += 1; + if (end == len) match.score += 1; + + if (start > prevEnd + 14) { +// cerr << "start = " << start << ", prevEnd = " <" + s.left(klen + 10).right(klen) + ""; +// cerr << "s = " << s.toStdString() << endl; + fragment += tr("...%1").arg(s); +// cerr << "fragment = " << fragment.toStdString() << endl; + } else { + QString s = text.right(len - prevEnd); + s = s.left(start - prevEnd) + "" + s.left(end - prevEnd).right(klen) + ""; + fragment += s; + } + + prevEnd = end; + } + + if (prevEnd > 0 && prevEnd < len) { + int n = len - prevEnd; + fragment += text.right(n).left(n < 8 ? n : 8); + } + + if (fragment != "") { + fragment = tr("%1: %2").arg(textType).arg(fragment); + match.fragments << fragment; + } +} + diff -r 04b7fd31e1c6 -r 381ec750eeee transform/TransformFactory.h --- a/transform/TransformFactory.h Fri Sep 19 12:55:35 2008 +0000 +++ b/transform/TransformFactory.h Mon Sep 22 15:44:03 2008 +0000 @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -41,6 +42,38 @@ std::vector getTransformCategories(QString transformType); std::vector getTransformMakers(QString transformType); + struct Match + { + TransformId transform; + int score; + QStringList fragments; + + Match() : score(0) { } + Match(const Match &m) : transform(m.transform), + score(m.score), fragments(m.fragments) { } + + bool operator<(const Match &m) { + if (score != m.score) { + return score < m.score; + } else if (transform != m.transform) { + return transform < m.transform; + } else if (fragments.size() != m.fragments.size()) { + return fragments.size() < m.fragments.size(); + } else { + for (int i = 0; i < fragments.size(); ++i) { + if (fragments[i] != m.fragments[i]) { + return fragments[i] < m.fragments[i]; + } + } + } + return false; + } + }; + + typedef std::map SearchResults; + SearchResults search(QString keyword); + SearchResults search(QStringList keywords); + /** * Return true if the given transform is known. */ @@ -165,6 +198,9 @@ void populateFeatureExtractionPlugins(TransformDescriptionMap &); void populateRealTimePlugins(TransformDescriptionMap &); + void searchTest(Match &match, QStringList keywords, QString text, + QString textType, int score); + Vamp::PluginBase *instantiateDefaultPluginFor(TransformId id, size_t rate); static TransformFactory *m_instance;