Skip to content

Commit c9c0cde

Browse files
committed
split into different files (WIP)
add missing libraries
1 parent 76c5055 commit c9c0cde

39 files changed

+5035
-701
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
compiler = gcc
2-
source = main.c Yin.c
2+
source = main.c tools.c samples.c grains.c oscillators.c wavetables.c note.c usage.c Yin.c
33
libs = liblfds711.a -lportaudio -lwebsockets -lrt -lm -lasound -ljack -pthread -lsndfile
44
static_libs = liblfds711.a libportaudio.a libwebsockets.a -lz -lrt -lm -lasound -ljack -pthread -lsndfile
55
ssl_libs = -lssl -lcrypto

Yin.c

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

fas.h

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#ifndef _FAS_H_
2+
#define _FAS_H_
3+
4+
// standard libraries
5+
#include <getopt.h>
6+
#include <assert.h>
7+
#include <errno.h>
8+
#include <string.h>
9+
#include <strings.h>
10+
11+
#if defined(_WIN32) || defined(_WIN64)
12+
#include <conio.h>
13+
#endif
14+
15+
// libraries
16+
#include "portaudio.h"
17+
#include "libwebsockets.h"
18+
#include "inc/liblfds711.h"
19+
20+
// fas
21+
#include "tools.h"
22+
#include "types.h"
23+
#include "grains.h"
24+
#include "oscillators.h"
25+
#include "wavetables.h"
26+
#include "note.h"
27+
#include "usage.h"
28+
29+
struct _freelist_frames_data {
30+
struct lfds711_freelist_element fe;
31+
32+
struct note *data;
33+
};
34+
35+
// program settings with associated default value
36+
unsigned int fas_sample_rate = FAS_SAMPLE_RATE;
37+
unsigned int fas_frames_per_buffer = FAS_FRAMES_PER_BUFFER;
38+
unsigned int fas_deflate = FAS_DEFLATE;
39+
unsigned int fas_wavetable = FAS_WAVETABLE;
40+
#ifdef FIXED_WAVETABLE
41+
unsigned int fas_wavetable_size = 65536;
42+
unsigned int fas_wavetable_size_m1 = 65535;
43+
#else
44+
unsigned int fas_wavetable_size = FAS_WAVETABLE_SIZE;
45+
unsigned int fas_wavetable_size_m1 = FAS_WAVETABLE_SIZE - 1;
46+
#endif
47+
unsigned int fas_fps = FAS_FPS;
48+
unsigned int fas_port = FAS_PORT;
49+
unsigned int fas_rx_buffer_size = FAS_RX_BUFFER_SIZE;
50+
unsigned int fas_realtime = FAS_REALTIME;
51+
unsigned int fas_frames_queue_size = FAS_FRAMES_QUEUE_SIZE;
52+
unsigned int fas_commands_queue_size = FAS_COMMANDS_QUEUE_SIZE;
53+
unsigned int fas_ssl = FAS_SSL;
54+
unsigned int fas_output_channels = FAS_OUTPUT_CHANNELS;
55+
unsigned int frame_data_count = FAS_OUTPUT_CHANNELS / 2;
56+
float fas_noise_amount = FAS_NOISE_AMOUNT;
57+
int fas_audio_device = -1;
58+
char *fas_iface = NULL;
59+
60+
float *fas_sine_wavetable = NULL;
61+
float *fas_white_noise_table = NULL;
62+
uint16_t noise_index = 0.;
63+
64+
double note_time;
65+
double note_time_samples;
66+
double lerp_t_step;
67+
68+
PaStream *stream;
69+
70+
struct lws_context *context;
71+
72+
struct sample *samples = NULL;
73+
unsigned int samples_count = 0;
74+
75+
float **grain_envelope;
76+
77+
78+
// liblfds related
79+
enum lfds711_misc_flag overwrite_occurred_flag;
80+
81+
struct lfds711_ringbuffer_state rs; // frames related data structure
82+
struct lfds711_queue_bss_state synth_commands_queue_state;
83+
struct lfds711_freelist_state freelist_frames;
84+
85+
struct _freelist_frames_data *ffd;
86+
//
87+
88+
struct note *curr_notes = NULL;
89+
struct _freelist_frames_data *curr_freelist_frames_data = NULL;
90+
unsigned long frames_read = 0;
91+
92+
#endif

grains.c

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "grains.h"
2+
3+
struct grain *createGrains(struct sample *samples, unsigned int samples_count, unsigned int n, double base_frequency, unsigned int octaves, unsigned int sample_rate) {
4+
struct grain *g = (struct grain *)malloc(n * sizeof(struct grain));
5+
for (int i = 0; i < n; i += 1) {
6+
struct sample *smp = &samples[i%samples_count];
7+
8+
double octave_length = n / octaves;
9+
double frequency;
10+
frequency = base_frequency * pow(2, (n-i) / octave_length);
11+
12+
g[i].frames = floor(randf(0.001f, 0.02f) * sample_rate); // 1ms - 100ms
13+
g[i].frame = 0;
14+
g[i].index = floor(randf(0, smp->frames - g[i].frames - 1)) * (smp->chn + 1);
15+
g[i].speed = frequency / smp->pitch;
16+
if (g[i].speed <= 0) {
17+
g[i].speed = 1;
18+
}
19+
g[i].env_step = FAS_ENVS_SIZE / (g[i].frames / g[i].speed);
20+
g[i].env_index = 0;
21+
}
22+
23+
return g;
24+
}
25+
26+
struct grain *freeGrains(struct grain *g, unsigned int n) {
27+
free(g);
28+
29+
return NULL;
30+
}

grains.h

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef _FAS_GRAINS_H_
2+
#define _FAS_GRAINS_H_
3+
4+
#include <stdint.h>
5+
6+
#include "tools.h"
7+
#include "samples.h"
8+
#include "constants.h"
9+
10+
struct grain {
11+
float frame; // current position
12+
unsigned int frames; // duration
13+
unsigned int index; // grain position
14+
unsigned int env_type; // envelope type
15+
float speed;
16+
float env_index;
17+
float env_step;
18+
};
19+
20+
extern struct grain *createGrains(struct sample *samples, unsigned int samples_count, unsigned int n, double base_frequency, unsigned int octaves, unsigned int sample_rate);
21+
extern struct grain *freeGrains(struct grain *g, unsigned int n);
22+
23+
#endif

0 commit comments

Comments
 (0)