From 8a6de236a010692836ab072e0070221f0db61e21 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Mon, 10 Apr 2017 16:41:02 +0200 Subject: [PATCH 1/5] Fix memory bug in Vibrato --- src/algorithms/tonal/vibrato.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/algorithms/tonal/vibrato.cpp b/src/algorithms/tonal/vibrato.cpp index ccae3f611..ad07f8d32 100644 --- a/src/algorithms/tonal/vibrato.cpp +++ b/src/algorithms/tonal/vibrato.cpp @@ -91,7 +91,7 @@ void Vibrato::compute() { startC.push_back(0); } for (int i=0; i<(int)pitchP.size()-1; i++) { - if (pitchP[i+1]>0 && pitchP[i]==0){ + if (pitchP[i+1]>0 && pitchP[i]==0) { startC.push_back(i+1); } if (pitchP[i+1]==0 && pitchP[i]>0) { @@ -138,7 +138,7 @@ void Vibrato::compute() { if(!frame.size()) { break; } - + // subtract mean pitch from frame Real m = mean(frame, 0, frame.size()-1); for (int ii=0; ii<(int)frame.size(); ii++) { @@ -181,11 +181,17 @@ void Vibrato::compute() { if (ext<_minExtend || ext>_maxExtend){ continue; } - - for (int ii=startC[i]+frameNumber-1; ii Date: Tue, 18 Apr 2017 13:31:30 +0200 Subject: [PATCH 2/5] fixed error in the documentation --- src/algorithms/tonal/vibrato.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/tonal/vibrato.h b/src/algorithms/tonal/vibrato.h index 5c6e5337f..31ec9dba0 100644 --- a/src/algorithms/tonal/vibrato.h +++ b/src/algorithms/tonal/vibrato.h @@ -40,8 +40,8 @@ class Vibrato : public Algorithm { public: Vibrato() { declareInput(_pitch, "pitch", "the pitch trajectory [Hz]."); - declareOutput(_vibratoFrequency, "vibratoFrequency", "estimated vibrato frquency [Hz]; zero if no vibrato was detected."); - declareOutput(_vibratoExtend, "vibratoExtend","estimated vibrato frquency [Hz]; zero if no vibrato was detected.") ; + declareOutput(_vibratoFrequency, "vibratoFrequency", "estimated vibrato frequency (or speed) [Hz]; zero if no vibrato was detected."); + declareOutput(_vibratoExtend, "vibratoExtend","estimated vibrato extend (or depth) [cents]; zero if no vibrato was detected.") ; frameCutter = AlgorithmFactory::create("FrameCutter"); window = AlgorithmFactory::create("Windowing"); From 756422ccb5f41cbf3b97e00c46b5e95735230b4c Mon Sep 17 00:00:00 2001 From: pabloEntropia Date: Tue, 18 Apr 2017 13:33:08 +0200 Subject: [PATCH 3/5] added Vibrato unit test #584 --- test/src/unittest/tonal/test_vibrato.py | 113 ++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 test/src/unittest/tonal/test_vibrato.py diff --git a/test/src/unittest/tonal/test_vibrato.py b/test/src/unittest/tonal/test_vibrato.py new file mode 100644 index 000000000..d8ec9c524 --- /dev/null +++ b/test/src/unittest/tonal/test_vibrato.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +# Copyright (C) 2006-2016 Music Technology Group - Universitat Pompeu Fabra +# +# This file is part of Essentia +# +# Essentia is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation (FSF), either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the Affero GNU General Public License +# version 3 along with this program. If not, see http://www.gnu.org/licenses/ + + + +from essentia_test import * +from numpy import sin, float32, pi, arange, mean, log2, floor, ceil + +class TestVibrato(TestCase): + + def testEmpty(self): + vibrato, extend = Vibrato()([]) + self.assertEqual(vibrato.size, 0) + self.assertEqual(extend.size, 0) + + def testZero(self): + vibrato, extend = Vibrato()([0]) + + self.assertEqualVector(vibrato, [0.]) + self.assertEqualVector(extend, [0.]) + + def testOnes(self): + vibrato, extend = Vibrato()([1]*1024) + + self.assertEqualVector(vibrato, [0.]*1024) + self.assertEqualVector(extend, [0.]*1024) + + + def testNegativeInput(self): + # Negative vlues should be set to 0 + vibrato, extend = Vibrato()([-1]*1024) + + self.assertEqualVector(vibrato, [0.]*1024) + self.assertEqualVector(extend, [0.]*1024) + + def testInvalidParam(self): + self.assertConfigureFails(Vibrato(), { 'maxExtend': -1 }) + self.assertConfigureFails(Vibrato(), { 'maxFrequency': -1 }) + self.assertConfigureFails(Vibrato(), { 'minExtend': -1 }) + self.assertConfigureFails(Vibrato(), { 'minFrequency': -1 }) + self.assertConfigureFails(Vibrato(), { 'sampleRate': -1 }) + + def testSyntheticVibrato(self): + fs = 100 #Hz + f0 = 100 #Hz + extend = 5 #Hz + vibrato = 5 #Hz + + x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + + vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + + self.assertAlmostEqual(vibrato,mean(vibratoEst[3:-3]), 1) + + extendCents = 1200*log2((f0+extend)/float(f0-extend)) + self.assertAlmostEqual(extendCents, mean(extendEst[3:-3]), 1e-1) + + def testFrequencyDetenctionThreshold(self): + # Vibrato Min and Max default values are 3 and 8Hz so + # this values shouldn't be detected. + + fs = 100 #Hz + f0 = 100 #Hz + extend = 5 #Hz + vibrato = 3 #Hz + x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + + vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + self.assertEqual(0, vibratoEst.all()) + + vibrato = 9 #Hz + x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + self.assertEqual(0, vibratoEst.all()) + + + def testExtendDetenctionThreshold(self): + # Extend Min and Max default values are 50 and 250 cents so + # this values shouldn't be detected. + fs = 100 #Hz + f0 = 100 #Hz + extend = ceil(f0 * (2**(250/1200.) -1) / (2**(250/1200.) + 1)) + vibrato = 5 #Hz + x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + self.assertEqual(0, vibratoEst.all()) + + extend = floor(f0 * (2**(50/1200.) -1) / (2**(50/1200.) + 1)) + x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + self.assertEqual(0, vibratoEst.all()) + + +suite = allTests(TestVibrato) + +if __name__ == '__main__': + TextTestRunner(verbosity=2).run(suite) \ No newline at end of file From 56dc3bb2fdc4c57277ab869333c6dac17dcb27ee Mon Sep 17 00:00:00 2001 From: pabloEntropia Date: Tue, 18 Apr 2017 14:07:46 +0200 Subject: [PATCH 4/5] changed `extend` for `extent` in the documentation --- src/algorithms/tonal/vibrato.cpp | 2 +- src/algorithms/tonal/vibrato.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/algorithms/tonal/vibrato.cpp b/src/algorithms/tonal/vibrato.cpp index ad07f8d32..3ad7b2474 100644 --- a/src/algorithms/tonal/vibrato.cpp +++ b/src/algorithms/tonal/vibrato.cpp @@ -26,7 +26,7 @@ using namespace standard; const char* Vibrato::name = "Vibrato"; const char* Vibrato::category = "Pitch"; -const char* Vibrato::description = DOC("This algorithm detects the presence of vibrato and estimates its parameters given a pitch contour [Hz]. The result is the vibrato frequency in Hz and the extend (peak to peak) in cents. If no vibrato is detected in a frame, the output of both values is zero.\n" +const char* Vibrato::description = DOC("This algorithm detects the presence of vibrato and estimates its parameters given a pitch contour [Hz]. The result is the vibrato frequency in Hz and the extent (peak to peak) in cents. If no vibrato is detected in a frame, the output of both values is zero.\n" "\n" "This algorithm should be given the outputs of a pitch estimator, i.e. PredominantMelody, PitchYinFFT or PitchMelodia and the corresponding sample rate with which it was computed.\n" "\n" diff --git a/src/algorithms/tonal/vibrato.h b/src/algorithms/tonal/vibrato.h index 31ec9dba0..f6ec1597b 100644 --- a/src/algorithms/tonal/vibrato.h +++ b/src/algorithms/tonal/vibrato.h @@ -41,7 +41,7 @@ class Vibrato : public Algorithm { Vibrato() { declareInput(_pitch, "pitch", "the pitch trajectory [Hz]."); declareOutput(_vibratoFrequency, "vibratoFrequency", "estimated vibrato frequency (or speed) [Hz]; zero if no vibrato was detected."); - declareOutput(_vibratoExtend, "vibratoExtend","estimated vibrato extend (or depth) [cents]; zero if no vibrato was detected.") ; + declareOutput(_vibratoExtend, "vibratoExtend","estimated vibrato extent (or depth) [cents]; zero if no vibrato was detected.") ; frameCutter = AlgorithmFactory::create("FrameCutter"); window = AlgorithmFactory::create("Windowing"); @@ -54,8 +54,8 @@ class Vibrato : public Algorithm { void declareParameters() { declareParameter("minFrequency", "minimum considered vibrato frequency [Hz]", "(0,inf)", 4.0); declareParameter("maxFrequency", "maximum considered vibrato frequency [Hz]", "(0,inf)", 8.0); - declareParameter("minExtend", "minimum considered vibrato extend [cents]", "(0,inf)", 50.0); - declareParameter("maxExtend", "maximum considered vibrato extend [cents]", "(0,inf)", 250.0); + declareParameter("minExtend", "minimum considered vibrato extent [cents]", "(0,inf)", 50.0); + declareParameter("maxExtend", "maximum considered vibrato extent [cents]", "(0,inf)", 250.0); declareParameter("sampleRate", "sample rate of the input pitch contour", "(0,inf)", 44100.0/128.0); } From 8c64b21eca7db23650cd70f021c48e8a742f2a9c Mon Sep 17 00:00:00 2001 From: pabloEntropia Date: Tue, 18 Apr 2017 14:22:01 +0200 Subject: [PATCH 5/5] replaced `extend` for `extent` in the test --- test/src/unittest/tonal/test_vibrato.py | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/src/unittest/tonal/test_vibrato.py b/test/src/unittest/tonal/test_vibrato.py index d8ec9c524..0abcd564a 100644 --- a/test/src/unittest/tonal/test_vibrato.py +++ b/test/src/unittest/tonal/test_vibrato.py @@ -25,29 +25,29 @@ class TestVibrato(TestCase): def testEmpty(self): - vibrato, extend = Vibrato()([]) + vibrato, extent = Vibrato()([]) self.assertEqual(vibrato.size, 0) - self.assertEqual(extend.size, 0) + self.assertEqual(extent.size, 0) def testZero(self): - vibrato, extend = Vibrato()([0]) + vibrato, extent = Vibrato()([0]) self.assertEqualVector(vibrato, [0.]) - self.assertEqualVector(extend, [0.]) + self.assertEqualVector(extent, [0.]) def testOnes(self): - vibrato, extend = Vibrato()([1]*1024) + vibrato, extent = Vibrato()([1]*1024) self.assertEqualVector(vibrato, [0.]*1024) - self.assertEqualVector(extend, [0.]*1024) + self.assertEqualVector(extent, [0.]*1024) def testNegativeInput(self): # Negative vlues should be set to 0 - vibrato, extend = Vibrato()([-1]*1024) + vibrato, extent = Vibrato()([-1]*1024) self.assertEqualVector(vibrato, [0.]*1024) - self.assertEqualVector(extend, [0.]*1024) + self.assertEqualVector(extent, [0.]*1024) def testInvalidParam(self): self.assertConfigureFails(Vibrato(), { 'maxExtend': -1 }) @@ -59,17 +59,17 @@ def testInvalidParam(self): def testSyntheticVibrato(self): fs = 100 #Hz f0 = 100 #Hz - extend = 5 #Hz + extent = 5 #Hz vibrato = 5 #Hz - x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs) - vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32)) self.assertAlmostEqual(vibrato,mean(vibratoEst[3:-3]), 1) - extendCents = 1200*log2((f0+extend)/float(f0-extend)) - self.assertAlmostEqual(extendCents, mean(extendEst[3:-3]), 1e-1) + extentCents = 1200*log2((f0+extent)/float(f0-extent)) + self.assertAlmostEqual(extentCents, mean(extentEst[3:-3]), 1e-1) def testFrequencyDetenctionThreshold(self): # Vibrato Min and Max default values are 3 and 8Hz so @@ -77,16 +77,16 @@ def testFrequencyDetenctionThreshold(self): fs = 100 #Hz f0 = 100 #Hz - extend = 5 #Hz + extent = 5 #Hz vibrato = 3 #Hz - x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) + x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs) - vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32)) self.assertEqual(0, vibratoEst.all()) vibrato = 9 #Hz - x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) - vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs) + vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32)) self.assertEqual(0, vibratoEst.all()) @@ -95,15 +95,15 @@ def testExtendDetenctionThreshold(self): # this values shouldn't be detected. fs = 100 #Hz f0 = 100 #Hz - extend = ceil(f0 * (2**(250/1200.) -1) / (2**(250/1200.) + 1)) + extent = ceil(f0 * (2**(250/1200.) -1) / (2**(250/1200.) + 1)) vibrato = 5 #Hz - x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) - vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs) + vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32)) self.assertEqual(0, vibratoEst.all()) - extend = floor(f0 * (2**(50/1200.) -1) / (2**(50/1200.) + 1)) - x = [f0] * 1024 + extend * sin(2 * pi * vibrato * arange(1024) / fs) - vibratoEst, extendEst = Vibrato(sampleRate=fs)(x.astype(float32)) + extent = floor(f0 * (2**(50/1200.) -1) / (2**(50/1200.) + 1)) + x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs) + vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32)) self.assertEqual(0, vibratoEst.all())