Skip to content

Commit

Permalink
Merge branch 'pabloEntropia-vibrato-fix'
Browse files Browse the repository at this point in the history
  • Loading branch information
dbogdanov committed Apr 18, 2017
2 parents 5a798a0 + b534565 commit 63cb8e1
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 9 deletions.
16 changes: 11 additions & 5 deletions src/algorithms/tonal/vibrato.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -181,11 +181,17 @@ void Vibrato::compute() {
if (ext<_minExtend || ext>_maxExtend){
continue;
}

for (int ii=startC[i]+frameNumber-1; ii<startC[i]+frameNumber+frameSize-1; ii++) {

int ii = startC[i]+frameNumber-1;
vibratoFrequency[ii] = peakFrequencies[0];
vibratoExtend[ii] = ext;
// NOTE: no need to loop over the frame, as the hopSize is 1
/*
for (int ii=startC[i]+frameNumber-1; ii<startC[i]+frameNumber-1+frameSize; ii++) {
vibratoFrequency[ii]=peakFrequencies[0];
vibratoExtend[ii]=ext;
}
*/
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/algorithms/tonal/vibrato.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 extent (or depth) [cents]; zero if no vibrato was detected.") ;

frameCutter = AlgorithmFactory::create("FrameCutter");
window = AlgorithmFactory::create("Windowing");
Expand All @@ -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);
}

Expand Down
113 changes: 113 additions & 0 deletions test/src/unittest/tonal/test_vibrato.py
Original file line number Diff line number Diff line change
@@ -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, extent = Vibrato()([])
self.assertEqual(vibrato.size, 0)
self.assertEqual(extent.size, 0)

def testZero(self):
vibrato, extent = Vibrato()([0])

self.assertEqualVector(vibrato, [0.])
self.assertEqualVector(extent, [0.])

def testOnes(self):
vibrato, extent = Vibrato()([1]*1024)

self.assertEqualVector(vibrato, [0.]*1024)
self.assertEqualVector(extent, [0.]*1024)


def testNegativeInput(self):
# Negative vlues should be set to 0
vibrato, extent = Vibrato()([-1]*1024)

self.assertEqualVector(vibrato, [0.]*1024)
self.assertEqualVector(extent, [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
extent = 5 #Hz
vibrato = 5 #Hz

x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs)

vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32))

self.assertAlmostEqual(vibrato,mean(vibratoEst[3:-3]), 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
# this values shouldn't be detected.

fs = 100 #Hz
f0 = 100 #Hz
extent = 5 #Hz
vibrato = 3 #Hz
x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs)

vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32))
self.assertEqual(0, vibratoEst.all())

vibrato = 9 #Hz
x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs)
vibratoEst, extentEst = 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
extent = ceil(f0 * (2**(250/1200.) -1) / (2**(250/1200.) + 1))
vibrato = 5 #Hz
x = [f0] * 1024 + extent * sin(2 * pi * vibrato * arange(1024) / fs)
vibratoEst, extentEst = Vibrato(sampleRate=fs)(x.astype(float32))
self.assertEqual(0, vibratoEst.all())

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())


suite = allTests(TestVibrato)

if __name__ == '__main__':
TextTestRunner(verbosity=2).run(suite)

0 comments on commit 63cb8e1

Please sign in to comment.