* Update to new Vamp process()
[vamp-aubio-plugins.git] / plugins / Notes.cpp
index 35f4be9..eb68cee 100644 (file)
@@ -36,7 +36,12 @@ Notes::Notes(float inputSampleRate) :
     m_pitchmode(aubio_pitchm_freq),
     m_threshold(0.3),
     m_silence(-90),
-    m_median(6)
+    m_median(6),
+    m_minpitch(27),
+    m_maxpitch(95),
+    m_wrapRange(false),
+    m_avoidLeaps(false),
+    m_prevPitch(-1)
 {
 }
 
@@ -112,8 +117,11 @@ Notes::initialise(size_t channels, size_t stepSize, size_t blockSize)
                                           m_pitchmode);
 
     m_count = 0;
+    m_delay = Vamp::RealTime::frame2RealTime((4 + m_median) * m_stepSize,
+                                       lrintf(m_inputSampleRate));
     m_currentOnset = Vamp::RealTime::zeroTime;
     m_haveCurrent = false;
+    m_prevPitch = -1;
 
     return true;
 }
@@ -132,7 +140,7 @@ Notes::getPreferredStepSize() const
 size_t
 Notes::getPreferredBlockSize() const
 {
-    return 4*getPreferredStepSize();
+    return 4 * getPreferredStepSize();
 }
 
 Notes::ParameterList
@@ -173,6 +181,48 @@ Notes::getParameterDescriptors() const
     list.push_back(desc);
 
     desc = ParameterDescriptor();
+    desc.name = "minpitch";
+    desc.description = "Minimum Pitch";
+    desc.minValue = 0;
+    desc.maxValue = 127;
+    desc.defaultValue = 32;
+    desc.unit = "MIDI units";
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    list.push_back(desc);
+
+    desc = ParameterDescriptor();
+    desc.name = "maxpitch";
+    desc.description = "Maximum Pitch";
+    desc.minValue = 0;
+    desc.maxValue = 127;
+    desc.defaultValue = 95;
+    desc.unit = "MIDI units";
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    list.push_back(desc);
+
+    desc = ParameterDescriptor();
+    desc.name = "wraprange";
+    desc.description = "Fold Higher or Lower Notes into Range";
+    desc.minValue = 0;
+    desc.maxValue = 1;
+    desc.defaultValue = 0;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    list.push_back(desc);
+
+    desc = ParameterDescriptor();
+    desc.name = "avoidleaps";
+    desc.description = "Avoid Multi-Octave Jumps";
+    desc.minValue = 0;
+    desc.maxValue = 1;
+    desc.defaultValue = 0;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    list.push_back(desc);
+
+    desc = ParameterDescriptor();
     desc.name = "peakpickthreshold";
     desc.description = "Peak Picker Threshold";
     desc.minValue = 0;
@@ -205,6 +255,14 @@ Notes::getParameter(std::string param) const
         return m_threshold;
     } else if (param == "silencethreshold") {
         return m_silence;
+    } else if (param == "minpitch") {
+        return m_minpitch;
+    } else if (param == "maxpitch") {
+        return m_maxpitch;
+    } else if (param == "wraprange") {
+        return m_wrapRange ? 1.0 : 0.0;
+    } else if (param == "avoidleaps") {
+        return m_avoidLeaps ? 1.0 : 0.0;
     } else {
         return 0.0;
     }
@@ -235,6 +293,14 @@ Notes::setParameter(std::string param, float value)
         m_threshold = value;
     } else if (param == "silencethreshold") {
         m_silence = value;
+    } else if (param == "minpitch") {
+        m_minpitch = lrintf(value);
+    } else if (param == "maxpitch") {
+        m_maxpitch = lrintf(value);
+    } else if (param == "wraprange") {
+        m_wrapRange = (value > 0.5);
+    } else if (param == "avoidleaps") {
+        m_avoidLeaps = (value > 0.5);
     }
 }
 
@@ -262,7 +328,7 @@ Notes::getOutputDescriptors() const
 }
 
 Notes::FeatureSet
-Notes::process(float **inputBuffers, Vamp::RealTime timestamp)
+Notes::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
 {
     for (size_t i = 0; i < m_stepSize; ++i) {
         for (size_t j = 0; j < m_channelCount; ++j) {
@@ -322,11 +388,41 @@ Notes::pushNote(FeatureSet &fs, const Vamp::RealTime &offTime)
     float median = toSort[toSort.size()/2];
     if (median < 45.0) return;
 
+    float freq = median;
+    int midiPitch = (int)FLOOR(aubio_freqtomidi(freq) + 0.5);
+    
+    if (m_avoidLeaps) {
+        if (m_prevPitch >= 0) {
+            while (midiPitch < m_prevPitch - 12) {
+                midiPitch += 12;
+                freq *= 2;
+            }
+            while (midiPitch > m_prevPitch + 12) {
+                midiPitch -= 12;
+                freq /= 2;
+            }
+        }
+    }
+
+    while (midiPitch < m_minpitch) {
+        if (!m_wrapRange) return;
+        midiPitch += 12;
+        freq *= 2;
+    }
+
+    while (midiPitch > m_maxpitch) {
+        if (!m_wrapRange) return;
+        midiPitch -= 12;
+        freq /= 2;
+    }
+
+    m_prevPitch = midiPitch;
+
     Feature feature;
     feature.hasTimestamp = true;
-    feature.timestamp = m_currentOnset;
-    feature.values.push_back(median);
-//    feature.values.push_back(FLOOR(aubio_freqtomidi(median) + 0.5));
+    if (m_currentOnset < m_delay) m_currentOnset = m_delay;
+    feature.timestamp = m_currentOnset - m_delay;
+    feature.values.push_back(freq);
     feature.values.push_back
         (Vamp::RealTime::realTime2Frame(offTime, lrintf(m_inputSampleRate)) -
          Vamp::RealTime::realTime2Frame(m_currentOnset, lrintf(m_inputSampleRate)));