Skip to content

Commit 01ab181

Browse files
committed
Added VIbrato
1 parent 6183b95 commit 01ab181

File tree

25 files changed

+2028
-0
lines changed

25 files changed

+2028
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright AudioKit. All Rights Reserved.
2+
3+
#include "SoundpipeDSPBase.h"
4+
#include "ParameterRamper.h"
5+
#include "Soundpipe.h"
6+
7+
enum VibratoParameter : AUParameterAddress {
8+
VibratoParameterSpeed,
9+
VibratoParameterDepth
10+
};
11+
12+
class VibratoDSP : public SoundpipeDSPBase {
13+
private:
14+
sp_osc *vibrato;
15+
sp_pshift *pshift;
16+
sp_ftbl *sine;
17+
ParameterRamper speedRamp;
18+
ParameterRamper depthRamp;
19+
20+
public:
21+
VibratoDSP() {
22+
parameters[VibratoParameterSpeed] = &speedRamp;
23+
parameters[VibratoParameterDepth] = &depthRamp;
24+
}
25+
26+
void init(int channelCount, double sampleRate) override {
27+
SoundpipeDSPBase::init(channelCount, sampleRate);
28+
29+
sp_ftbl_create(sp, &sine, 4096);
30+
sp_gen_sine(sp, sine);
31+
32+
sp_osc_create(&vibrato);
33+
sp_osc_init(sp, vibrato, sine, 0);
34+
35+
sp_pshift_create(&pshift);
36+
sp_pshift_init(sp, pshift);
37+
}
38+
39+
void deinit() override {
40+
SoundpipeDSPBase::deinit();
41+
sp_osc_destroy(&vibrato);
42+
sp_pshift_destroy(&pshift);
43+
sp_ftbl_destroy(&sine);
44+
}
45+
46+
void reset() override {
47+
SoundpipeDSPBase::reset();
48+
if (!isInitialized) return;
49+
sp_osc_init(sp, vibrato, sine, 0);
50+
}
51+
52+
void process(FrameRange range) override {
53+
float vibrato_out = 0;
54+
55+
for (int i : range) {
56+
float speed = speedRamp.getAndStep();
57+
float depth = depthRamp.getAndStep();
58+
59+
vibrato->freq = speed;
60+
sp_osc_compute(sp, vibrato, NULL, &vibrato_out);
61+
*pshift->shift = vibrato_out * depth;
62+
63+
float leftIn = inputSample(0, i);
64+
float rightIn = inputSample(1, i);
65+
66+
float leftOut, rightOut;
67+
sp_pshift_compute(sp, pshift, &leftIn, &leftOut);
68+
sp_pshift_compute(sp, pshift, &rightIn, &rightOut);
69+
70+
outputSample(0, i) = leftOut;
71+
outputSample(1, i) = rightOut;
72+
}
73+
}
74+
};
75+
76+
AK_REGISTER_DSP(VibratoDSP, "vbrt")
77+
AK_REGISTER_PARAMETER(VibratoParameterSpeed)
78+
AK_REGISTER_PARAMETER(VibratoParameterDepth)
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
#include <stdint.h> /* For standard interger types (int16_t) */
2+
#include <stdlib.h> /* For call to malloc */
3+
#include <math.h>
4+
#include "Yin.h"
5+
6+
/* ------------------------------------------------------------------------------------------
7+
--------------------------------------------------------------------------- PRIVATE FUNCTIONS
8+
-------------------------------------------------------------------------------------------*/
9+
10+
/**
11+
* Step 1: Calculates the squared difference of the signal with a shifted version of itself.
12+
* @param buffer Buffer of samples to process.
13+
*
14+
* This is the Yin algorithms tweak on autocorellation. Read http://audition.ens.fr/adc/pdf/2002_JASA_YIN.pdf
15+
* for more details on what is in here and why it's done this way.
16+
*/
17+
void Yin_difference(Yin *yin, int16_t* buffer){
18+
int16_t i;
19+
int16_t tau;
20+
float delta;
21+
22+
/* Calculate the difference for difference shift values (tau) for the half of the samples */
23+
for(tau = 0 ; tau < yin->halfBufferSize; tau++){
24+
25+
/* Take the difference of the signal with a shifted version of itself, then square it.
26+
* (This is the Yin algorithm's tweak on autocorellation) */
27+
for(i = 0; i < yin->halfBufferSize; i++) {
28+
29+
if (isnan(yin->yinBuffer[tau])) {
30+
yin->yinBuffer[tau] = 0.0f;
31+
}
32+
33+
delta = buffer[i] - buffer[i + tau];
34+
yin->yinBuffer[tau] += delta * delta;
35+
}
36+
}
37+
}
38+
39+
40+
/**
41+
* Step 2: Calculate the cumulative mean on the normalised difference calculated in step 1
42+
* @param yin #Yin structure with information about the signal
43+
*
44+
* This goes through the Yin autocorellation values and finds out roughly where shift is which
45+
* produced the smallest difference
46+
*/
47+
void Yin_cumulativeMeanNormalizedDifference(Yin *yin){
48+
int16_t tau;
49+
float runningSum = 0;
50+
yin->yinBuffer[0] = 1;
51+
52+
/* Sum all the values in the autocorellation buffer and nomalise the result, replacing
53+
* the value in the autocorellation buffer with a cumulative mean of the normalised difference */
54+
for (tau = 1; tau < yin->halfBufferSize; tau++) {
55+
runningSum += yin->yinBuffer[tau];
56+
yin->yinBuffer[tau] *= tau / runningSum;
57+
}
58+
}
59+
60+
/**
61+
* Step 3: Search through the normalised cumulative mean array and find values that are over the threshold
62+
* @return Shift (tau) which caused the best approximate autocorellation. -1 if no suitable value is found over the threshold.
63+
*/
64+
int16_t Yin_absoluteThreshold(Yin *yin){
65+
int16_t tau;
66+
67+
/* Search through the array of cumulative mean values, and look for ones that are over the threshold
68+
* The first two positions in yinBuffer are always so start at the third (index 2) */
69+
for (tau = 2; tau < yin->halfBufferSize ; tau++) {
70+
if (yin->yinBuffer[tau] < yin->threshold) {
71+
while (tau + 1 < yin->halfBufferSize && yin->yinBuffer[tau + 1] < yin->yinBuffer[tau]) {
72+
tau++;
73+
}
74+
/* found tau, exit loop and return
75+
* store the probability
76+
* From the YIN paper: The yin->threshold determines the list of
77+
* candidates admitted to the set, and can be interpreted as the
78+
* proportion of aperiodic power tolerated
79+
* within a periodic signal.
80+
*
81+
* Since we want the periodicity and and not aperiodicity:
82+
* periodicity = 1 - aperiodicity */
83+
yin->probability = 1 - yin->yinBuffer[tau];
84+
break;
85+
}
86+
}
87+
88+
/* if no pitch found, tau => -1 */
89+
if (tau == yin->halfBufferSize || yin->yinBuffer[tau] >= yin->threshold) {
90+
tau = -1;
91+
yin->probability = 0;
92+
}
93+
94+
return tau;
95+
}
96+
97+
/**
98+
* Step 5: Interpolate the shift value (tau) to improve the pitch estimate.
99+
* @param yin [description]
100+
* @param tauEstimate [description]
101+
* @return [description]
102+
*
103+
* The 'best' shift value for autocorellation is most likely not an interger shift of the signal.
104+
* As we only autocorellated using integer shifts we should check that there isn't a better fractional
105+
* shift value.
106+
*/
107+
float Yin_parabolicInterpolation(Yin *yin, int16_t tauEstimate) {
108+
float betterTau;
109+
int16_t x0;
110+
int16_t x2;
111+
112+
/* Calculate the first polynomial coeffcient based on the current estimate of tau */
113+
if (tauEstimate < 1) {
114+
x0 = tauEstimate;
115+
}
116+
else {
117+
x0 = tauEstimate - 1;
118+
}
119+
120+
/* Calculate the second polynomial coeffcient based on the current estimate of tau */
121+
if (tauEstimate + 1 < yin->halfBufferSize) {
122+
x2 = tauEstimate + 1;
123+
}
124+
else {
125+
x2 = tauEstimate;
126+
}
127+
128+
/* Algorithm to parabolically interpolate the shift value tau to find a better estimate */
129+
if (x0 == tauEstimate) {
130+
if (yin->yinBuffer[tauEstimate] <= yin->yinBuffer[x2]) {
131+
betterTau = tauEstimate;
132+
}
133+
else {
134+
betterTau = x2;
135+
}
136+
}
137+
else if (x2 == tauEstimate) {
138+
if (yin->yinBuffer[tauEstimate] <= yin->yinBuffer[x0]) {
139+
betterTau = tauEstimate;
140+
}
141+
else {
142+
betterTau = x0;
143+
}
144+
}
145+
else {
146+
float s0, s1, s2;
147+
s0 = yin->yinBuffer[x0];
148+
s1 = yin->yinBuffer[tauEstimate];
149+
s2 = yin->yinBuffer[x2];
150+
// fixed AUBIO implementation, thanks to Karl Helgason:
151+
// (2.0f * s1 - s2 - s0) was incorrectly multiplied with -1
152+
betterTau = tauEstimate + (s2 - s0) / (2 * (2 * s1 - s2 - s0));
153+
}
154+
155+
156+
return betterTau;
157+
}
158+
159+
160+
161+
162+
163+
/* ------------------------------------------------------------------------------------------
164+
---------------------------------------------------------------------------- PUBLIC FUNCTIONS
165+
-------------------------------------------------------------------------------------------*/
166+
167+
168+
169+
/**
170+
* Initialise the Yin pitch detection object
171+
* @param yin Yin pitch detection object to initialise
172+
* @param bufferSize Length of the audio buffer to analyse
173+
* @param threshold Allowed uncertainty (e.g 0.05 will return a pitch with ~95% probability)
174+
*/
175+
void Yin_init(Yin *yin, int16_t bufferSize, float threshold, int sampleRate) {
176+
/* Initialise the fields of the Yin structure passed in */
177+
yin->bufferSize = bufferSize;
178+
yin->halfBufferSize = bufferSize / 2;
179+
yin->probability = 0.0;
180+
yin->threshold = threshold;
181+
yin->sampleRate = (float)sampleRate / 8;
182+
183+
/* Allocate the autocorellation buffer and initialise it to zero */
184+
yin->yinBuffer = (float *) malloc(sizeof(float)* yin->halfBufferSize);
185+
186+
int16_t i;
187+
for(i = 0; i < yin->halfBufferSize; i++){
188+
yin->yinBuffer[i] = 0;
189+
}
190+
}
191+
192+
/**
193+
* Runs the Yin pitch detection algortihm
194+
* @param yin Initialised Yin object
195+
* @param buffer Buffer of samples to analyse
196+
* @return Fundamental frequency of the signal in Hz. Returns -1 if pitch can't be found
197+
*/
198+
float Yin_getPitch(Yin *yin, int16_t* buffer) {
199+
int16_t tauEstimate = -1;
200+
float pitchInHertz = -1;
201+
202+
/* Step 1: Calculates the squared difference of the signal with a shifted version of itself. */
203+
Yin_difference(yin, buffer);
204+
205+
/* Step 2: Calculate the cumulative mean on the normalised difference calculated in step 1 */
206+
Yin_cumulativeMeanNormalizedDifference(yin);
207+
208+
/* Step 3: Search through the normalised cumulative mean array and find values that are over the threshold */
209+
tauEstimate = Yin_absoluteThreshold(yin);
210+
211+
/* Step 5: Interpolate the shift value (tau) to improve the pitch estimate. */
212+
if(tauEstimate != -1){
213+
pitchInHertz = yin->sampleRate / Yin_parabolicInterpolation(yin, tauEstimate);
214+
}
215+
216+
return pitchInHertz;
217+
}
218+
219+
/**
220+
* Certainty of the pitch found
221+
* @param yin Yin object that has been run over a buffer
222+
* @return Returns the certainty of the note found as a decimal (i.e 0.3 is 30%)
223+
*/
224+
float Yin_getProbability(Yin *yin){
225+
return yin->probability;
226+
}
227+
228+
229+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#ifndef Yin_h
2+
#define Yin_h
3+
4+
#include <stdint.h>
5+
6+
#define YIN_DEFAULT_THRESHOLD 0.15
7+
8+
/**
9+
* @struct Yin
10+
* @breif Object to encapsulate the parameters for the Yin pitch detection algorithm
11+
*/
12+
typedef struct _Yin {
13+
int16_t bufferSize; /**< Size of the audio buffer to be analysed */
14+
int16_t halfBufferSize; /**< Half the buffer length */
15+
float* yinBuffer; /**< Buffer that stores the results of the intermediate processing steps of the algorithm */
16+
float probability; /**< Probability that the pitch found is correct as a decimal (i.e 0.85 is 85%) */
17+
float threshold; /**< Allowed uncertainty in the result as a decimal (i.e 0.15 is 15%) */
18+
float sampleRate;
19+
} Yin;
20+
21+
/**
22+
* Initialise the Yin pitch detection object
23+
* @param yin Yin pitch detection object to initialise
24+
* @param bufferSize Length of the audio buffer to analyse
25+
* @param threshold Allowed uncertainty (e.g 0.05 will return a pitch with ~95% probability)
26+
*/
27+
void Yin_init(Yin *yin, int16_t bufferSize, float threshold, int sampleRate);
28+
29+
/**
30+
* Runs the Yin pitch detection algortihm
31+
* @param yin Initialised Yin object
32+
* @param buffer Buffer of samples to analyse
33+
* @return Fundamental frequency of the signal in Hz. Returns -1 if pitch can't be found
34+
*/
35+
float Yin_getPitch(Yin *yin, int16_t* buffer);
36+
37+
/**
38+
* Certainty of the pitch found
39+
* @param yin Yin object that has been run over a buffer
40+
* @return Returns the certainty of the note found as a decimal (i.e 0.3 is 30%)
41+
*/
42+
float Yin_getProbability(Yin *yin);
43+
44+
45+
46+
#endif

0 commit comments

Comments
 (0)