Chris@0: Chris@0: Chris@0: #include "VampTestPlugin.h" Chris@0: Chris@19: #include Chris@3: #include Chris@18: #include Chris@3: Chris@19: using namespace std; Chris@3: Chris@3: using Vamp::RealTime; Chris@0: Chris@0: VampTestPlugin::VampTestPlugin(float inputSampleRate) : Chris@3: Plugin(inputSampleRate), Chris@17: m_produceOutput(true), Chris@3: m_n(0), Chris@18: m_channels(1), Chris@3: m_stepSize(0), Chris@3: m_blockSize(0) Chris@0: { Chris@3: for (int i = 0; i < 10; ++i) { Chris@3: m_instants.push_back(RealTime::fromSeconds(1.5 * i)); Chris@3: } Chris@0: } Chris@0: Chris@0: VampTestPlugin::~VampTestPlugin() Chris@0: { Chris@0: } Chris@0: Chris@0: string Chris@0: VampTestPlugin::getIdentifier() const Chris@0: { Chris@0: return "vamp-test-plugin"; Chris@0: } Chris@0: Chris@0: string Chris@0: VampTestPlugin::getName() const Chris@0: { Chris@0: return "Vamp Test Plugin"; Chris@0: } Chris@0: Chris@0: string Chris@0: VampTestPlugin::getDescription() const Chris@0: { Chris@0: return "Test plugin for hosts handling various output types"; Chris@0: } Chris@0: Chris@0: string Chris@0: VampTestPlugin::getMaker() const Chris@0: { Chris@0: return "Chris Cannam"; Chris@0: } Chris@0: Chris@0: int Chris@0: VampTestPlugin::getPluginVersion() const Chris@0: { Chris@17: return 2; Chris@0: } Chris@0: Chris@0: string Chris@0: VampTestPlugin::getCopyright() const Chris@0: { Chris@0: return "BSD"; Chris@0: } Chris@0: Chris@0: VampTestPlugin::InputDomain Chris@0: VampTestPlugin::getInputDomain() const Chris@0: { Chris@0: return TimeDomain; Chris@0: } Chris@0: Chris@0: size_t Chris@0: VampTestPlugin::getPreferredBlockSize() const Chris@0: { Chris@0: return 0; Chris@0: } Chris@0: Chris@0: size_t Chris@0: VampTestPlugin::getPreferredStepSize() const Chris@0: { Chris@0: return 0; Chris@0: } Chris@0: Chris@0: size_t Chris@0: VampTestPlugin::getMinChannelCount() const Chris@0: { Chris@0: return 1; Chris@0: } Chris@0: Chris@0: size_t Chris@0: VampTestPlugin::getMaxChannelCount() const Chris@0: { Chris@18: return 10; Chris@0: } Chris@0: Chris@0: VampTestPlugin::ParameterList Chris@0: VampTestPlugin::getParameterDescriptors() const Chris@0: { Chris@0: ParameterList list; Chris@17: Chris@17: // Provide one parameter, and make it so that we can easily tell Chris@17: // whether it has been changed Chris@17: ParameterDescriptor d; Chris@17: d.identifier = "produce_output"; Chris@17: d.name = "Produce some output"; Chris@17: d.description = "Whether to produce any output. If this parameter is switched off, the plugin will produce no output. This is intended for basic testing of whether a host's parameter setting logic is functioning."; Chris@17: d.unit = ""; Chris@17: d.minValue = 0; Chris@17: d.maxValue = 1; Chris@17: d.defaultValue = 1; Chris@17: d.isQuantized = true; Chris@17: d.quantizeStep = 1; Chris@17: list.push_back(d); Chris@17: Chris@0: return list; Chris@0: } Chris@0: Chris@0: float Chris@0: VampTestPlugin::getParameter(string identifier) const Chris@0: { Chris@17: if (identifier == "produce_output") { Chris@17: return m_produceOutput ? 1.f : 0.f; Chris@17: } Chris@0: return 0; Chris@0: } Chris@0: Chris@0: void Chris@0: VampTestPlugin::setParameter(string identifier, float value) Chris@0: { Chris@17: if (identifier == "produce_output") { Chris@17: m_produceOutput = (value > 0.5); Chris@17: } Chris@0: } Chris@0: Chris@0: VampTestPlugin::ProgramList Chris@0: VampTestPlugin::getPrograms() const Chris@0: { Chris@0: ProgramList list; Chris@0: return list; Chris@0: } Chris@0: Chris@0: string Chris@0: VampTestPlugin::getCurrentProgram() const Chris@0: { Chris@0: return ""; // no programs Chris@0: } Chris@0: Chris@0: void Chris@0: VampTestPlugin::selectProgram(string name) Chris@0: { Chris@0: } Chris@0: Chris@0: VampTestPlugin::OutputList Chris@0: VampTestPlugin::getOutputDescriptors() const Chris@0: { Chris@0: OutputList list; Chris@0: Chris@7: int n = 0; Chris@7: Chris@0: OutputDescriptor d; Chris@1: Chris@1: d.identifier = "instants"; Chris@1: d.name = "Instants"; Chris@2: d.description = "Single time points without values"; Chris@1: d.unit = ""; Chris@1: d.hasFixedBinCount = true; Chris@1: d.binCount = 0; Chris@1: d.hasKnownExtents = false; Chris@1: d.isQuantized = false; Chris@1: d.sampleType = OutputDescriptor::VariableSampleRate; Chris@1: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@1: list.push_back(d); Chris@1: Chris@1: d.identifier = "curve-oss"; Chris@1: d.name = "Curve: OneSamplePerStep"; Chris@2: d.description = "A time series with one value per process block"; Chris@0: d.unit = ""; Chris@0: d.hasFixedBinCount = true; Chris@0: d.binCount = 1; Chris@0: d.hasKnownExtents = false; Chris@0: d.isQuantized = false; Chris@0: d.sampleType = OutputDescriptor::OneSamplePerStep; Chris@0: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@0: list.push_back(d); Chris@0: Chris@1: d.identifier = "curve-fsr"; Chris@1: d.name = "Curve: FixedSampleRate"; Chris@2: d.description = "A time series with equally-spaced values (independent of process step size)"; Chris@1: d.unit = ""; Chris@1: d.hasFixedBinCount = true; Chris@1: d.binCount = 1; Chris@1: d.hasKnownExtents = false; Chris@1: d.isQuantized = false; Chris@1: d.sampleType = OutputDescriptor::FixedSampleRate; Chris@8: d.sampleRate = 2.5; Chris@1: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@1: list.push_back(d); Chris@1: Chris@7: d.identifier = "curve-fsr-timed"; Chris@7: d.name = "Curve: FixedSampleRate/Timed"; Chris@7: d.description = "A time series with a fixed sample rate (independent of process step size) but with timestamps on features"; Chris@7: d.unit = ""; Chris@7: d.hasFixedBinCount = true; Chris@7: d.binCount = 1; Chris@7: d.hasKnownExtents = false; Chris@7: d.isQuantized = false; Chris@7: d.sampleType = OutputDescriptor::FixedSampleRate; Chris@8: d.sampleRate = 2.5; Chris@7: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@7: list.push_back(d); Chris@7: Chris@1: d.identifier = "curve-vsr"; Chris@1: d.name = "Curve: VariableSampleRate"; Chris@2: d.description = "A variably-spaced series of values"; Chris@1: d.unit = ""; Chris@1: d.hasFixedBinCount = true; Chris@1: d.binCount = 1; Chris@1: d.hasKnownExtents = false; Chris@1: d.isQuantized = false; Chris@1: d.sampleType = OutputDescriptor::VariableSampleRate; Chris@2: d.sampleRate = 0; Chris@1: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@1: list.push_back(d); Chris@1: Chris@2: d.identifier = "grid-oss"; Chris@2: d.name = "Grid: OneSamplePerStep"; Chris@2: d.description = "A fixed-height grid of values with one column per process block"; Chris@2: d.unit = ""; Chris@2: d.hasFixedBinCount = true; Chris@4: d.binCount = 10; Chris@2: d.hasKnownExtents = false; Chris@2: d.isQuantized = false; Chris@4: d.sampleType = OutputDescriptor::OneSamplePerStep; Chris@2: d.sampleRate = 0; Chris@2: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@2: list.push_back(d); Chris@2: Chris@2: d.identifier = "grid-fsr"; Chris@2: d.name = "Grid: FixedSampleRate"; Chris@2: d.description = "A fixed-height grid of values with equally-spaced columns (independent of process step size)"; Chris@2: d.unit = ""; Chris@2: d.hasFixedBinCount = true; Chris@4: d.binCount = 10; Chris@2: d.hasKnownExtents = false; Chris@2: d.isQuantized = false; Chris@4: d.sampleType = OutputDescriptor::FixedSampleRate; Chris@8: d.sampleRate = 2.5; Chris@2: d.hasDuration = false; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@2: list.push_back(d); Chris@2: Chris@5: d.identifier = "notes-regions"; Chris@5: d.name = "Notes or Regions"; Chris@5: d.description = "Variably-spaced features with one value and duration"; Chris@5: d.unit = ""; Chris@5: d.hasFixedBinCount = true; Chris@5: d.binCount = 1; Chris@5: d.hasKnownExtents = false; Chris@5: d.isQuantized = false; Chris@5: d.sampleType = OutputDescriptor::VariableSampleRate; Chris@5: d.sampleRate = 0; Chris@5: d.hasDuration = true; Chris@7: m_outputNumbers[d.identifier] = n++; Chris@5: list.push_back(d); Chris@2: Chris@19: d.identifier = "input-summary"; Chris@19: d.name = "Data derived from inputs"; Chris@19: d.description = "One-sample-per-step features with n values, where n is the number of input channels. Each feature contains, for each input channel, the first sample value on that channel plus the total number of non-zero samples on that channel"; Chris@18: d.unit = ""; Chris@18: d.hasFixedBinCount = true; Chris@18: d.binCount = m_channels; Chris@18: d.hasKnownExtents = false; Chris@18: d.isQuantized = false; Chris@18: d.sampleType = OutputDescriptor::OneSamplePerStep; Chris@18: d.hasDuration = false; Chris@18: m_outputNumbers[d.identifier] = n++; Chris@18: list.push_back(d); Chris@18: Chris@0: return list; Chris@0: } Chris@0: Chris@0: bool Chris@0: VampTestPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) Chris@0: { Chris@0: if (channels < getMinChannelCount() || Chris@0: channels > getMaxChannelCount()) return false; Chris@0: Chris@18: m_channels = channels; Chris@3: m_stepSize = stepSize; Chris@3: m_blockSize = blockSize; Chris@0: Chris@0: return true; Chris@0: } Chris@0: Chris@0: void Chris@0: VampTestPlugin::reset() Chris@0: { Chris@3: m_n = 0; Chris@3: } Chris@3: Chris@3: static Vamp::Plugin::Feature Chris@3: instant(RealTime r, int i, int n) Chris@3: { Chris@19: stringstream s; Chris@3: Vamp::Plugin::Feature f; Chris@3: f.hasTimestamp = true; Chris@3: f.timestamp = r; Chris@3: f.hasDuration = false; Chris@3: s << i+1 << " of " << n << " at " << r.toText(); Chris@3: f.label = s.str(); Chris@3: return f; Chris@3: } Chris@3: Chris@3: static Vamp::Plugin::Feature Chris@3: untimedCurveValue(RealTime r, int i, int n) Chris@3: { Chris@19: stringstream s; Chris@3: Vamp::Plugin::Feature f; Chris@3: f.hasTimestamp = false; Chris@3: f.hasDuration = false; Chris@3: float v = float(i) / float(n); Chris@3: f.values.push_back(v); Chris@3: s << i+1 << " of " << n << ": " << v << " at " << r.toText(); Chris@3: f.label = s.str(); Chris@3: return f; Chris@0: } Chris@0: Chris@4: static Vamp::Plugin::Feature Chris@4: timedCurveValue(RealTime r, int i, int n) Chris@4: { Chris@19: stringstream s; Chris@4: Vamp::Plugin::Feature f; Chris@4: f.hasTimestamp = true; Chris@4: f.timestamp = r; Chris@4: f.hasDuration = false; Chris@4: float v = float(i) / float(n); Chris@4: f.values.push_back(v); Chris@4: s << i+1 << " of " << n << ": " << v << " at " << r.toText(); Chris@4: f.label = s.str(); Chris@4: return f; Chris@4: } Chris@4: Chris@4: static Vamp::Plugin::Feature Chris@7: snappedCurveValue(RealTime r, RealTime sn, int i, int n) Chris@7: { Chris@19: stringstream s; Chris@7: Vamp::Plugin::Feature f; Chris@7: f.hasTimestamp = true; Chris@7: f.timestamp = r; Chris@7: f.hasDuration = false; Chris@7: float v = float(i) / float(n); Chris@7: f.values.push_back(v); Chris@7: s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " snap to " << sn.toText(); Chris@7: f.label = s.str(); Chris@7: return f; Chris@7: } Chris@7: Chris@7: static Vamp::Plugin::Feature Chris@4: gridColumn(RealTime r, int i, int n) Chris@4: { Chris@19: stringstream s; Chris@4: Vamp::Plugin::Feature f; Chris@4: f.hasTimestamp = false; Chris@4: f.hasDuration = false; Chris@4: for (int j = 0; j < 10; ++j) { Chris@4: float v = float(j + i + 2) / float(n + 10); Chris@4: f.values.push_back(v); Chris@4: } Chris@4: s << i+1 << " of " << n << " at " << r.toText(); Chris@4: f.label = s.str(); Chris@4: return f; Chris@4: } Chris@4: Chris@5: static Vamp::Plugin::Feature Chris@5: noteOrRegion(RealTime r, RealTime d, int i, int n) Chris@5: { Chris@19: stringstream s; Chris@5: Vamp::Plugin::Feature f; Chris@5: f.hasTimestamp = true; Chris@5: f.timestamp = r; Chris@5: f.hasDuration = true; Chris@5: f.duration = d; Chris@5: float v = float(i) / float(n); Chris@5: f.values.push_back(v); Chris@5: s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " dur. " << d.toText(); Chris@5: f.label = s.str(); Chris@5: return f; Chris@5: } Chris@5: Chris@7: static Chris@7: float snap(float x, float r) Chris@7: { Chris@7: int n = int(x / r + 0.5); Chris@7: return n * r; Chris@7: } Chris@7: Chris@5: Vamp::Plugin::FeatureSet Chris@5: VampTestPlugin::featuresFrom(RealTime timestamp, bool final) Chris@0: { Chris@3: FeatureSet fs; Chris@3: Chris@3: RealTime endTime = timestamp + RealTime::frame2RealTime Chris@3: (m_stepSize, m_inputSampleRate); Chris@3: Chris@3: for (int i = 0; i < (int)m_instants.size(); ++i) { Chris@5: Chris@5: if (m_instants[i] >= timestamp && (final || m_instants[i] < endTime)) { Chris@7: fs[m_outputNumbers["instants"]] Chris@7: .push_back(instant(m_instants[i], i, m_instants.size())); Chris@3: } Chris@4: Chris@4: RealTime variCurveTime = m_instants[i] / 2; Chris@5: if (variCurveTime >= timestamp && (final || variCurveTime < endTime)) { Chris@7: fs[m_outputNumbers["curve-vsr"]] Chris@7: .push_back(timedCurveValue(variCurveTime, i, m_instants.size())); Chris@4: } Chris@5: Chris@5: RealTime noteTime = (m_instants[i] + m_instants[i]) / 3; Chris@5: RealTime noteDuration = RealTime::fromSeconds((i % 2 == 0) ? 1.75 : 0.5); Chris@5: Chris@5: if (noteTime >= timestamp && (final || noteTime < endTime)) { Chris@7: fs[m_outputNumbers["notes-regions"]] Chris@7: .push_back(noteOrRegion(noteTime, noteDuration, i, m_instants.size())); Chris@5: } Chris@3: } Chris@3: Chris@5: if (!final) { Chris@3: Chris@5: if (m_n < 20) { Chris@7: fs[m_outputNumbers["curve-oss"]] Chris@7: .push_back(untimedCurveValue(timestamp, m_n, 20)); Chris@5: } Chris@3: Chris@5: if (m_n < 5) { Chris@7: fs[m_outputNumbers["curve-fsr"]] Chris@8: .push_back(untimedCurveValue(RealTime::fromSeconds(m_n / 2.5), m_n, 10)); Chris@6: Chris@7: float s = (m_n / 4) * 2; Chris@7: if ((m_n % 4) > 0) { Chris@7: s += float((m_n % 4) - 1) / 6.0; Chris@7: } Chris@7: fs[m_outputNumbers["curve-fsr-timed"]] Chris@7: .push_back(snappedCurveValue(RealTime::fromSeconds(s), Chris@8: RealTime::fromSeconds(snap(s, 0.4)), Chris@7: m_n, 10)); Chris@5: } Chris@5: Chris@5: if (m_n < 20) { Chris@7: fs[m_outputNumbers["grid-oss"]] Chris@7: .push_back(gridColumn(timestamp, m_n, 20)); Chris@5: } Chris@5: Chris@5: } else { Chris@5: Chris@5: for (int i = (m_n > 5 ? 5 : m_n); i < 10; ++i) { Chris@7: fs[m_outputNumbers["curve-fsr"]] Chris@8: .push_back(untimedCurveValue(RealTime::fromSeconds(i / 2.5), i, 10)); Chris@7: Chris@7: float s = (i / 4) * 2; Chris@7: if ((i % 4) > 0) { Chris@7: s += float((i % 4) - 1) / 6.0; Chris@7: } Chris@7: fs[m_outputNumbers["curve-fsr-timed"]] Chris@7: .push_back(snappedCurveValue(RealTime::fromSeconds(s), Chris@8: RealTime::fromSeconds(snap(s, 0.4)), Chris@7: i, 10)); Chris@5: } Chris@5: Chris@8: for (int i = 0; i < 10; ++i) { Chris@7: fs[m_outputNumbers["grid-fsr"]] Chris@9: .push_back(gridColumn(RealTime::fromSeconds(i / 2.5), i, 10)); Chris@5: } Chris@4: } Chris@4: Chris@3: m_lastTime = endTime; Chris@3: m_n = m_n + 1; Chris@3: return fs; Chris@5: } Chris@5: Chris@5: VampTestPlugin::FeatureSet Chris@5: VampTestPlugin::process(const float *const *inputBuffers, RealTime timestamp) Chris@5: { Chris@17: if (!m_produceOutput) return FeatureSet(); Chris@5: FeatureSet fs = featuresFrom(timestamp, false); Chris@18: Chris@18: Feature f; Chris@18: for (int c = 0; c < m_channels; ++c) { Chris@19: // first value plus number of non-zero values Chris@19: float sum = inputBuffers[c][0]; Chris@18: for (int i = 0; i < m_blockSize; ++i) { Chris@19: if (inputBuffers[c][i] != 0.f) sum += 1; Chris@18: } Chris@19: f.values.push_back(sum); Chris@18: } Chris@19: fs[m_outputNumbers["input-summary"]].push_back(f); Chris@18: Chris@5: return fs; Chris@0: } Chris@0: Chris@0: VampTestPlugin::FeatureSet Chris@0: VampTestPlugin::getRemainingFeatures() Chris@0: { Chris@17: if (!m_produceOutput) return FeatureSet(); Chris@5: FeatureSet fs = featuresFrom(m_lastTime, true); Chris@3: return fs; Chris@0: } Chris@0: