Mercurial > hg > silvet
changeset 298:ebe5e0942bb8 livemode
More toward a possible live mode
author | Chris Cannam |
---|---|
date | Fri, 28 Nov 2014 10:18:22 +0000 |
parents | d6ab1b4918bd |
children | a4216826f01c |
files | Makefile.inc src/Instruments.cpp src/Instruments.h src/LiveInstruments.cpp src/LiveInstruments.h src/Silvet.cpp src/Silvet.h |
diffstat | 7 files changed, 166 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.inc Fri Nov 28 09:42:56 2014 +0000 +++ b/Makefile.inc Fri Nov 28 10:18:22 2014 +0000 @@ -20,8 +20,8 @@ PLUGIN := silvet$(PLUGIN_EXT) -PLUGIN_HEADERS := $(SRC_DIR)/Silvet.h $(SRC_DIR)/EM.h $(SRC_DIR)/Instruments.h -PLUGIN_SOURCES := $(SRC_DIR)/Silvet.cpp $(SRC_DIR)/EM.cpp $(SRC_DIR)/Instruments.cpp $(SRC_DIR)/libmain.cpp +PLUGIN_HEADERS := $(SRC_DIR)/Silvet.h $(SRC_DIR)/EM.h $(SRC_DIR)/Instruments.h $(SRC_DIR)/LiveInstruments.h +PLUGIN_SOURCES := $(SRC_DIR)/Silvet.cpp $(SRC_DIR)/EM.cpp $(SRC_DIR)/Instruments.cpp $(SRC_DIR)/LiveInstruments.cpp $(SRC_DIR)/libmain.cpp BQVEC_HEADERS := $(BQVEC_DIR)/Allocators.h $(BQVEC_DIR)/Restrict.h $(BQVEC_DIR)/VectorOps.h BQVEC_SOURCES := $(BQVEC_DIR)/Allocators.cpp
--- a/src/Instruments.cpp Fri Nov 28 09:42:56 2014 +0000 +++ b/src/Instruments.cpp Fri Nov 28 10:18:22 2014 +0000 @@ -19,16 +19,28 @@ #include <iostream> -const int InstrumentPack::templateNoteCount = SILVET_TEMPLATE_NOTE_COUNT; -const int InstrumentPack::templateHeight = SILVET_TEMPLATE_HEIGHT; -const int InstrumentPack::templateMaxShift = SILVET_TEMPLATE_MAX_SHIFT; -const int InstrumentPack::templateSize = SILVET_TEMPLATE_SIZE; - using std::string; using std::vector; using std::cerr; using std::endl; +InstrumentPack::InstrumentPack(int lowest, int highest, + std::string n, std::vector<Templates> tt) : + templateNoteCount(SILVET_TEMPLATE_NOTE_COUNT), + templateHeight(SILVET_TEMPLATE_HEIGHT), + templateMaxShift(SILVET_TEMPLATE_MAX_SHIFT), + templateSize(SILVET_TEMPLATE_SIZE), + lowestNote(lowest), + highestNote(highest), + maxPolyphony(5), + pitchSparsity(1.1), + sourceSparsity(1.2), + levelThreshold(5), + name(n), + templates(tt) +{ +} + const char *simpleInstruments[] = { // Each instrument has two consecutive slots, one for the pack // name and one for the template to look up
--- a/src/Instruments.h Fri Nov 28 09:42:56 2014 +0000 +++ b/src/Instruments.h Fri Nov 28 10:18:22 2014 +0000 @@ -32,10 +32,10 @@ class InstrumentPack { public: - static const int templateNoteCount; - static const int templateHeight; - static const int templateMaxShift; - static const int templateSize; + int templateNoteCount; + int templateHeight; + int templateMaxShift; + int templateSize; int lowestNote; int highestNote; @@ -60,15 +60,9 @@ private: InstrumentPack(int lowest, int highest, std::string n, - std::vector<Templates> tt) : - lowestNote(lowest), - highestNote(highest), - maxPolyphony(5), - pitchSparsity(1.1), - sourceSparsity(1.2), - levelThreshold(5), - name(n), - templates(tt) { } + std::vector<Templates> tt); + + friend class LiveAdapter; }; #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LiveInstruments.cpp Fri Nov 28 10:18:22 2014 +0000 @@ -0,0 +1,71 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Silvet + + A Vamp plugin for note transcription. + Centre for Digital Music, Queen Mary University of London. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "LiveInstruments.h" + +#include "data/include/templates.h" + +using namespace std; + +InstrumentPack +LiveAdapter::adapt(const InstrumentPack &original) +{ + vector<InstrumentPack::Templates> templates; + + for (vector<InstrumentPack::Templates>::const_iterator i = + original.templates.begin(); + i != original.templates.end(); ++i) { + + InstrumentPack::Templates t; + t.lowestNote = i->lowestNote; + t.highestNote = i->highestNote; + t.data.resize(i->data.size()); + + for (int j = 0; j < int(i->data.size()); ++j) { + t.data[j].resize(SILVET_TEMPLATE_HEIGHT/5); + for (int k = 0; k < SILVET_TEMPLATE_HEIGHT/5; ++k) { + t.data[j][k] = i->data[j][k * 5 + 2 - SILVET_TEMPLATE_MAX_SHIFT]; + } + } + templates.push_back(t); + } + + InstrumentPack live(original.lowestNote, + original.highestNote, + original.name, + templates); + + live.templateHeight = SILVET_TEMPLATE_HEIGHT/5; + live.templateMaxShift = 0; + live.templateSize = live.templateHeight; + + live.maxPolyphony = original.maxPolyphony; + live.pitchSparsity = original.pitchSparsity; + live.sourceSparsity = original.sourceSparsity; + live.levelThreshold = original.levelThreshold; + + return live; +} + +vector<InstrumentPack> +LiveAdapter::adaptAll(const vector<InstrumentPack> &v) +{ + vector<InstrumentPack> out; + for (int i = 0; i < (int)v.size(); ++i) { + InstrumentPack p(LiveAdapter::adapt(v[i])); + out.push_back(p); + } + return out; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/LiveInstruments.h Fri Nov 28 10:18:22 2014 +0000 @@ -0,0 +1,32 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Silvet + + A Vamp plugin for note transcription. + Centre for Digital Music, Queen Mary University of London. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef SILVET_LIVE_INSTRUMENTS_H +#define SILVET_LIVE_INSTRUMENTS_H + +#include "Instruments.h" + +/** + * Adapt an instrument pack into a "live" version, with fewer bins per + * octave and so lower CQ latency. + */ +class LiveAdapter +{ +public: + static InstrumentPack adapt(const InstrumentPack &original); + static std::vector<InstrumentPack> adaptAll(const std::vector<InstrumentPack> &); +}; + +#endif
--- a/src/Silvet.cpp Fri Nov 28 09:42:56 2014 +0000 +++ b/src/Silvet.cpp Fri Nov 28 10:18:22 2014 +0000 @@ -21,6 +21,7 @@ #include "MedianFilter.h" #include "constant-q-cpp/src/dsp/Resampler.h" #include "flattendynamics-ladspa.h" +#include "LiveInstruments.h" #include <vector> @@ -33,7 +34,9 @@ using Vamp::RealTime; static int processingSampleRate = 44100; -static int processingBPO = 60; + +static int binsPerSemitoneLive = 1; +static int binsPerSemitoneNormal = 5; static int minInputSampleRate = 100; static int maxInputSampleRate = 192000; @@ -41,6 +44,7 @@ Silvet::Silvet(float inputSampleRate) : Plugin(inputSampleRate), m_instruments(InstrumentPack::listInstrumentPacks()), + m_liveInstruments(LiveAdapter::adaptAll(m_instruments)), m_resampler(0), m_flattener(0), m_cq(0), @@ -247,18 +251,18 @@ d.description = "Filtered constant-Q time-frequency distribution as used as input to the expectation-maximisation algorithm."; d.unit = ""; d.hasFixedBinCount = true; - d.binCount = m_instruments[0].templateHeight; + d.binCount = getPack(0).templateHeight; d.binNames.clear(); if (m_cq) { char name[50]; - for (int i = 0; i < m_instruments[0].templateHeight; ++i) { + for (int i = 0; i < getPack(0).templateHeight; ++i) { // We have a 600-bin (10 oct 60-bin CQ) of which the // lowest-frequency 55 bins have been dropped, for a // 545-bin template. The native CQ bins go high->low // frequency though, so these are still the first 545 bins // as reported by getBinFrequency, though in reverse order float freq = m_cq->getBinFrequency - (m_instruments[0].templateHeight - i - 1); + (getPack(0).templateHeight - i - 1); sprintf(name, "%.1f Hz", freq); d.binNames.push_back(name); } @@ -276,10 +280,10 @@ d.description = "Pitch activation distribution resulting from expectation-maximisation algorithm, prior to note extraction."; d.unit = ""; d.hasFixedBinCount = true; - d.binCount = m_instruments[0].templateNoteCount; + d.binCount = getPack(0).templateNoteCount; d.binNames.clear(); if (m_cq) { - for (int i = 0; i < m_instruments[0].templateNoteCount; ++i) { + for (int i = 0; i < getPack(0).templateNoteCount; ++i) { d.binNames.push_back(noteName(i, 0, 1)); } } @@ -406,10 +410,13 @@ minFreq *= 2; } + int bpo = 12 * + (m_mode == LiveMode ? binsPerSemitoneLive : binsPerSemitoneNormal); + CQParameters params(processingSampleRate, minFreq, processingSampleRate / 3, - processingBPO); + bpo); params.q = 0.95; // MIREX code uses 0.8, but it seems 0.9 or lower // drops the FFT size to 512 from 1024 and alters @@ -430,7 +437,7 @@ delete m_postFilter[i]; } m_postFilter.clear(); - for (int i = 0; i < m_instruments[0].templateNoteCount; ++i) { + for (int i = 0; i < getPack(0).templateNoteCount; ++i) { m_postFilter.push_back(new MedianFilter<double>(3)); } m_pianoRoll.clear(); @@ -506,7 +513,7 @@ if (filtered.empty()) return fs; - const InstrumentPack &pack = m_instruments[m_instrument]; + const InstrumentPack &pack(getPack(m_instrument)); for (int i = 0; i < (int)filtered.size(); ++i) { Feature f; @@ -633,7 +640,7 @@ // size we reduce to in a moment int latentColumns = m_cq->getLatency() / m_cq->getColumnHop(); - const InstrumentPack &pack = m_instruments[m_instrument]; + const InstrumentPack &pack(getPack(m_instrument)); for (int i = 0; i < width; ++i) { @@ -652,7 +659,7 @@ vector<double> outCol(pack.templateHeight); // In HQ mode, the CQ returns 600 bins and we ignore the - // lowest 55 of them. + // lowest 55 of them (assuming binsPerSemitone == 5). // // In draft and live mode the CQ is an octave shorter, // returning 540 bins, so we instead pad them with an @@ -662,29 +669,32 @@ // raw CQ has the high frequencies first and we need it // the other way around. + int bps = (m_mode == LiveMode ? + binsPerSemitoneLive : binsPerSemitoneNormal); + if (m_mode == HighQualityMode) { for (int j = 0; j < pack.templateHeight; ++j) { - int ix = inCol.size() - j - 55; + int ix = inCol.size() - j - (11 * bps); outCol[j] = inCol[ix]; } } else { - for (int j = 0; j < 5; ++j) { + for (int j = 0; j < bps; ++j) { outCol[j] = 0.0; } - for (int j = 5; j < pack.templateHeight; ++j) { - int ix = inCol.size() - j + 4; + for (int j = bps; j < pack.templateHeight; ++j) { + int ix = inCol.size() - j + (bps-1); outCol[j] = inCol[ix]; } } vector<double> noiseLevel1 = - MedianFilter<double>::filter(40, outCol); + MedianFilter<double>::filter(8 * bps, outCol); for (int j = 0; j < pack.templateHeight; ++j) { noiseLevel1[j] = std::min(outCol[j], noiseLevel1[j]); } vector<double> noiseLevel2 = - MedianFilter<double>::filter(40, noiseLevel1); + MedianFilter<double>::filter(8 * bps, noiseLevel1); for (int j = 0; j < pack.templateHeight; ++j) { outCol[j] = std::max(outCol[j] - noiseLevel2[j], 0.0); } @@ -703,7 +713,7 @@ const vector<int> &bestShifts, bool wantShifts) { - const InstrumentPack &pack = m_instruments[m_instrument]; + const InstrumentPack &pack(getPack(m_instrument)); vector<double> filtered;
--- a/src/Silvet.h Fri Nov 28 09:42:56 2014 +0000 +++ b/src/Silvet.h Fri Nov 28 10:18:22 2014 +0000 @@ -73,7 +73,16 @@ protected: const std::vector<InstrumentPack> m_instruments; + const std::vector<InstrumentPack> m_liveInstruments; + const InstrumentPack &getPack(int instrument) const { + if (m_mode == LiveMode) { + return m_liveInstruments[instrument]; + } else { + return m_instruments[instrument]; + } + } + Resampler *m_resampler; FlattenDynamics *m_flattener; CQSpectrogram *m_cq;