cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: cannam@0: /* cannam@0: Vamp Plugin Fuzz Tester cannam@0: Chris Cannam, cannam@all-day-breakfast.com cannam@0: Centre for Digital Music, Queen Mary, University of London. cannam@0: Copyright 2009 QMUL. cannam@0: cannam@0: This program loads a Vamp plugin and tests its susceptibility to a cannam@0: number of common pitfalls, including handling of extremes of input cannam@0: data. If you can think of any additional useful tests that are cannam@0: easily added, please send them to me. cannam@0: cannam@0: Permission is hereby granted, free of charge, to any person cannam@0: obtaining a copy of this software and associated documentation cannam@0: files (the "Software"), to deal in the Software without cannam@0: restriction, including without limitation the rights to use, copy, cannam@0: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@0: of the Software, and to permit persons to whom the Software is cannam@0: furnished to do so, subject to the following conditions: cannam@0: cannam@0: The above copyright notice and this permission notice shall be cannam@0: included in all copies or substantial portions of the Software. cannam@0: cannam@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@0: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@0: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@0: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@0: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@0: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@0: cannam@0: Except as contained in this notice, the names of the Centre for cannam@0: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@0: shall not be used in advertising or otherwise to promote the sale, cannam@0: use or other dealings in this Software without prior written cannam@0: authorization. cannam@0: */ cannam@0: cannam@0: #include "Test.h" cannam@0: cannam@0: #include cannam@0: cannam@0: using namespace Vamp; cannam@0: using namespace Vamp::HostExt; cannam@0: cannam@20: #include cannam@1: cannam@0: Test::Test() { } cannam@0: Test::~Test() { } cannam@0: cannam@0: Plugin * cannam@0: Test::load(std::string key, float rate) cannam@0: { cannam@23: Plugin *p = PluginLoader::getInstance()->loadPlugin cannam@0: (key, rate, PluginLoader::ADAPT_ALL); cannam@23: if (!p) throw FailedToLoadPlugin(); cannam@23: return p; cannam@0: } cannam@0: cannam@1: float ** cannam@1: Test::createBlock(size_t channels, size_t blocksize) cannam@1: { cannam@1: float **b = new float *[channels]; cannam@1: for (size_t c = 0; c < channels; ++c) { cannam@1: b[c] = new float[blocksize]; cannam@1: } cannam@1: return b; cannam@1: } cannam@1: cannam@1: void cannam@1: Test::destroyBlock(float **blocks, size_t channels) cannam@1: { cannam@1: for (size_t c = 0; c < channels; ++c) { cannam@1: delete[] blocks[c]; cannam@1: } cannam@1: delete[] blocks; cannam@1: } cannam@1: cannam@3: float ** cannam@3: Test::createTestAudio(size_t channels, size_t blocksize, size_t blocks) cannam@3: { cannam@3: float **b = new float *[channels]; cannam@3: for (size_t c = 0; c < channels; ++c) { cannam@3: b[c] = new float[blocksize * blocks]; cannam@3: for (int i = 0; i < int(blocksize * blocks); ++i) { cannam@3: b[c][i] = sinf(float(i) / 10.f); cannam@3: if (i == 5005 || i == 20002) { cannam@3: b[c][i-2] = 0; cannam@3: b[c][i-1] = -1; cannam@3: b[c][i] = 1; cannam@3: } cannam@3: } cannam@3: } cannam@3: return b; cannam@3: } cannam@3: cannam@3: void cannam@3: Test::destroyTestAudio(float **b, size_t channels) cannam@3: { cannam@3: for (size_t c = 0; c < channels; ++c) { cannam@3: delete[] b[c]; cannam@3: } cannam@3: delete[] b; cannam@3: } cannam@3: cannam@1: bool cannam@1: Test::initDefaults(Plugin *p, size_t &channels, size_t &step, size_t &block, cannam@1: Results &r) cannam@1: { cannam@1: channels = p->getMinChannelCount(); cannam@1: block = p->getPreferredBlockSize(); cannam@1: step = p->getPreferredStepSize(); cannam@1: if (block == 0) block = 1024; cannam@1: if (step == 0) { cannam@1: if (p->getInputDomain() == Plugin::FrequencyDomain) step = block/2; cannam@1: else step = block; cannam@1: } cannam@1: if (!p->initialise(channels, step, block)) { cannam@1: r.push_back(error("initialisation with default values failed")); cannam@1: return false; cannam@1: } cannam@1: return true; cannam@1: } cannam@1: cannam@3: bool cannam@3: Test::initAdapted(Plugin *p, size_t &channels, size_t step, size_t block, cannam@3: Results &r) cannam@3: { cannam@3: channels = p->getMinChannelCount(); cannam@3: if (!p->initialise(channels, step, block)) { cannam@3: r.push_back(error("initialisation failed")); cannam@3: return false; cannam@3: } cannam@3: return true; cannam@3: } cannam@3: cannam@0: void cannam@0: Test::appendFeatures(Plugin::FeatureSet &a, const Plugin::FeatureSet &b) cannam@0: { cannam@0: for (Plugin::FeatureSet::const_iterator i = b.begin(); i != b.end(); ++i) { cannam@0: int output = i->first; cannam@0: const Plugin::FeatureList &fl = i->second; cannam@0: Plugin::FeatureList &target = a[output]; cannam@0: for (Plugin::FeatureList::const_iterator j = fl.begin(); j != fl.end(); ++j) { cannam@0: target.push_back(*j); cannam@0: } cannam@0: } cannam@0: } cannam@0: cannam@0: bool cannam@1: Test::allFeaturesValid(const Plugin::FeatureSet &b) cannam@1: { cannam@1: for (Plugin::FeatureSet::const_iterator i = b.begin(); i != b.end(); ++i) { cannam@1: for (int j = 0; j < (int)i->second.size(); ++j) { cannam@1: if (i->second[j].values.empty()) continue; cannam@1: for (int k = 0; k < (int)i->second[j].values.size(); ++k) { cannam@1: if (isnan(i->second[j].values[k]) || cannam@1: isinf(i->second[j].values[k])) { cannam@1: return false; cannam@1: } cannam@1: } cannam@1: } cannam@1: } cannam@1: return true; cannam@1: } cannam@1: cannam@3: void cannam@3: Test::dump(const Plugin::FeatureSet &fs) cannam@3: { cannam@3: for (Plugin::FeatureSet::const_iterator fsi = fs.begin(); cannam@3: fsi != fs.end(); ++fsi) { cannam@3: int output = fsi->first; cannam@8: std::cout << "Output " << output << ":" << std::endl; cannam@3: const Plugin::FeatureList &fl = fsi->second; cannam@3: for (int i = 0; i < (int)fl.size(); ++i) { cannam@8: std::cout << " Feature " << i << ":" << std::endl; cannam@3: const Plugin::Feature &f = fl[i]; cannam@8: std::cout << " Timestamp: " << (f.hasTimestamp ? "(none)" : f.timestamp.toText()) << std::endl; cannam@8: std::cout << " Duration: " << (f.hasDuration ? "(none)" : f.duration.toText()) << std::endl; cannam@8: std::cout << " Label: " << (f.label == "" ? "(none)" : f.label) << std::endl; cannam@8: std::cout << " Value: " << (f.values.empty() ? "(none)" : ""); cannam@3: for (int j = 0; j < (int)f.values.size(); ++j) { cannam@8: std::cout << f.values[j] << " "; cannam@3: } cannam@8: std::cout << std::endl; cannam@3: } cannam@3: } cannam@3: } cannam@3: cannam@3: void cannam@3: Test::dump(const Result &r, cannam@3: const Plugin::FeatureSet &a, cannam@3: const Plugin::FeatureSet &b) cannam@3: { cannam@8: std::cout << r.message() << std::endl; cannam@8: std::cout << "\nFirst result set:" << std::endl; cannam@3: dump(a); cannam@8: std::cout << "\nSecond result set:" << std::endl; cannam@3: dump(b); cannam@8: std::cout << std::endl; cannam@3: } cannam@3: cannam@1: bool cannam@0: operator==(const Plugin::FeatureSet &a, const Plugin::FeatureSet &b) cannam@0: { cannam@0: if (a.size() != b.size()) return false; cannam@0: for (Plugin::FeatureSet::const_iterator ai = a.begin(); cannam@0: ai != a.end(); ++ai) { cannam@0: int output = ai->first; cannam@0: Plugin::FeatureSet::const_iterator bi = b.find(output); cannam@0: if (bi == b.end()) return false; cannam@0: if (!(ai->second == bi->second)) return false; cannam@0: } cannam@0: return true; cannam@0: } cannam@0: cannam@0: bool cannam@0: operator==(const Plugin::FeatureList &a, const Plugin::FeatureList &b) cannam@0: { cannam@0: if (a.size() != b.size()) return false; cannam@0: for (int i = 0; i < (int)a.size(); ++i) { cannam@0: if (!(a[i] == b[i])) return false; cannam@0: } cannam@0: return true; cannam@0: } cannam@0: cannam@0: bool cannam@0: operator==(const Plugin::Feature &a, const Plugin::Feature &b) cannam@0: { cannam@0: if (a.hasTimestamp != b.hasTimestamp) return false; cannam@0: if (a.hasTimestamp && (a.timestamp != b.timestamp)) return false; cannam@0: if (a.hasDuration != b.hasDuration) return false; cannam@0: if (a.hasDuration && (a.duration != b.duration)) return false; cannam@0: if (a.values != b.values) return false; cannam@0: if (a.label != b.label) return false; cannam@0: return true; cannam@0: } cannam@0: