History

added float tTalkbox

spiricom committed 6 years ago

Commit a3ed8621 parent 77f3ac510 files · +881 −117Browse files

Unified · Split

10 files
  1. leaf/Inc/leaf-effects.h +64 −18
  2. leaf/Inc/leaf-math.h +2 −0
  3. leaf/Inc/leaf-physical.h +48 −0
  4. leaf/Inc/leaf-sampling.h +3 −0
  5. leaf/Src/leaf-analysis.c +11 −4
  6. leaf/Src/leaf-effects.c +464 −80
  7. leaf/Src/leaf-math.c +17 −6
  8. leaf/Src/leaf-physical.c +246 −0
  9. leaf/Src/leaf-sampling.c +25 −8
  10. leaf/Src/leaf-tables.c +1 −1
leaf/Inc/leaf-effects.h+64−18
@@ -1,8 +1,7 @@
11 /*==============================================================================
22
33 leaf-effects.h
4− Created: 20 Jan 2017 12:01:54pm
5− Author: Michael R Mulshine
4+
65
76 ==============================================================================*/
87
@@ -21,14 +20,8 @@ extern "C" { · 12 unmodified lines
2120 #include "leaf-analysis.h"
2221 #include "leaf-envelopes.h"
2322
24− /*!
25− * @internal
26− * Header.
27− * @include basic-oscillators.h
28− * @example basic-oscillators.c
29− * An example.
30− */
31−
23+
24+
3225 //==============================================================================
3326
3427 /* tTalkbox */
@@ -37,23 +30,23 @@ extern "C" { · 2 unmodified lines
3730 typedef struct _tTalkbox
3831 {
3932 float param[NUM_TALKBOX_PARAM];
40−
33+
4134 int bufsize;
4235 float* car0;
4336 float* car1;
4437 float* window;
4538 float* buf0;
4639 float* buf1;
47−
40+ float* k;
4841 float warpFactor;
4942 int32_t warpOn;
50−
43+ int freeze;
5144 float emphasis;
5245 int32_t K, N, O, pos;
5346 float wet, dry, FX;
5447 float d0, d1, d2, d3, d4;
5548 float u0, u1, u2, u3, u4;
56−
49+ float G;
5750 double* dl;
5851 double* Rt;
5952
@@ -68,16 +61,69 @@ extern "C" { · 8 unmodified lines
6861 void tTalkbox_freeFromPool (tTalkbox* const, tMempool* const);
6962
7063 float tTalkbox_tick (tTalkbox* const, float synth, float voice);
64+ float tTalkbox_tickFrozen (tTalkbox* const voc, float synth, float voice);
7165 void tTalkbox_update (tTalkbox* const);
7266 void tTalkbox_suspend (tTalkbox* const);
7367 void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g);
74− void tTalkbox_lpc (float *buf, float *car, double* dl, double* Rt, int32_t n, int32_t o, float warp, int warpOn);
68+ void tTalkbox_lpc (float *buf, float *car, double* dl, double* Rt, int32_t n, int32_t o, float warp, int warpOn, float *k, int freeze, float *G);
7569 void tTalkbox_setQuality (tTalkbox* const, float quality);
76− void tTalkbox_setWarpFactor (tTalkbox* const voc, float warp);
70+ void tTalkbox_setWarpFactor (tTalkbox* const voc, float warp);
7771 void tTalkbox_setWarpOn (tTalkbox* const voc, float warpOn);
72+ void tTalkbox_setFreeze (tTalkbox* const voc, float freeze);
7873 void tTalkbox_warpedAutocorrelate (float * x, double* dl, double* Rt, unsigned int L, float * R, unsigned int P, float lambda);
7974 //==============================================================================
8075
76+
77+ ///////
78+
79+ typedef struct _tTalkboxFloat
80+ {
81+ float param[NUM_TALKBOX_PARAM];
82+
83+ int bufsize;
84+ float* car0;
85+ float* car1;
86+ float* window;
87+ float* buf0;
88+ float* buf1;
89+ float* k;
90+ float warpFactor;
91+ int32_t warpOn;
92+ int freeze;
93+ float emphasis;
94+ int32_t K, N, O, pos;
95+ float wet, dry, FX;
96+ float d0, d1, d2, d3, d4;
97+ float u0, u1, u2, u3, u4;
98+ float G;
99+ float* dl;
100+ float* Rt;
101+
102+
103+ } _tTalkboxFloat;
104+
105+ typedef _tTalkboxFloat* tTalkboxFloat;
106+
107+ void tTalkboxFloat_init (tTalkboxFloat* const, int bufsize);
108+ void tTalkboxFloat_free (tTalkboxFloat* const);
109+ void tTalkboxFloat_initToPool (tTalkboxFloat* const, int bufsize, tMempool* const);
110+ void tTalkboxFloat_freeFromPool (tTalkboxFloat* const, tMempool* const);
111+
112+ float tTalkboxFloat_tick (tTalkboxFloat* const, float synth, float voice);
113+ float tTalkboxFloat_tickFrozen (tTalkboxFloat* const voc, float synth, float voice);
114+ void tTalkboxFloat_update (tTalkboxFloat* const);
115+ void tTalkboxFloat_suspend (tTalkboxFloat* const);
116+ void tTalkboxFloat_lpcDurbin (float *r, int p, float *k, float *g);
117+ void tTalkboxFloat_lpc (float *buf, float *car, float* dl, float* Rt, int32_t n, int32_t o, float warp, int warpOn, float *k, int freeze, float *G);
118+ void tTalkboxFloat_setQuality (tTalkboxFloat* const, float quality);
119+ void tTalkboxFloat_setWarpFactor (tTalkboxFloat* const voc, float warp);
120+ void tTalkboxFloat_setWarpOn (tTalkboxFloat* const voc, float warpOn);
121+ void tTalkboxFloat_setFreeze (tTalkboxFloat* const voc, float freeze);
122+ void tTalkboxFloat_warpedAutocorrelate (float * x, float* dl, float* Rt, unsigned int L, float * R, unsigned int P, float lambda);
123+ //==============================================================================
124+
125+
126+
81127 /* tVocoder */
82128 #define NUM_VOCODER_PARAM 8
83129 #define NBANDS 16
@@ -132,7 +178,7 @@ extern "C" { · 48 unmodified lines
132178 void tRosenbergGlottalPulse_freeFromPool (tRosenbergGlottalPulse* const, tMempool* const);
133179
134180 float tRosenbergGlottalPulse_tick (tRosenbergGlottalPulse* const);
135−
181+ float tRosenbergGlottalPulse_tickHQ (tRosenbergGlottalPulse* const gp);
136182 void tRosenbergGlottalPulse_setFreq (tRosenbergGlottalPulse* const, float freq);
137183
138184 void tRosenbergGlottalPulse_setOpenLength (tRosenbergGlottalPulse* const, float openLength);
@@ -284,7 +330,7 @@ extern "C" { · 145 unmodified lines
284330 float radius;
285331
286332 float inputPeriod;
287−
333+ int shiftOn;
288334 int numVoices;
289335 } _tAutotune;
290336
leaf/Inc/leaf-math.h+2−0
@@ -204,6 +204,8 @@ extern "C" { · 203 unmodified lines
204204
205205 float fastdbtoa(float db);
206206
207+ float fasterdbtoa(float db);
208+
207209 float maximum (float num1, float num2);
208210
209211 float minimum (float num1, float num2);
leaf/Inc/leaf-physical.h+48−0
@@ -228,7 +228,55 @@ extern "C" { · 227 unmodified lines
228228 void tLivingString_setLevStrength (tLivingString* const, float levStrength);
229229 void tLivingString_setLevMode (tLivingString* const, int levMode);
230230
231+
232+
233+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
234+
235+ /* Complex Living String */
236+ typedef struct _tComplexLivingString {
237+ float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length
238+ float pickPos; // the pick position, dividing the string, in ratio
239+ float prepPos; // preparation position, in ratio
240+ int prepLower;
241+ float prepIndex; // the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj)
242+ float dampFreq; // frequency for the bridge LP filter, in Hz
243+ float decay; // amplitude damping factor for the string (only active in mode 0)
244+ float levMode;
245+ float curr;
246+ tLinearDelay delLF,delUF, delMF, delMB, delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model
247+ tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL;
248+ tHighpass DCblockerL, DCblockerU;
249+ tFeedbackLeveler fbLevU, fbLevL;
250+ tExpSmooth wlSmooth, pickPosSmooth, prepPosSmooth;
251+ } _tComplexLivingString;
252+
253+ typedef _tComplexLivingString* tComplexLivingString;
254+
255+ void tComplexLivingString_init (tComplexLivingString* const, float freq, float pickPos, float prepPos, float prepIndex,
256+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
257+ float levStrength, int levMode);
258+ void tComplexLivingString_free (tComplexLivingString* const);
259+ void tComplexLivingString_initToPool (tComplexLivingString* const, float freq, float pickPos, float prepPos, float prepIndex,
260+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
261+ float levStrength, int levMode, tMempool* const);
262+ void tComplexLivingString_freeFromPool (tComplexLivingString* const, tMempool* const);
263+
264+ float tComplexLivingString_tick (tComplexLivingString* const, float input);
265+ float tComplexLivingString_sample (tComplexLivingString* const);
266+ void tComplexLivingString_setFreq (tComplexLivingString* const, float freq);
267+ void tComplexLivingString_setWaveLength (tComplexLivingString* const, float waveLength); // in samples
268+ void tComplexLivingString_setPickPos (tComplexLivingString* const, float pickPos);
269+ void tComplexLivingString_setPrepPos (tComplexLivingString* const, float prepPos);
270+ void tComplexLivingString_setPrepIndex (tComplexLivingString* const, float prepIndex);
271+ void tComplexLivingString_setDampFreq (tComplexLivingString* const, float dampFreq);
272+ void tComplexLivingString_setDecay (tComplexLivingString* const, float decay); // should be near 1.0
273+ void tComplexLivingString_setTargetLev (tComplexLivingString* const, float targetLev);
274+ void tComplexLivingString_setLevSmoothFactor (tComplexLivingString* const, float levSmoothFactor);
275+ void tComplexLivingString_setLevStrength (tComplexLivingString* const, float levStrength);
276+ void tComplexLivingString_setLevMode (tComplexLivingString* const, int levMode);
231277 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
278+
279+
232280
233281 //Reed Table - borrowed from STK
234282 typedef struct _tReedTable {
leaf/Inc/leaf-sampling.h+3−0
@@ -69,6 +69,7 @@ extern "C" { · 68 unmodified lines
6969 void tBuffer_record (tBuffer* const);
7070 void tBuffer_stop (tBuffer* const);
7171 int tBuffer_getRecordPosition (tBuffer* const);
72+ void tBuffer_setRecordPosition (tBuffer* const, int pos);
7273
7374 void tBuffer_setRecordMode (tBuffer* const, RecordMode mode);
7475
@@ -76,6 +77,8 @@ extern "C" { · 1 unmodified line
7677
7778 uint32_t tBuffer_getBufferLength (tBuffer* const);
7879 uint32_t tBuffer_getRecordedLength (tBuffer* const sb);
80+ void tBuffer_setRecordedLength (tBuffer* const sb, int length);
81+ int tBuffer_isActive (tBuffer* const sb);
7982
8083 //==============================================================================
8184
leaf/Src/leaf-analysis.c+11−4
@@ -62,8 +62,10 @@ float tEnvelopeFollower_tick(tEnvelopeFollower* const ef, float x) · 61 unmodified lines
6262 //ef->y = envelope_pow[(uint16_t)(ef->y * (float)UINT16_MAX)] * ef->d_coeff; //not quite the right behavior - too much loss of precision?
6363 //ef->y = powf(ef->y, 1.000009f) * ef->d_coeff; // too expensive
6464
65+#ifdef NO_DENORMAL_CHECK
66+#else
6567 if( e->y < VSF) e->y = 0.0f;
66−
68+#endif
6769 return e->y;
6870 }
6971
@@ -887,7 +889,10 @@ void tPeriodDetection_initToPool (tPeriodDetection* const pd, float* in, flo · 817 unmodified lines
887889 tEnvPD_initToPool(&p->env, p->windowSize, p->hopSize, p->frameSize, mp);
888890
889891 tSNAC_initToPool(&p->snac, DEFOVERLAP, mp);
890−
892+
893+ p->history = 0.0f;
894+ p->alpha = 1.0f;
895+ p->tolerance = 1.0f;
891896 p->timeConstant = DEFTIMECONSTANT;
892897 p->radius = expf(-1000.0f * p->hopSize * leaf.invSampleRate / p->timeConstant);
893898 p->fidelityThreshold = 0.95;
@@ -928,14 +933,16 @@ float tPeriodDetection_tick (tPeriodDetection* pd, float sample) · 34 unmodified lines
928933 tSNAC_ioSamples(&p->snac, &(p->inBuffer[i]), &(p->outBuffer[i]), p->frameSize);
929934 float fidelity = tSNAC_getFidelity(&p->snac);
930935 // Fidelity threshold recommended by Katja Vetters is 0.95 for most instruments/voices http://www.katjaas.nl/helmholtz/helmholtz.html
931− if (fidelity > p->fidelityThreshold) p->period = tSNAC_getPeriod(&p->snac);
936+ if (fidelity > p->fidelityThreshold)
937+ {
938+ p->period = tSNAC_getPeriod(&p->snac);
939+ }
932940
933941 p->curBlock++;
934942 if (p->curBlock >= p->framesPerBuffer) p->curBlock = 0;
935943 p->lastBlock++;
936944 if (p->lastBlock >= p->framesPerBuffer) p->lastBlock = 0;
937945 }
938−
939946 return p->period;
940947 }
941948
leaf/Src/leaf-effects.c+464−80
@@ -25,6 +25,13 @@ · 24 unmodified lines
2525 //============================================================================================================
2626
2727 //LPC vocoder adapted from MDA's excellent open source talkbox plugin code
28+
29+#define ORD_MAX 34 // Was 100.
30+// order is defined by the set_quality function.
31+// it's set to max out at 0.0005 of sample rate (if you don't go above 1.0f in the quality setting) == at 48000 that's 24.
32+// -JS
33+
34+
2835 void tTalkbox_init(tTalkbox* const voc, int bufsize)
2936 {
3037 tTalkbox_initToPool(voc, bufsize, &leaf.mempool);
@@ -47,7 +54,8 @@ void tTalkbox_initToPool (tTalkbox* const voc, int bufsize, tMempool* con · 16 unmodified lines
4754 v->warpFactor = 0.0f;
4855 v->warpOn = 0;
4956 v->bufsize = bufsize;
50−
57+ v->freeze = 0;
58+ v->G = 0.0f;
5159 v->car0 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
5260 v->car1 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
5361 v->window = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
@@ -56,7 +64,9 @@ void tTalkbox_initToPool (tTalkbox* const voc, int bufsize, tMempool* con · 2 unmodified lines
5664
5765 v->dl = (double*) mpool_alloc(sizeof(double) * v->bufsize, m);
5866 v->Rt = (double*) mpool_alloc(sizeof(double) * v->bufsize, m);
59−
67+
68+ v->k = (float*) mpool_alloc(sizeof(float) * ORD_MAX, m);
69+
6070 tTalkbox_update(voc);
6171 tTalkbox_suspend(voc);
6272 }
@@ -74,7 +84,7 @@ void tTalkbox_freeFromPool (tTalkbox* const voc, tMempool* const mp) · 11 unmodified lines
7484
7585 mpool_free((char*)v->dl, m);
7686 mpool_free((char*)v->Rt, m);
77−
87+ mpool_free((char*)v->k, m);
7888 mpool_free((char*)v, m);
7989 }
8090
@@ -132,89 +142,173 @@ void tTalkbox_suspend(tTalkbox* const voc) ///clear any buffers... · 51 unmodified lines
132142 //wAutocorrelate(&pfSrc[stIndex],siglen,R,P,0);
133143 void tTalkbox_warpedAutocorrelate(float * x, double* dl, double* Rt, unsigned int L, float * R, unsigned int P, float lambda)
134144 {
135−// double dl[L];
136−// double Rt[L];
137145 double r1,r2,r1t;
138146 R[0]=0;
139147 Rt[0]=0;
140148 r1=0;
141149 r2=0;
142150 r1t=0;
143− for(int32_t k=0; k<L;k++)
151+ for(uint32_t m=0; m<L;m++)
144152 {
145− Rt[0] += (double)(x[k]) * (double)(x[k]);
153+ Rt[0] += (double)(x[m]) * (double)(x[m]);
146154
147− dl[k]= r1 - (double)(lambda) * (double)(x[k]-r2);
148− r1 = x[k];
149− r2 = dl[k];
155+ dl[m]= r1 - (double)(lambda) * (double)(x[m]-r2);
156+ r1 = x[m];
157+ r2 = dl[m];
150158 }
151− for(int32_t i=1; i<=P; i++)
159+ for(uint32_t i=1; i<=P; i++)
152160 {
153161 Rt[i]=0;
154162 r1=0;
155163 r2=0;
156− for(unsigned int k=0; k<L;k++)
164+ for(unsigned int m=0; m<L;m++)
157165 {
158− Rt[i] += (double) (dl[k]) * (double)(x[k]);
166+ Rt[i] += (double) (dl[m]) * (double)(x[m]);
159167
160− r1t = dl[k];
161− dl[k]= r1 - (double)(lambda) * (double)(r1t-r2);
168+ r1t = dl[m];
169+ dl[m]= r1 - (double)(lambda) * (double)(r1t-r2);
162170 r1 = r1t;
163− r2 = dl[k];
171+ r2 = dl[m];
164172 }
165173 }
166− for(int32_t i=0; i<=P; i++)
174+ for(uint32_t i=0; i<=P; i++)
167175 {
168176 R[i]=(float)(Rt[i]);
169177 }
170178
171179 }
172180
173−
174−
175−#define ORD_MAX 35 // Was 100.
176−// order is defined by the set_quality function.
177−// it's set to max out at 0.0005 of sample rate (if you don't go above 1.0f in the quality setting) == at 48000 that's 24.
178−// -JS
179−void tTalkbox_lpc(float *buf, float *car, double* dl, double* Rt, int32_t n, int32_t o, float warp, int warpOn)
181+void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g)
180182 {
181− float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x;
182− int32_t i, j, nn=n;
183−
184− if (warpOn == 0)
183+ int i, j;
184+ float a[ORD_MAX], at[ORD_MAX], e=r[0];
185+
186+ for(i=0; i<=p; i++)
185187 {
186− for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
187− {
188− z[j] = r[j] = 0.0f;
189− for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation
190− }
188+ a[i] = 0.0f; //probably don't need to clear at[] or k[]
191189 }
192− else
190+ k[0] = 0.0f;
191+ at[0] = 0.0f;
192+ for(i=1; i<=p; i++)
193193 {
194− for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
194+ k[i] = -r[i];
195+
196+ for(j=1; j<i; j++)
195197 {
196− z[j] = r[j] = 0.0f;
198+ at[j] = a[j];
199+ k[i] -= a[j] * r[i-j];
197200 }
198− tTalkbox_warpedAutocorrelate(buf, dl, Rt, n, r, o, warp);
201+ if(fabs(e) < 1.0e-20f) { e = 0.0f; break; }
202+ k[i] /= e;
203+
204+ a[i] = k[i];
205+ for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j];
206+
207+ e *= 1.0f - k[i] * k[i];
199208 }
200209
201− r[0] *= 1.001f; //stability fix
210+ if(e < 1.0e-20f) e = 0.0f;
211+ *g = sqrtf(e);
212+}
213+
214+float tTalkbox_tick(tTalkbox* const voc, float synth, float voice)
215+{
216+ _tTalkbox* v = *voc;
202217
203− float min = 0.00001f;
204− if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; }
218+ int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N;
219+ float e=v->emphasis, w, o, x, fx=v->FX;
220+ float p, q, h0=0.3f, h1=0.77f;
205221
206− tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs
222+ o = voice;
223+ x = synth;
224+
225+
226+
227+ p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p;
228+ q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q;
229+ v->d4 = x;
230+ x = p + q;
207231
208− //this is for stability to keep reflection coefficients inside the unit circle
209− //but in Harma's papers I've seen 0.998. just needs to be less than 1 it seems but maybe some wiggle room to avoid instability from floating point precision -JS
210− for(i=0; i<=o; i++)
232+ if(v->K++)
211233 {
212− if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f;
234+ v->K = 0;
235+
236+ v->car0[p0] = v->car1[p1] = x; //carrier input
237+
238+ x = o - e; e = o; //6dB/oct pre-emphasis
239+
240+ w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows
241+ if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->dl, v->Rt, v->N, v->O, v->warpFactor, v->warpOn, v->k, v->freeze, &v->G); p0 = 0; }
242+
243+ w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w;
244+ if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->dl, v->Rt, v->N, v->O, v->warpFactor, v->warpOn, v->k, v->freeze, &v->G); p1 = 0; }
213245 }
214246
247+ p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p;
248+ q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q;
249+ v->u4 = fx;
250+ x = p + q;
251+
252+ o = x;
253+
254+ v->emphasis = e;
255+ v->pos = p0;
256+ v->FX = fx;
257+
258+
259+ return o;
260+}
261+
262+
263+void tTalkbox_lpc(float *buf, float *car, double* dl, double* Rt, int32_t n, int32_t o, float warp, int warpOn, float *k, int freeze, float *G)
264+{
265+ float z[ORD_MAX], r[ORD_MAX], x;
266+ int32_t i, j, nn=n;
267+
268+
269+ if (warpOn == 0)
270+ {
271+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
272+ {
273+ z[j] = r[j] = 0.0f;
274+ for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation
275+ }
276+ }
277+ else
278+ {
279+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
280+ {
281+ z[j] = r[j] = 0.0f;
282+ }
283+ tTalkbox_warpedAutocorrelate(buf, dl, Rt, n, r, o, warp);
284+ }
285+
286+ r[0] *= 1.001f; //stability fix
287+
288+ float min = 0.000001f;
289+ if (!freeze)
290+ {
291+ if(r[0] < min)
292+ {
293+ for(i=0; i<n; i++)
294+ {
295+ buf[i] = 0.0f;
296+ return;
297+ }
298+ }
299+
300+ tTalkbox_lpcDurbin(r, o, k, G); //calc reflection coeffs
301+
302+ //this is for stability to keep reflection coefficients inside the unit circle
303+ //in mda's code it's .995 but in Harma's papers I've seen 0.998. just needs to be less than 1 it seems but maybe some wiggle room to avoid instability from floating point precision -JS
304+ for(i=0; i<=o; i++)
305+ {
306+ if(k[i] > 0.998f) k[i] = 0.998f; else if(k[i] < -0.998f) k[i] = -.998f;
307+ }
308+ }
215309 for(i=0; i<n; i++)
216310 {
217− x = G * car[i];
311+ x = G[0] * car[i];
218312 for(j=o; j>0; j--) //lattice filter
219313 {
220314 x -= k[j] * z[j-1];
@@ -224,18 +318,213 @@ void tTalkbox_lpc(float *buf, float *car, double* dl, double* Rt, int32_t n, int · 3 unmodified lines
224318 }
225319 }
226320
321+void tTalkbox_setQuality(tTalkbox* const voc, float quality)
322+{
323+ _tTalkbox* v = *voc;
324+ v->param[3] = quality;
325+ v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate);
326+ if (v->O >= ORD_MAX)
327+ {
328+ v->O = ORD_MAX-1;
329+ }
330+}
227331
228−void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g)
332+void tTalkbox_setWarpFactor(tTalkbox* const voc, float warpFactor)
333+{
334+ _tTalkbox* v = *voc;
335+
336+ v->warpFactor = warpFactor;
337+}
338+
339+void tTalkbox_setWarpOn(tTalkbox* const voc, float warpOn)
340+{
341+ _tTalkbox* v = *voc;
342+
343+ v->warpOn = warpOn;
344+}
345+
346+void tTalkbox_setFreeze(tTalkbox* const voc, float freeze)
347+{
348+ _tTalkbox* v = *voc;
349+
350+ v->freeze = freeze;
351+}
352+
353+
354+
355+////
356+
357+// LPC vocoder adapted from MDA's excellent open source talkbox plugin code
358+// order is defined by the set_quality function.
359+// it's set to max out at 0.0005 of sample rate (if you don't go above 1.0f in the quality setting) == at 48000 that's 24.
360+
361+//the "float" version has no double calculations for faster computation on single-precision FPUs
362+
363+// -JS
364+
365+
366+void tTalkboxFloat_init(tTalkboxFloat* const voc, int bufsize)
367+{
368+ tTalkboxFloat_initToPool(voc, bufsize, &leaf.mempool);
369+}
370+
371+void tTalkboFloat_free(tTalkboxFloat* const voc)
372+{
373+ tTalkboxFloat_freeFromPool(voc, &leaf.mempool);
374+}
375+
376+void tTalkboxFloat_initToPool (tTalkboxFloat* const voc, int bufsize, tMempool* const mp)
377+{
378+ _tMempool* m = *mp;
379+ _tTalkboxFloat* v = *voc = (_tTalkboxFloat*) mpool_alloc(sizeof(_tTalkboxFloat), m);
380+
381+ v->param[0] = 0.5f; //wet
382+ v->param[1] = 0.0f; //dry
383+ v->param[2] = 0; // Swap
384+ v->param[3] = 1.0f; //quality
385+ v->warpFactor = 0.0f;
386+ v->warpOn = 0;
387+ v->bufsize = bufsize;
388+ v->freeze = 0;
389+ v->G = 0.0f;
390+ v->car0 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
391+ v->car1 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
392+ v->window = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
393+ v->buf0 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
394+ v->buf1 = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
395+
396+ v->dl = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
397+ v->Rt = (float*) mpool_alloc(sizeof(float) * v->bufsize, m);
398+
399+ v->k = (float*) mpool_alloc(sizeof(float) * ORD_MAX, m);
400+
401+ tTalkboxFloat_update(voc);
402+ tTalkboxFloat_suspend(voc);
403+}
404+
405+void tTalkboxFloat_freeFromPool (tTalkboxFloat* const voc, tMempool* const mp)
406+{
407+ _tMempool* m = *mp;
408+ _tTalkboxFloat* v = *voc;
409+
410+ mpool_free((char*)v->buf1, m);
411+ mpool_free((char*)v->buf0, m);
412+ mpool_free((char*)v->window, m);
413+ mpool_free((char*)v->car1, m);
414+ mpool_free((char*)v->car0, m);
415+
416+ mpool_free((char*)v->dl, m);
417+ mpool_free((char*)v->Rt, m);
418+ mpool_free((char*)v->k, m);
419+ mpool_free((char*)v, m);
420+}
421+
422+void tTalkboxFloat_update(tTalkboxFloat* const voc) ///update internal parameters...
423+{
424+ _tTalkboxFloat* v = *voc;
425+
426+ float fs = leaf.sampleRate;
427+ if(fs < 8000.0f) fs = 8000.0f;
428+ if(fs > 96000.0f) fs = 96000.0f;
429+
430+ int32_t n = (int32_t)(0.01633f * fs); //this sets the window time to 16ms if the buffer is large enough. Buffer needs to be at least 784 samples at 48000
431+ if(n > v->bufsize) n = v->bufsize;
432+
433+ //O = (VstInt32)(0.0005f * fs);
434+ v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs);
435+
436+ if(n != v->N) //recalc hanning window
437+ {
438+ v->N = n;
439+ float dp = TWO_PI / v->N;
440+ float p = 0.0f;
441+ for(n=0; n<v->N; n++)
442+ {
443+ v->window[n] = 0.5f - 0.5f * cosf(p);
444+ p += dp;
445+ }
446+ }
447+ v->wet = 0.5f * v->param[0] * v->param[0];
448+ v->dry = 2.0f * v->param[1] * v->param[1];
449+}
450+
451+void tTalkboxFloat_suspend(tTalkboxFloat* const voc) ///clear any buffers...
452+{
453+ _tTalkboxFloat* v = *voc;
454+
455+ v->pos = v->K = 0;
456+ v->emphasis = 0.0f;
457+ v->FX = 0;
458+
459+ v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f;
460+ v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f;
461+
462+ for (int32_t i = 0; i < v->bufsize; i++)
463+ {
464+ v->buf0[i] = 0;
465+ v->buf1[i] = 0;
466+ v->car0[i] = 0;
467+ v->car1[i] = 0;
468+ }
469+}
470+
471+// warped autocorrelation adapted from ten.enegatum@liam's post on music-dsp 2004-04-07 09:37:51
472+//find the order-P autocorrelation array, R, for the sequence x of length L and warping of lambda
473+//wAutocorrelate(&pfSrc[stIndex],siglen,R,P,0);
474+void tTalkboxFloat_warpedAutocorrelate(float * x, float* dl, float* Rt, unsigned int L, float * R, unsigned int P, float lambda)
475+{
476+ float r1,r2,r1t;
477+ R[0]=0;
478+ Rt[0]=0;
479+ r1=0;
480+ r2=0;
481+ r1t=0;
482+ for(uint32_t m=0; m<L;m++)
483+ {
484+ Rt[0] += (x[m]) * (x[m]);
485+
486+ dl[m]= r1 - lambda * (x[m]-r2);
487+ r1 = x[m];
488+ r2 = dl[m];
489+ }
490+ for(uint32_t i=1; i<=P; i++)
491+ {
492+ Rt[i]=0;
493+ r1=0;
494+ r2=0;
495+ for(unsigned int m=0; m<L;m++)
496+ {
497+ Rt[i] += (dl[m]) * (x[m]);
498+
499+ r1t = dl[m];
500+ dl[m]= r1 - lambda * (r1t-r2);
501+ r1 = r1t;
502+ r2 = dl[m];
503+ }
504+ }
505+ for(uint32_t i=0; i<=P; i++)
506+ {
507+ R[i]=Rt[i];
508+ }
509+
510+}
511+
512+void tTalkboxFloat_lpcDurbin(float *r, int p, float *k, float *g)
229513 {
230514 int i, j;
231515 float a[ORD_MAX], at[ORD_MAX], e=r[0];
232−
233− for(i=0; i<=p; i++) a[i] = 0.0f; //probably don't need to clear at[] or k[]
516+
517+ for(i=0; i<=p; i++)
518+ {
519+ a[i] = 0.0f; //probably don't need to clear at[]
520+
521+ }
522+ k[0] = 0.0f;
234523 at[0] = 0.0f;
235524 for(i=1; i<=p; i++)
236525 {
237526 k[i] = -r[i];
238−
527+
239528 for(j=1; j<i; j++)
240529 {
241530 at[j] = a[j];
@@ -243,69 +532,127 @@ void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g) · 1 unmodified line
243532 }
244533 if(fabs(e) < 1.0e-20f) { e = 0.0f; break; }
245534 k[i] /= e;
246−
535+
247536 a[i] = k[i];
248537 for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j];
249−
538+
250539 e *= 1.0f - k[i] * k[i];
251540 }
252−
541+
253542 if(e < 1.0e-20f) e = 0.0f;
254543 *g = sqrtf(e);
255544 }
256545
257−float tTalkbox_tick(tTalkbox* const voc, float synth, float voice)
546+float tTalkboxFloat_tick(tTalkboxFloat* const voc, float synth, float voice)
258547 {
259− _tTalkbox* v = *voc;
260−
548+ _tTalkboxFloat* v = *voc;
549+
261550 int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N;
262551 float e=v->emphasis, w, o, x, fx=v->FX;
263552 float p, q, h0=0.3f, h1=0.77f;
264−
553+
265554 o = voice;
266555 x = synth;
267−
556+
268557
269558
270559 p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p;
271560 q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q;
272561 v->d4 = x;
273562 x = p + q;
274−
563+
275564 if(v->K++)
276565 {
277566 v->K = 0;
278−
567+
279568 v->car0[p0] = v->car1[p1] = x; //carrier input
280−
569+
281570 x = o - e; e = o; //6dB/oct pre-emphasis
282−
571+
283572 w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows
284− if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->dl, v->Rt, v->N, v->O, v->warpFactor, v->warpOn); p0 = 0; }
285−
573+ if(++p0 >= v->N) { tTalkboxFloat_lpc(v->buf0, v->car0, v->dl, v->Rt, v->N, v->O, v->warpFactor, v->warpOn, v->k, v->freeze, &v->G); p0 = 0; }
574+
286575 w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w;
287− if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->dl, v->Rt, v->N, v->O, v->warpFactor, v->warpOn); p1 = 0; }
576+ if(++p1 >= v->N) { tTalkboxFloat_lpc(v->buf1, v->car1, v->dl, v->Rt, v->N, v->O, v->warpFactor, v->warpOn, v->k, v->freeze, &v->G); p1 = 0; }
288577 }
289−
578+
290579 p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p;
291580 q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q;
292581 v->u4 = fx;
293582 x = p + q;
294−
583+
295584 o = x;
296−
585+
297586 v->emphasis = e;
298587 v->pos = p0;
299588 v->FX = fx;
300−
589+
301590
302591 return o;
303592 }
304593
305−void tTalkbox_setQuality(tTalkbox* const voc, float quality)
594+
595+void tTalkboxFloat_lpc(float *buf, float *car, float* dl, float* Rt, int32_t n, int32_t o, float warp, int warpOn, float *k, int freeze, float *G)
306596 {
307− _tTalkbox* v = *voc;
308−
597+ float z[ORD_MAX], r[ORD_MAX], x;
598+ int32_t i, j, nn=n;
599+
600+
601+ if (warpOn == 0)
602+ {
603+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
604+ {
605+ z[j] = r[j] = 0.0f;
606+ for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation
607+ }
608+ }
609+ else
610+ {
611+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
612+ {
613+ z[j] = r[j] = 0.0f;
614+ }
615+ tTalkboxFloat_warpedAutocorrelate(buf, dl, Rt, n, r, o, warp);
616+ }
617+
618+ r[0] *= 1.001f; //stability fix
619+
620+ float min = 0.000001f;
621+ if (!freeze)
622+ {
623+ if(r[0] < min)
624+ {
625+ for(i=0; i<n; i++)
626+ {
627+ buf[i] = 0.0f;
628+ return;
629+ }
630+ }
631+
632+ tTalkbox_lpcDurbin(r, o, k, G); //calc reflection coeffs
633+
634+ //this is for stability to keep reflection coefficients inside the unit circle
635+ //but in Harma's papers I've seen 0.998. just needs to be less than 1 it seems but maybe some wiggle room to avoid instability from floating point precision -JS
636+ for(i=0; i<=o; i++)
637+ {
638+ if(k[i] > 0.998f) k[i] = 0.998f; else if(k[i] < -0.998f) k[i] = -.998f;
639+ }
640+ }
641+ for(i=0; i<n; i++)
642+ {
643+ x = G[0] * car[i];
644+ for(j=o; j>0; j--) //lattice filter
645+ {
646+ x -= k[j] * z[j-1];
647+ z[j] = z[j-1] + k[j] * x;
648+ }
649+ buf[i] = z[0] = x; //output buf[] will be windowed elsewhere
650+ }
651+}
652+
653+void tTalkboxFloat_setQuality(tTalkboxFloat* const voc, float quality)
654+{
655+ _tTalkboxFloat* v = *voc;
309656 v->param[3] = quality;
310657 v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate);
311658 if (v->O >= ORD_MAX)
@@ -314,20 +661,27 @@ void tTalkbox_setQuality(tTalkbox* const voc, float quality) · 2 unmodified lines
314661 }
315662 }
316663
317−void tTalkbox_setWarpFactor(tTalkbox* const voc, float warpFactor)
664+void tTalkboxFloat_setWarpFactor(tTalkboxFloat* const voc, float warpFactor)
318665 {
319− _tTalkbox* v = *voc;
666+ _tTalkboxFloat* v = *voc;
320667
321668 v->warpFactor = warpFactor;
322669 }
323670
324−void tTalkbox_setWarpOn(tTalkbox* const voc, float warpOn)
671+void tTalkboxFloat_setWarpOn(tTalkboxFloat* const voc, float warpOn)
325672 {
326− _tTalkbox* v = *voc;
673+ _tTalkboxFloat* v = *voc;
327674
328675 v->warpOn = warpOn;
329676 }
330677
678+void tTalkboxFloat_setFreeze(tTalkboxFloat* const voc, float freeze)
679+{
680+ _tTalkboxFloat* v = *voc;
681+
682+ v->freeze = freeze;
683+}
684+
331685
332686 //============================================================================================================
333687 // VOCODER
@@ -374,7 +728,7 @@ void tVocoder_update (tVocoder* const voc) · 40 unmodified lines
374728
375729 float tpofs = 6.2831853f * leaf.invSampleRate;
376730
377− float rr, th, re;
731+ float rr, th;
378732
379733 float sh;
380734
@@ -389,7 +743,7 @@ void tVocoder_update (tVocoder* const voc) · 8 unmodified lines
389743 if(v->param[7]<0.5f)
390744 {
391745 v->nbnd=8;
392− re=0.003f;
746+
393747 v->f[1][2] = 3000.0f;
394748 v->f[2][2] = 2200.0f;
395749 v->f[3][2] = 1500.0f;
@@ -401,7 +755,7 @@ void tVocoder_update (tVocoder* const voc) · 5 unmodified lines
401755 else
402756 {
403757 v->nbnd=16;
404− re=0.0015f;
758+
405759 v->f[ 1][2] = 5000.0f; //+1000
406760 v->f[ 2][2] = 4000.0f; //+750
407761 v->f[ 3][2] = 3250.0f; //+500
@@ -588,6 +942,35 @@ float tRosenbergGlottalPulse_tick (tRosenbergGlottalPulse* const gp) · 180 unmodified lines
588942 return output;
589943 }
590944
945+
946+float tRosenbergGlottalPulse_tickHQ (tRosenbergGlottalPulse* const gp)
947+{
948+ _tRosenbergGlottalPulse* g = *gp;
949+
950+ float output = 0.0f;
951+
952+ // Phasor increment
953+ g->phase += g->inc;
954+ while (g->phase >= 1.0f) g->phase -= 1.0f;
955+ while (g->phase < 0.0f) g->phase += 1.0f;
956+
957+ if (g->phase < g->openLength)
958+ {
959+ output = 0.5f*(1.0f-cosf(PI * g->phase));
960+ }
961+
962+ else if (g->phase < g->pulseLength)
963+ {
964+ output = cosf(HALF_PI * (g->phase-g->openLength)* g->invPulseLengthMinusOpenLength);
965+ }
966+
967+ else
968+ {
969+ output = 0.0f;
970+ }
971+ return output;
972+}
973+
591974 void tRosenbergGlottalPulse_setFreq (tRosenbergGlottalPulse* const gp, float freq)
592975 {
593976 _tRosenbergGlottalPulse* g = *gp;
@@ -999,7 +1382,7 @@ static int pitchshift_attackdetect(_tPitchShift* ps) · 405 unmodified lines
9991382
10001383 void tPitchShift_init (tPitchShift* const psr, tPeriodDetection* pd, float* out, int bufSize)
10011384 {
1002− tPitchShift_freeFromPool(psr, &leaf.mempool);
1385+ tPitchShift_initToPool(psr, pd, out, bufSize, &leaf.mempool);
10031386 }
10041387
10051388 void tPitchShift_free(tPitchShift* const psr)
@@ -1386,6 +1769,7 @@ void tAutotune_initToPool (tAutotune* const rt, int numVoices, int buf · 380 unmodified lines
13861769 }
13871770
13881771 r->inputPeriod = 0.0f;
1772+ r->shiftOn = 0;
13891773 }
13901774
13911775 void tAutotune_freeFromPool (tAutotune* const rt, tMempool* const mp)
leaf/Src/leaf-math.c+17−6
@@ -109,7 +109,7 @@ int fastabs_int(int in){ · 108 unmodified lines
109109
110110 // alternative implementation for abs()
111111 // REQUIRES: 32 bit floats
112−float fastabsf(float f)
112+inline float fastabsf(float f)
113113 {
114114 union
115115 {
@@ -130,7 +130,7 @@ double fastexp(double x) { · 14 unmodified lines
130130 return x;
131131 }
132132
133−float fastexpf(float x) {
133+inline float fastexpf(float x) {
134134 x = 1.0f + (x * 0.0009765625f);
135135 x *= x; x *= x; x *= x; x *= x;
136136 x *= x; x *= x; x *= x; x *= x;
@@ -145,7 +145,7 @@ double fasterexp(double x) { · 8 unmodified lines
145145 return x;
146146 }
147147
148−float fasterexpf(float x) {
148+inline float fasterexpf(float x) {
149149 x = 1.0f + (x * 0.00390625f);
150150 x *= x; x *= x; x *= x; x *= x;
151151 x *= x; x *= x; x *= x; x *= x;
@@ -329,11 +329,16 @@ float LEAF_clip(float min, float val, float max) · 177 unmodified lines
329329 tempmin = max;
330330 tempmax = min;
331331 }
332− if (val < tempmin) {
332+ if (val < tempmin)
333+ {
333334 return tempmin;
334− } else if (val > tempmax) {
335+ }
336+ else if (val > tempmax)
337+ {
335338 return tempmax;
336− } else {
339+ }
340+ else
341+ {
337342 return val;
338343 }
339344 }
@@ -698,6 +703,12 @@ float fastdbtoa(float db) · 358 unmodified lines
698703 return expf(0.115129254649702f * db); //faster version from http://openaudio.blogspot.com/2017/02/faster-log10-and-pow.html
699704 }
700705
706+float fasterdbtoa(float db)
707+{
708+ //return powf(10.0f, db * 0.05f);
709+ return fasterexpf(0.115129254649702f * db); //faster version from http://openaudio.blogspot.com/2017/02/faster-log10-and-pow.html
710+}
711+
701712
702713 float maximum (float num1, float num2)
703714 {
leaf/Src/leaf-physical.c+246−0
@@ -668,6 +668,252 @@ float tLivingString_sample(tLivingString* const pl) · 667 unmodified lines
668668 return p->curr;
669669 }
670670
671+
672+//////////---------------------------
673+
674+/* Complex Living String (has pick position and preparation position separated) */
675+
676+void tComplexLivingString_init(tComplexLivingString* const pl, float freq, float pickPos, float prepPos, float prepIndex,
677+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
678+ float levStrength, int levMode)
679+{
680+ tComplexLivingString_initToPool(pl, freq, pickPos, prepPos, prepIndex, dampFreq, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf.mempool);
681+}
682+
683+void tComplexLivingString_free(tComplexLivingString* const pl)
684+{
685+ tComplexLivingString_freeFromPool(pl, &leaf.mempool);
686+}
687+
688+void tComplexLivingString_initToPool (tComplexLivingString* const pl, float freq, float pickPos, float prepPos, float prepIndex,
689+ float dampFreq, float decay, float targetLev, float levSmoothFactor,
690+ float levStrength, int levMode, tMempool* const mp)
691+{
692+ _tMempool* m = *mp;
693+ _tComplexLivingString* p = *pl = (_tComplexLivingString*) mpool_alloc(sizeof(_tComplexLivingString), m);
694+
695+ p->curr=0.0f;
696+ tExpSmooth_initToPool(&p->wlSmooth, leaf.sampleRate/freq, 0.01, mp); // smoother for string wavelength (not freq, to avoid expensive divisions)
697+ tComplexLivingString_setFreq(pl, freq);
698+ p->freq = freq;
699+ tExpSmooth_initToPool(&p->pickPosSmooth, pickPos, 0.01f, mp); // smoother for pick position
700+ tExpSmooth_initToPool(&p->prepPosSmooth, prepPos, 0.01f, mp); // smoother for pick position
701+
702+ tComplexLivingString_setPickPos(pl, pickPos);
703+ tComplexLivingString_setPrepPos(pl, prepPos);
704+
705+ p->prepPos=prepPos;
706+ p->pickPos=pickPos;
707+ tLinearDelay_initToPool(&p->delLF,p->waveLengthInSamples, 2400, mp);
708+ tLinearDelay_initToPool(&p->delMF,p->waveLengthInSamples, 2400, mp);
709+ tLinearDelay_initToPool(&p->delUF,p->waveLengthInSamples, 2400, mp);
710+ tLinearDelay_initToPool(&p->delUB,p->waveLengthInSamples, 2400, mp);
711+ tLinearDelay_initToPool(&p->delMB,p->waveLengthInSamples, 2400, mp);
712+ tLinearDelay_initToPool(&p->delLB,p->waveLengthInSamples, 2400, mp);
713+ tLinearDelay_clear(&p->delLF);
714+ tLinearDelay_clear(&p->delMF);
715+ tLinearDelay_clear(&p->delUF);
716+ tLinearDelay_clear(&p->delUB);
717+ tLinearDelay_clear(&p->delMB);
718+ tLinearDelay_clear(&p->delLB);
719+ p->dampFreq = dampFreq;
720+ tOnePole_initToPool(&p->bridgeFilter, dampFreq, mp);
721+ tOnePole_initToPool(&p->nutFilter, dampFreq, mp);
722+ tOnePole_initToPool(&p->prepFilterU, dampFreq, mp);
723+ tOnePole_initToPool(&p->prepFilterL, dampFreq, mp);
724+ tHighpass_initToPool(&p->DCblockerU,13, mp);
725+ tHighpass_initToPool(&p->DCblockerL,13, mp);
726+ p->decay=decay;
727+ p->prepIndex = prepIndex;
728+ tFeedbackLeveler_initToPool(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode, mp);
729+ tFeedbackLeveler_initToPool(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode, mp);
730+ p->levMode=levMode;
731+}
732+
733+void tComplexLivingString_freeFromPool (tComplexLivingString* const pl, tMempool* const mp)
734+{
735+ _tMempool* m = *mp;
736+ _tComplexLivingString* p = *pl;
737+
738+ tExpSmooth_freeFromPool(&p->wlSmooth, mp);
739+ tExpSmooth_freeFromPool(&p->pickPosSmooth, mp);
740+ tExpSmooth_freeFromPool(&p->prepPosSmooth, mp);
741+ tLinearDelay_freeFromPool(&p->delLF, mp);
742+ tLinearDelay_freeFromPool(&p->delMF, mp);
743+ tLinearDelay_freeFromPool(&p->delUF, mp);
744+ tLinearDelay_freeFromPool(&p->delUB, mp);
745+ tLinearDelay_freeFromPool(&p->delMB, mp);
746+ tLinearDelay_freeFromPool(&p->delLB, mp);
747+ tOnePole_freeFromPool(&p->bridgeFilter, mp);
748+ tOnePole_freeFromPool(&p->nutFilter, mp);
749+ tOnePole_freeFromPool(&p->prepFilterU, mp);
750+ tOnePole_freeFromPool(&p->prepFilterL, mp);
751+ tHighpass_freeFromPool(&p->DCblockerU, mp);
752+ tHighpass_freeFromPool(&p->DCblockerL, mp);
753+ tFeedbackLeveler_freeFromPool(&p->fbLevU, mp);
754+ tFeedbackLeveler_freeFromPool(&p->fbLevL, mp);
755+
756+ mpool_free((char*)p, m);
757+}
758+
759+void tComplexLivingString_setFreq(tComplexLivingString* const pl, float freq)
760+{ // NOTE: It is faster to set wavelength in samples directly
761+ _tComplexLivingString* p = *pl;
762+ if (freq<20.0f) freq=20.0f;
763+ else if (freq>10000.0f) freq=10000.0f;
764+ p->waveLengthInSamples = leaf.sampleRate/freq;
765+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
766+}
767+
768+void tComplexLivingString_setWaveLength(tComplexLivingString* const pl, float waveLength)
769+{
770+ _tComplexLivingString* p = *pl;
771+ if (waveLength<4.8f) waveLength=4.8f;
772+ else if (waveLength>2400.0f) waveLength=2400.0f;
773+ p->waveLengthInSamples = waveLength;
774+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
775+}
776+
777+void tComplexLivingString_setPickPos(tComplexLivingString* const pl, float pickPos)
778+{ // between 0 and 1
779+ _tComplexLivingString* p = *pl;
780+ if (pickPos<0.5f) pickPos=0.5f;
781+ else if (pickPos>1.f) pickPos=1.f;
782+ p->pickPos = pickPos;
783+ tExpSmooth_setDest(&p->pickPosSmooth, p->pickPos);
784+}
785+
786+void tComplexLivingString_setPrepPos(tComplexLivingString* const pl, float prepPos)
787+{ // between 0 and 1
788+ _tComplexLivingString* p = *pl;
789+ if (prepPos<0.f) prepPos=0.f;
790+ else if (prepPos>0.5f) prepPos=0.5f;
791+ p->prepPos = prepPos;
792+ tExpSmooth_setDest(&p->prepPosSmooth, p->prepPos);
793+}
794+
795+void tComplexLivingString_setPrepIndex(tComplexLivingString* const pl, float prepIndex)
796+{ // between 0 and 1
797+ _tComplexLivingString* p = *pl;
798+ if (prepIndex<0.f) prepIndex=0.f;
799+ else if (prepIndex>1.f) prepIndex=1.f;
800+ p->prepIndex = prepIndex;
801+}
802+
803+void tComplexLivingString_setDampFreq(tComplexLivingString* const pl, float dampFreq)
804+{
805+ _tComplexLivingString* p = *pl;
806+ tOnePole_setFreq(&p->bridgeFilter, dampFreq);
807+ tOnePole_setFreq(&p->nutFilter, dampFreq);
808+ tOnePole_setFreq(&p->prepFilterU, dampFreq);
809+ tOnePole_setFreq(&p->prepFilterL, dampFreq);
810+}
811+
812+void tComplexLivingString_setDecay(tComplexLivingString* const pl, float decay)
813+{
814+ _tComplexLivingString* p = *pl;
815+ p->decay=decay;
816+}
817+
818+void tComplexLivingString_setTargetLev(tComplexLivingString* const pl, float targetLev)
819+{
820+ _tComplexLivingString* p = *pl;
821+ tFeedbackLeveler_setTargetLevel(&p->fbLevU, targetLev);
822+ tFeedbackLeveler_setTargetLevel(&p->fbLevL, targetLev);
823+}
824+
825+void tComplexLivingString_setLevSmoothFactor(tComplexLivingString* const pl, float levSmoothFactor)
826+{
827+ _tComplexLivingString* p = *pl;
828+ tFeedbackLeveler_setFactor(&p->fbLevU, levSmoothFactor);
829+ tFeedbackLeveler_setFactor(&p->fbLevL, levSmoothFactor);
830+}
831+
832+void tComplexLivingString_setLevStrength(tComplexLivingString* const pl, float levStrength)
833+{
834+ _tComplexLivingString* p = *pl;
835+ tFeedbackLeveler_setStrength(&p->fbLevU, levStrength);
836+ tFeedbackLeveler_setStrength(&p->fbLevL, levStrength);
837+}
838+
839+void tComplexLivingString_setLevMode(tComplexLivingString* const pl, int levMode)
840+{
841+ _tComplexLivingString* p = *pl;
842+ tFeedbackLeveler_setMode(&p->fbLevU, levMode);
843+ tFeedbackLeveler_setMode(&p->fbLevL, levMode);
844+ p->levMode=levMode;
845+}
846+
847+float tComplexLivingString_tick(tComplexLivingString* const pl, float input)
848+{
849+ _tComplexLivingString* p = *pl;
850+
851+ // from pickPos upwards=forwards
852+ float fromLF=tLinearDelay_tickOut(&p->delLF);
853+ float fromMF=tLinearDelay_tickOut(&p->delMF);
854+ float fromUF=tLinearDelay_tickOut(&p->delUF);
855+ float fromUB=tLinearDelay_tickOut(&p->delUB);
856+ float fromMB=tLinearDelay_tickOut(&p->delMB);
857+ float fromLB=tLinearDelay_tickOut(&p->delLB);
858+
859+ // into upper part of string, from bridge, going backwards
860+ float fromBridge=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->bridgeFilter, fromUF)));
861+ tLinearDelay_tickIn(&p->delUB, fromBridge);
862+
863+ // into pick position, take input and add it into the waveguide, going to come out of middle segment
864+ tLinearDelay_tickIn(&p->delMB, fromUB+input);
865+
866+ // into lower part of string, from prepPos, going backwards
867+ float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF);
868+ float intoLower=p->prepIndex*fromLowerPrep+(1.0f - p->prepIndex)*fromMB;
869+ tLinearDelay_tickIn(&p->delLB, intoLower);
870+
871+ // into lower part of string, from nut, going forwards toward prep position
872+ float fromNut=-tFeedbackLeveler_tick(&p->fbLevL, (p->levMode==0?p->decay:1.0f)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->nutFilter, fromLB)));
873+ tLinearDelay_tickIn(&p->delLF, fromNut);
874+
875+ // into middle part of string, from prep going toward pick position
876+ float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB);
877+ float intoMiddle=p->prepIndex*fromUpperPrep+(1.0f - p->prepIndex)*fromLF;
878+
879+ //pick position, take input and add it into the waveguide, going to come out of middle segment
880+ tLinearDelay_tickIn(&p->delMF, intoMiddle + input);
881+
882+ //take output of middle segment and put it into upper segment connecting to the bridge
883+ tLinearDelay_tickIn(&p->delUF, fromMF);
884+
885+ // update all delay lengths
886+ float pickP=tExpSmooth_tick(&p->pickPosSmooth);
887+ float prepP=tExpSmooth_tick(&p->prepPosSmooth);
888+ float wLen=tExpSmooth_tick(&p->wlSmooth);
889+
890+ float midLen = (pickP-prepP) * wLen; // the length between the pick and the prep;
891+ float lowLen = prepP*wLen; // the length from prep to nut
892+ float upLen = (1.0f-pickP)*wLen; // the length from pick to bridge
893+
894+
895+ tLinearDelay_setDelay(&p->delLF, lowLen);
896+ tLinearDelay_setDelay(&p->delLB, lowLen);
897+
898+ tLinearDelay_setDelay(&p->delMF, midLen);
899+ tLinearDelay_setDelay(&p->delMB, midLen);
900+
901+ tLinearDelay_setDelay(&p->delUF, upLen);
902+ tLinearDelay_setDelay(&p->delUB, upLen);
903+
904+ //update this to allow pickup position variation
905+ p->curr = fromBridge;
906+ return p->curr;
907+}
908+
909+float tComplexLivingString_sample(tComplexLivingString* const pl)
910+{
911+ _tComplexLivingString* p = *pl;
912+ return p->curr;
913+}
914+
915+
916+
671917 ///Reed Table model
672918 //default values from STK are 0.6 offset and -0.8 slope
673919
leaf/Src/leaf-sampling.c+25−8
@@ -78,6 +78,7 @@ void tBuffer_tick (tBuffer* const sb, float sample) · 77 unmodified lines
7878 s->idx = 0;
7979 }
8080 }
81+ s->recordedLength = s->idx;
8182 }
8283 }
8384
@@ -110,7 +111,6 @@ void tBuffer_stop(tBuffer* const sb) · 26 unmodified lines
110111 {
111112 _tBuffer* s = *sb;
112113 s->active = 0;
113− s->recordedLength = s->idx;
114114 }
115115
116116 int tBuffer_getRecordPosition(tBuffer* const sb)
@@ -119,6 +119,12 @@ int tBuffer_getRecordPosition(tBuffer* const sb) · 2 unmodified lines
119119 return s->idx;
120120 }
121121
122+void tBuffer_setRecordPosition(tBuffer* const sb, int pos)
123+{
124+ _tBuffer* s = *sb;
125+ s->idx = pos;
126+}
127+
122128 void tBuffer_setRecordMode (tBuffer* const sb, RecordMode mode)
123129 {
124130 _tBuffer* s = *sb;
@@ -132,6 +138,7 @@ void tBuffer_clear (tBuffer* const sb) · 7 unmodified lines
132138 {
133139 s->buff[i] = 0.f;
134140 }
141+
135142 }
136143
137144 uint32_t tBuffer_getBufferLength(tBuffer* const sb)
@@ -146,6 +153,18 @@ uint32_t tBuffer_getRecordedLength(tBuffer* const sb) · 8 unmodified lines
146153 return s->recordedLength;
147154 }
148155
156+void tBuffer_setRecordedLength(tBuffer* const sb, int length)
157+{
158+ _tBuffer* s = *sb;
159+ s->recordedLength = length;
160+}
161+
162+int tBuffer_isActive(tBuffer* const sb)
163+{
164+ _tBuffer* s = *sb;
165+ return s->active;
166+}
167+
149168 //================================tSampler=====================================
150169
151170 static void handleStartEndChange(tSampler* const sp);
@@ -224,7 +243,7 @@ void tSampler_setSample (tSampler* const sp, tBuffer* const b) · 72 unmodified lines
224243 p->idx = 0.f;
225244 }
226245
227−volatile uint32_t errorState = 0;
246+
228247
229248 float tSampler_tick (tSampler* const sp)
230249 {
@@ -429,10 +448,11 @@ float tSampler_tick (tSampler* const sp) · 198 unmodified lines
429448 }
430449 }
431450
432− float ticksToEnd = rev ? ((idx - start) * p->iinc) : ((end - idx) * p->iinc);
451+
433452 if (p->mode == PlayNormal)
434453 {
435− if (ticksToEnd < (0.007f * leaf.sampleRate))
454+ float ticksToEnd = rev ? ((idx - start) * p->iinc) : ((end - idx) * p->iinc);
455+ if (ticksToEnd < (0.007f * leaf.sampleRate))
436456 {
437457 tRamp_setDest(&p->gain, 0.f);
438458 p->active = -1;
@@ -472,10 +492,7 @@ float tSampler_tick (tSampler* const sp) · 33 unmodified lines
472492 }
473493 }
474494
475− if (fabsf(sample-p->last) > 0.1f)
476− {
477− errorState = 1;
478− }
495+
479496
480497 p->last = sample;
481498
leaf/Src/leaf-tables.c+1−1
@@ -3489,7 +3489,7 @@ const float __leaf_table_squarewave[11][SQR_TABLE_SIZE] = · 3488 unmodified lines
34893489
34903490
34913491
3492−#if DECAY_TABLES_USED
3492+#ifdef DECAY_TABLES_USED
34933493 const float __leaf_table_exp_decay[EXP_DECAY_TABLE_SIZE] = {
34943494 1.0f, 0.999969f, 0.999939f, 0.999908f, 0.999878f, 0.999847f, 0.999817f, 0.999786f, 0.999756f, 0.999725f, 0.999695f, 0.999664f, 0.999634f, 0.999603f, 0.999573f, 0.999542f, 0.999512f, 0.999481f, 0.999451f, 0.99942f,
34953495 0.99939f, 0.999359f, 0.999329f, 0.999298f, 0.999268f, 0.999237f, 0.999207f, 0.999176f, 0.999146f, 0.999115f, 0.999085f, 0.999054f, 0.999024f, 0.998993f, 0.998963f, 0.998932f, 0.998902f, 0.998871f, 0.998841f, 0.99881f,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t