ref: 23faeb0a9edc0b46299231e9f78a40705aab2e4d
parent: 53a6d7a024d9b38c86da84fe5fc43d3fc2753621
author: spiricom <jeff@snyderphonics.com>
date: Thu Sep 10 13:04:04 EDT 2020
added some fixes to several leaf objects and major bug fix to tSampler
--- a/leaf/Inc/leaf-filters.h
+++ b/leaf/Inc/leaf-filters.h
@@ -1012,13 +1012,16 @@
float tVZFilter_tick (tVZFilter* const, float input);
float tVZFilter_tickEfficient (tVZFilter* const vf, float in);
void tVZFilter_calcCoeffs (tVZFilter* const);
+ void tVZFilter_calcCoeffsEfficientBP (tVZFilter* const);
void tVZFilter_setBandwidth (tVZFilter* const, float bandWidth);
void tVZFilter_setFreq (tVZFilter* const, float freq);
void tVZFilter_setFreqAndBandwidth (tVZFilter* const vf, float freq, float bw);
+ void tVZFilter_setFreqAndBandwidthEfficientBP (tVZFilter* const vf, float freq, float bw);
void tVZFilter_setGain (tVZFilter* const, float gain);
+
void tVZFilter_setType (tVZFilter* const, VZFilterType type);
float tVZFilter_BandwidthToR (tVZFilter* const vf, float B);
-
+ float tVZFilter_BandwidthToREfficientBP(tVZFilter* const vf, float B);
/*!
@defgroup tdiodefilter tDiodeFilter
--- a/leaf/Inc/leaf-math.h
+++ b/leaf/Inc/leaf-math.h
@@ -138,6 +138,13 @@
float fastcosf(float fAngle);
float fastercosf(float fAngle);
+
+ float fasttanf (float fAngle);
+
+
+ float fastertanf(float fAngle);
+
+
// alternative implementation for abs()
// REQUIRES: 32 bit integers
int fastabs_int(int in);
--- a/leaf/Inc/leaf-mempool.h
+++ b/leaf/Inc/leaf-mempool.h
@@ -112,7 +112,7 @@
@param size The size of the chuck of memory to be used as a mempool.
@param poolTo A pointer to the tMempool to which a tMempool should be initialized.
*/
- void tMempool_initToPool (tMempool* const pool, char* memory, size_t size, tMempool* const poolTo);
+ void tMempool_initToPool (tMempool* const mp, char* memory, size_t size, tMempool* const mem, LEAF* const leaf);
/*!
@} */
--- a/leaf/Inc/leaf-sampling.h
+++ b/leaf/Inc/leaf-sampling.h
@@ -122,6 +122,8 @@
uint32_t idx;
uint32_t bufferLength;
uint32_t recordedLength;
+ uint32_t channels;
+ uint32_t sampleRate;
RecordMode mode;
int active;
@@ -130,7 +132,7 @@
typedef _tBuffer* tBuffer;
void tBuffer_init (tBuffer* const, uint32_t length, LEAF* const leaf);
- void tBuffer_initToPool (tBuffer* const, uint32_t length, tMempool* const);
+ void tBuffer_initToPool (tBuffer* const sb, uint32_t length, tMempool* const mp, LEAF* const leaf);
void tBuffer_free (tBuffer* const);
void tBuffer_tick (tBuffer* const, float sample);
@@ -138,6 +140,7 @@
float tBuffer_get (tBuffer* const, int idx);
void tBuffer_record (tBuffer* const);
void tBuffer_stop (tBuffer* const);
+ void tBuffer_setBuffer (tBuffer* const sb, float* externalBuffer, int length, int channels, int sampleRate);
int tBuffer_getRecordPosition (tBuffer* const);
void tBuffer_setRecordPosition (tBuffer* const, int pos);
void tBuffer_setRecordMode (tBuffer* const, RecordMode mode);
@@ -224,6 +227,12 @@
tBuffer samp;
+ float leafInvSampleRate;
+ float leafSampleRate;
+ float ticksPerSevenMs;
+ float rateFactor;
+ uint32_t channels;
+
tRamp gain;
float idx;
@@ -254,10 +263,11 @@
typedef _tSampler* tSampler;
void tSampler_init (tSampler* const, tBuffer* const, LEAF* const leaf);
- void tSampler_initToPool (tSampler* const, tBuffer* const, tMempool* const);
+ void tSampler_initToPool (tSampler* const sp, tBuffer* const b, tMempool* const mp, LEAF* const leaf);
void tSampler_free (tSampler* const);
float tSampler_tick (tSampler* const);
+ float tSampler_tickStereo (tSampler* const sp, float* outputArray);
void tSampler_setSample (tSampler* const, tBuffer* const);
void tSampler_setMode (tSampler* const, PlayMode mode);
void tSampler_play (tSampler* const);
@@ -343,7 +353,7 @@
typedef _tAutoSampler* tAutoSampler;
void tAutoSampler_init (tAutoSampler* const, tBuffer* const, LEAF* const leaf);
- void tAutoSampler_initToPool (tAutoSampler* const, tBuffer* const, tMempool* const);
+ void tAutoSampler_initToPool (tAutoSampler* const as, tBuffer* const b, tMempool* const mp, LEAF* const leaf);
void tAutoSampler_free (tAutoSampler* const);
float tAutoSampler_tick (tAutoSampler* const, float input);
--- a/leaf/Src/leaf-analysis.c
+++ b/leaf/Src/leaf-analysis.c
@@ -10,7 +10,7 @@
#include "..\Inc\leaf-analysis.h"
#include "..\Externals\d_fft_mayer.h"
-
+#include <intrin.h>
#else
#include "../Inc/leaf-analysis.h"
--- a/leaf/Src/leaf-effects.c
+++ b/leaf/Src/leaf-effects.c
@@ -288,7 +288,7 @@
{
// for(i=0; i<n; i++)
// {
- buf[i] = 0.0f;
+ buf[0] = 0.0f;
return;
// }
}
@@ -618,7 +618,7 @@
{
// for(i=0; i<n; i++)
// {
- buf[i] = 0.0f;
+ buf[0] = 0.0f;
return;
// }
}
--- a/leaf/Src/leaf-filters.c
+++ b/leaf/Src/leaf-filters.c
@@ -1321,38 +1321,7 @@
}
-float tVZFilter_tickEfficientBP (tVZFilter* const vf, float in)
-{
- _tVZFilter* f = *vf;
- float yL, yB, yH;
-
- // compute highpass output via Eq. 5.1:
- yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
-
- // compute bandpass output by applying 1st integrator to highpass output:
- yB = (f->g*yH) + f->s1;
- f->s1 = f->g*yH + yB; // state update in 1st integrator
-
- // compute lowpass output by applying 2nd integrator to bandpass output:
- yL = (f->g*yB) + f->s2;
- f->s2 = f->g*yB + yL; // state update in 2nd integrator
-
- //according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
- //
- //seems like that might look like this:
- // y = tanh(g*x) + s; // output computation
- // s = g*x + y; // state update
-
- //instead of this:
- // y = g*x + s; // output computation
- // s = g*x + y; // state update
-
- return f->cL*yL + f->cB*yB + f->cH*yH;
-
-}
-
-
void tVZFilter_calcCoeffs (tVZFilter* const vf)
{
@@ -1458,7 +1427,19 @@
f->h = 1.0f / (1.0f + f->R2*f->g + f->g*f->g); // factor for feedback precomputation
}
+void tVZFilter_calcCoeffsEfficientBP (tVZFilter* const vf)
+{
+ _tVZFilter* f = *vf;
+ f->g = fastertanf(PI * f->fc * f->inv_sr); // embedded integrator gain (Fig 3.11)
+ f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
+ f->cB = f->R2;
+ f->h = 1.0f / (1.0f + f->R2*f->g + f->g*f->g); // factor for feedback precomputation
+}
+
+
+
+
void tVZFilter_setBandwidth (tVZFilter* const vf, float B)
{
_tVZFilter* f = *vf;
@@ -1483,14 +1464,28 @@
tVZFilter_calcCoeffs(vf);
}
+void tVZFilter_setFreqAndBandwidthEfficientBP (tVZFilter* const vf, float freq, float bw)
+{
+ _tVZFilter* f = *vf;
+ LEAF* leaf = f->mempool->leaf;
+
+ f->B = LEAF_clip(0.0f,bw, 100.0f);
+ f->fc = LEAF_clip(0.0f, freq, 0.5f * leaf->sampleRate);
+ tVZFilter_calcCoeffsEfficientBP(vf);
+}
+
+
+
void tVZFilter_setGain (tVZFilter* const vf, float gain)
{
_tVZFilter* f = *vf;
- f->G = LEAF_clip(0.000001f, gain, 100.0f);
+ f->G = LEAF_clip(0.000001f, gain, 4000.0f);
f->invG = 1.0f/f->G;
tVZFilter_calcCoeffs(vf);
}
+
+
void tVZFilter_setMorph (tVZFilter* const vf, float morph)
{
_tVZFilter* f = *vf;
@@ -1516,8 +1511,20 @@
return sqrtf((1.0f-r*r)*(1.0f-r*r)/(4.0f*r*r));
}
+float tVZFilter_BandwidthToREfficientBP(tVZFilter* const vf, float B)
+{
+ _tVZFilter* f = *vf;
+ float fl = f->fc*fastPowf(2.0f, -B * 0.5f); // lower bandedge frequency (in Hz)
+ float gl = fastertanf(PI*fl*f->inv_sr); // warped radian lower bandedge frequency /(2*fs)
+ float r = gl/f->g; // ratio between warped lower bandedge- and center-frequencies
+ // unwarped: r = pow(2, -B/2) -> approximation for low
+ // center-frequencies
+ return fastsqrtf((1.0f-r*r)*(1.0f-r*r)/(4.0f*r*r));
+}
+
+
void tDiodeFilter_init (tDiodeFilter* const vf, float cutoff, float resonance, LEAF* const leaf)
{
tDiodeFilter_initToPool(vf, cutoff, resonance, &leaf->mempool);
@@ -1557,7 +1564,15 @@
{
float a = x*x;
// IIRC I got this as Pade-approx for tanh(sqrt(x))/sqrt(x)
- return ((a + 105.0f)*a + 945.0f) / ((15.0f*a + 420.0f)*a + 945.0f);
+ float testVal = ((15.0f*a + 420.0f)*a + 945.0f);
+ float output = 1.0f;
+
+ if (testVal!= 0.0f)
+ {
+ output = testVal;
+
+ }
+ return ((a + 105.0f)*a + 945.0f) / output;
}
float tDiodeFilter_tick (tDiodeFilter* const vf, float in)
@@ -1564,6 +1579,7 @@
{
_tDiodeFilter* f = *vf;
+ int errorCheck = 0;
// the input x[n+1] is given by 'in', and x[n] by zi
// input with half delay
float ih = 0.5f * (in + f->zi);
@@ -1579,24 +1595,24 @@
// This formula gives the result for y3 thanks to MATLAB
float y3 = (f->s2 + f->s3 + t2*(f->s1 + f->s2 + f->s3 + t1*(f->s0 + f->s1 + f->s2 + f->s3 + t0*in)) + t1*(2.0f*f->s2 + 2.0f*f->s3))*t3 + f->s3 + 2.0f*f->s3*t1 + t2*(2.0f*f->s3 + 3.0f*f->s3*t1);
-// if (isnan(y3))
-// {
-// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-// }
+ if (isnan(y3))
+ {
+ errorCheck = 1;
+ }
float tempy3denom = (t4 + t1*(2.0f*t4 + 4.0f) + t2*(t4 + t1*(t4 + f->r*t0 + 4.0f) + 3.0f) + 2.0f)*t3 + t4 + t1*(2.0f*t4 + 2.0f) + t2*(2.0f*t4 + t1*(3.0f*t4 + 3.0f) + 2.0f) + 1.0f;
-// if (isnan(tempy3denom))
-// {
-// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-// }
+ if (isnan(tempy3denom))
+ {
+ errorCheck = 2;
+ }
if (tempy3denom == 0.0f)
{
tempy3denom = 0.000001f;
}
y3 = y3 / tempy3denom;
-// if (isnan(y3))
-// {
-// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-// }
+ if (isnan(y3))
+ {
+ errorCheck = 3;
+ }
if (t1 == 0.0f)
{
t1 = 0.000001f;
@@ -1617,15 +1633,15 @@
// update state
f->s0 += 2.0f * (t0*xx + t1*(y1-y0));
-// if (isnan(f->s0))
-// {
-// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-// }
+ if (isnan(f->s0))
+ {
+ errorCheck = 4;
+ }
-// if (isinf(f->s0))
-// {
-// __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-// }
+ if (isinf(f->s0))
+ {
+ errorCheck = 5;
+ }
f->s1 += 2.0f * (t2*(y2-y1) - t1*(y1-y0));
f->s2 += 2.0f * (t3*(y3-y2) - t2*(y2-y1));
f->s3 += 2.0f * (-t4*(y3) - t3*(y3-y2));
--- a/leaf/Src/leaf-math.c
+++ b/leaf/Src/leaf-math.c
@@ -99,8 +99,48 @@
return fResult;
}
+float fasttanf (float fAngle)
+{
+ float fASqr = fAngle*fAngle;
+ float fResult = 9.5168091e-03f;
+ fResult *= fASqr;
+ fResult += 2.900525e-03f;
+ fResult *= fASqr;
+ fResult += 2.45650893e-02f;
+ fResult *= fASqr;
+ fResult += 5.33740603e-02f;
+ fResult *= fASqr;
+ fResult += 1.333923995e-01f;
+ fResult *= fASqr;
+ fResult += 3.333314036e-01f;
+ fResult *= fASqr;
+ fResult += 1.0f;
+ fResult *= fAngle;
+ return fResult;
+}
+float fastertanf(float fAngle)
+{
+ float fASqr = fAngle*fAngle;
+ float fResult = 2.033e-01f;
+ fResult *= fASqr;
+ fResult += 3.1755e-01f;
+ fResult *= fASqr;
+ fResult += 1.0f;
+ fResult *= fAngle;
+ return fResult;
+}
+// from Heng Li, a combination of inverse square root (see wiki) and inversion: https://bits.stephan-brumme.com/inverse.html
+float fastsqrtf(float x)
+{
+ union { float f; uint32_t i; } z = { x };
+ z.i = 0x5f3759df - (z.i >> 1);
+ z.f *= (1.5f - (x * 0.5f * z.f * z.f));
+ z.i = 0x7EEEEEEE - z.i;
+ return z.f;
+}
+
// alternative implementation for abs()
// REQUIRES: 32 bit integers
int fastabs_int(int in){
@@ -114,7 +154,7 @@
// alternative implementation for abs()
// REQUIRES: 32 bit floats
-inline float fastabsf(float f)
+float fastabsf(float f)
{
union
{
--- a/leaf/Src/leaf-mempool.c
+++ b/leaf/Src/leaf-mempool.c
@@ -410,7 +410,7 @@
void tMempool_init(tMempool* const mp, char* memory, size_t size, LEAF* const leaf)
{
- tMempool_initToPool(mp, memory, size, &leaf->mempool);
+ tMempool_initToPool(mp, memory, size, &leaf->mempool, leaf);
}
void tMempool_free(tMempool* const mp)
@@ -420,10 +420,11 @@
mpool_free((char*)m, m->mempool);
}
-void tMempool_initToPool (tMempool* const mp, char* memory, size_t size, tMempool* const mem)
+void tMempool_initToPool (tMempool* const mp, char* memory, size_t size, tMempool* const mem, LEAF* const leaf)
{
_tMempool* mm = *mem;
_tMempool* m = *mp = (_tMempool*) mpool_alloc(sizeof(_tMempool), mm);
-
+ m->leaf = leaf;
mpool_create (memory, size, m);
}
+
--- a/leaf/Src/leaf-sampling.c
+++ b/leaf/Src/leaf-sampling.c
@@ -26,10 +26,10 @@
void tBuffer_init (tBuffer* const sb, uint32_t length, LEAF* const leaf)
{
- tBuffer_initToPool(sb, length, &leaf->mempool);
+ tBuffer_initToPool(sb, length, &leaf->mempool, leaf);
}
-void tBuffer_initToPool (tBuffer* const sb, uint32_t length, tMempool* const mp)
+void tBuffer_initToPool (tBuffer* const sb, uint32_t length, tMempool* const mp, LEAF* const leaf)
{
_tMempool* m = *mp;
_tBuffer* s = *sb = (_tBuffer*) mpool_alloc(sizeof(_tBuffer), m);
@@ -36,7 +36,8 @@
s->mempool = m;
s->buff = (float*) mpool_alloc( sizeof(float) * length, m);
-
+ s->sampleRate = leaf->sampleRate;
+ s->channels = 1;
s->bufferLength = length;
s->recordedLength = 0;
s->active = 0;
@@ -136,6 +137,17 @@
}
+void tBuffer_setBuffer(tBuffer* const sb, float* externalBuffer, int length, int channels, int sampleRate)
+{
+ _tBuffer* s = *sb;
+
+ s->buff = externalBuffer;
+ s->channels = channels;
+ s->sampleRate = sampleRate;
+ s->recordedLength = length/channels;
+ s->bufferLength = s->recordedLength;
+}
+
uint32_t tBuffer_getBufferLength(tBuffer* const sb)
{
_tBuffer* s = *sb;
@@ -168,10 +180,10 @@
void tSampler_init(tSampler* const sp, tBuffer* const b, LEAF* const leaf)
{
- tSampler_initToPool(sp, b, &leaf->mempool);
+ tSampler_initToPool(sp, b, &leaf->mempool, leaf);
}
-void tSampler_initToPool(tSampler* const sp, tBuffer* const b, tMempool* const mp)
+void tSampler_initToPool(tSampler* const sp, tBuffer* const b, tMempool* const mp, LEAF* const leaf)
{
_tMempool* m = *mp;
_tSampler* p = *sp = (_tSampler*) mpool_alloc(sizeof(_tSampler), m);
@@ -179,18 +191,36 @@
_tBuffer* s = *b;
+ p->leafInvSampleRate = leaf->invSampleRate;
+ p->leafSampleRate = leaf->sampleRate;
+ p->ticksPerSevenMs = 0.007f * p->leafSampleRate;
+ p->rateFactor = s->sampleRate * p->leafInvSampleRate;
+ p->channels = s->channels;
+
+
p->samp = s;
p->active = 0;
p->start = 0;
- p->end = 0;
+ p->end = p->samp->bufferLength - 1;
p->len = p->end - p->start;
p->idx = 0.f;
- p->inc = 1.f;
- p->iinc = 1.f;
+ float rate = p->rateFactor; //adjust for sampling rate of buffer (may be different from leaf.sampleRate if audio file was loaded form SD card)
+ if (rate < 0.f)
+ {
+ rate = -rate;
+ p->dir = -1;
+ }
+ else
+ {
+ p->dir = 1;
+ }
+
+ p->inc = rate;
+ p->iinc = 1.f / p->inc;
p->dir = 1;
p->flip = 1;
@@ -200,7 +230,7 @@
p->cfxlen = 500; // default 300 sample crossfade
- tRamp_initToPool(&p->gain, 7.0f, 1, mp);
+ tRamp_initToPool(&p->gain, 5.0f, 1, mp);
tRamp_setVal(&p->gain, 0.f);
p->targetstart = -1;
@@ -226,6 +256,10 @@
p->samp = s;
+
+ p->rateFactor = s->sampleRate * p->leafInvSampleRate;
+ p->channels = s->channels;
+
p->start = 0;
p->end = p->samp->bufferLength - 1;
@@ -452,7 +486,7 @@
p->idx = myEnd;
}
float ticksToEnd = rev ? ((idx - myStart) * p->iinc) : ((myEnd - idx) * p->iinc);
- if (ticksToEnd < (0.007f * leaf->sampleRate))
+ if ((ticksToEnd < p->ticksPerSevenMs) && (p->active == 1))
{
tRamp_setDest(&p->gain, 0.f);
p->active = -1;
@@ -500,6 +534,299 @@
return p->last;
}
+
+float tSampler_tickStereo (tSampler* const sp, float* outputArray)
+{
+ _tSampler* p = *sp;
+ LEAF* leaf = p->mempool->leaf;
+
+ attemptStartEndChange(sp);
+
+ if (p->active == 0) return 0.f;
+
+ if ((p->inc == 0.0f) || (p->len < 2))
+ {
+ // p->inCrossfade = 1;
+ return p->last;
+ }
+
+ float cfxsample[2] = {0.0f, 0.0f};
+ float crossfadeMix = 0.0f;
+ float flipsample[2] = {0.0f, 0.0f};
+ float flipMix = 0.0f;
+
+ float* buff = p->samp->buff;
+
+ // Variables so start is also before end
+ int myStart = p->start;
+ int myEnd = p->end;
+ if (p->flip < 0)
+ {
+ myStart = p->end;
+ myEnd = p->start;
+ }
+
+ // Get the direction and a reverse flag for some calcs
+ int dir = p->bnf * p->dir * p->flip;
+ int rev = 0;
+ if (dir < 0) rev = 1;
+
+ // Get the current integer index and alpha for interpolation
+ int idx = (int) p->idx;
+ float alpha = rev + (p->idx - idx) * dir;
+ idx += rev;
+
+ // Get the indexes for interpolation
+ int i1 = idx-(1*dir);
+ int i2 = idx;
+ int i3 = idx+(1*dir);
+ int i4 = idx+(2*dir);
+
+ int length = p->samp->recordedLength;
+
+ // Wrap as needed
+ i1 = (i1 < length*rev) ? i1 + (length * (1-rev)) : i1 - (length * rev);
+ i2 = (i2 < length*rev) ? i2 + (length * (1-rev)) : i2 - (length * rev);
+ i3 = (i3 < length*(1-rev)) ? i3 + (length * rev) : i3 - (length * (1-rev));
+ i4 = (i4 < length*(1-rev)) ? i4 + (length * rev) : i4 - (length * (1-rev));
+
+ outputArray[0] = LEAF_interpolate_hermite_x (buff[i1 * p->channels],
+ buff[i2 * p->channels],
+ buff[i3 * p->channels],
+ buff[i4 * p->channels],
+ alpha);
+
+ outputArray[1] = LEAF_interpolate_hermite_x (buff[(i1 * p->channels) + 1],
+ buff[(i2 * p->channels) + 1],
+ buff[(i3 * p->channels) + 1],
+ buff[(i4 * p->channels) + 1],
+ alpha);
+
+ int32_t cfxlen = p->cfxlen;
+ if (p->len * 0.25f < cfxlen) cfxlen = p->len * 0.25f;
+
+ // Determine crossfade points
+ int32_t fadeLeftStart = 0;
+ if (myStart >= cfxlen) fadeLeftStart = myStart - cfxlen;
+ int32_t fadeLeftEnd = fadeLeftStart + cfxlen;
+
+ int32_t fadeRightEnd = myEnd;// + (fadeLeftEnd - start);
+ // if (fadeRightEnd >= length) fadeRightEnd = length - 1;
+ int32_t fadeRightStart = fadeRightEnd - cfxlen;
+
+
+
+
+ if (p->mode == PlayLoop)
+ {
+
+ int offset = 0;
+ int cdx = 0;
+ if ((fadeLeftStart <= idx) && (idx <= fadeLeftEnd))
+ {
+ offset = fadeLeftEnd - idx;
+ cdx = fadeRightEnd - offset;
+ p->inCrossfade = 1;
+ }
+ else if ((fadeRightStart <= idx) && (idx <= fadeRightEnd))
+ {
+ offset = idx - fadeRightStart;
+ cdx = fadeLeftStart + offset;
+ p->inCrossfade = 1;
+ }
+ else p->inCrossfade = 0;
+
+ if (p->inCrossfade)
+ {
+ int c1 = cdx-(1*dir);
+ int c2 = cdx;
+ int c3 = cdx+(1*dir);
+ int c4 = cdx+(2*dir);
+
+ // Wrap as needed
+ c1 = (c1 < length * rev) ? c1 + (length * (1-rev)) : c1 - (length * rev);
+ c2 = (c2 < length * rev) ? c2 + (length * (1-rev)) : c2 - (length * rev);
+ c3 = (c3 < length * (1-rev)) ? c3 + (length * rev) : c3 - (length * (1-rev));
+ c4 = (c4 < length * (1-rev)) ? c4 + (length * rev) : c4 - (length * (1-rev));
+
+ cfxsample[0] = LEAF_interpolate_hermite_x (buff[c1 * p->channels],
+ buff[c2 * p->channels],
+ buff[c3 * p->channels],
+ buff[c4 * p->channels],
+ alpha);
+
+ cfxsample[1] = LEAF_interpolate_hermite_x (buff[(c1 * p->channels) + 1],
+ buff[(c2 * p->channels) + 1],
+ buff[(c3 * p->channels) + 1],
+ buff[(c4 * p->channels) + 1],
+ alpha);
+
+ crossfadeMix = (float) offset / (float) cfxlen;
+ }
+
+ float flipLength = fabsf(p->flipIdx - p->flipStart);
+ if (flipLength > cfxlen)
+ {
+ p->flipStart = -1;
+ p->flipIdx = -1;
+ }
+ if (p->flipIdx >= 0)
+ {
+ if (p->flipStart == -1)
+ {
+ p->flipStart = p->idx;
+ p->flipIdx = p->idx;
+ }
+ flipLength = fabsf(p->flipIdx - p->flipStart);
+
+ int fdx = (int) p->flipIdx;
+ float falpha = (1-rev) - (p->flipIdx - fdx) * dir;
+ idx += (1-rev);
+
+ // Get the indexes for interpolation
+ int f1 = fdx+(1*dir);
+ int f2 = fdx;
+ int f3 = fdx-(1*dir);
+ int f4 = fdx-(2*dir);
+
+ // Wrap as needed
+ f1 = (f1 < length*(1-rev)) ? f1 + (length * rev) : f1 - (length * (1-rev));
+ f2 = (f2 < length*(1-rev)) ? f2 + (length * rev) : f2 - (length * (1-rev));
+ f3 = (f3 < length*rev) ? f3 + (length * (1-rev)) : f3 - (length * rev);
+ f4 = (f4 < length*rev) ? f4 + (length * (1-rev)) : f4 - (length * rev);
+
+ flipsample[0] = LEAF_interpolate_hermite_x (buff[f1 * p->channels],
+ buff[f2 * p->channels],
+ buff[f3 * p->channels],
+ buff[f4 * p->channels],
+ falpha);
+
+ flipsample[1] = LEAF_interpolate_hermite_x (buff[(f1 * p->channels) + 1],
+ buff[(f2 * p->channels) + 1],
+ buff[(f3 * p->channels) + 1],
+ buff[(f4 * p->channels) + 1],
+ falpha);
+
+ flipMix = (float) (cfxlen - flipLength) / (float) cfxlen;
+ }
+ }
+
+ float inc = fmodf(p->inc, (float)p->len);
+ p->idx += (dir * inc);
+ if (p->flipStart >= 0)
+ {
+ p->flipIdx += (-dir * inc);
+ if((int)p->flipIdx < 0)
+ {
+ p->idx += (float)length;
+ }
+ if((int)p->idx >= length)
+ {
+
+ p->idx -= (float)length;
+ }
+ }
+
+
+
+ attemptStartEndChange(sp);
+
+
+ if (p->mode == PlayLoop)
+ {
+ if((int)p->idx < myStart)
+ {
+ p->idx += (float)(fadeRightEnd - fadeLeftEnd);
+ }
+ if((int)p->idx > myEnd)
+ {
+
+ p->idx -= (float)(fadeRightEnd - fadeLeftEnd);
+ }
+ }
+ else if (p->mode == PlayBackAndForth)
+ {
+ if (p->idx < myStart)
+ {
+ p->bnf = -p->bnf;
+ p->idx = myStart + 1;
+ }
+ else if (p->idx > myEnd)
+ {
+ p->bnf = -p->bnf;
+ p->idx = myEnd - 1;
+ }
+ }
+
+
+ if (p->mode == PlayNormal)
+ {
+ if (p->idx < myStart)
+ {
+ p->idx = myStart;
+ }
+ else if (p->idx > myEnd)
+ {
+ p->idx = myEnd;
+ }
+ float ticksToEnd = rev ? ((idx - myStart) * p->iinc) : ((myEnd - idx) * p->iinc);
+ if ((ticksToEnd < p->ticksPerSevenMs) && (p->active == 1))
+ {
+ tRamp_setDest(&p->gain, 0.f);
+ p->active = -1;
+ }
+ }
+
+ float sampleGain = tRamp_tick(&p->gain);
+ for (int i = 0; i < p->channels; i++)
+ {
+ outputArray[i] = ((outputArray[i] * (1.0f - crossfadeMix)) + (cfxsample[i] * crossfadeMix)) * (1.0f - flipMix) + (flipsample[i] * flipMix);
+ outputArray[i] = outputArray[i] * sampleGain;
+ }
+
+
+
+
+ if (p->active < 0)
+ {
+ //if was fading out and reached silence
+ if (tRamp_sample(&p->gain) <= 0.0001f)
+ {
+ if (p->retrigger == 1)
+ {
+ p->active = 1;
+ p->retrigger = 0;
+ tRamp_setDest(&p->gain, 1.f);
+
+ if (p->dir > 0)
+ {
+ if (p->flip > 0) p->idx = p->start;
+ else p->idx = p->end;
+ }
+ else
+ {
+ if (p->flip > 0) p->idx = p->end;
+ else p->idx = p->start;
+ }
+ handleStartEndChange(&p);
+ }
+ else
+ {
+ p->active = 0;
+ }
+
+ }
+ }
+
+
+
+ p->last = outputArray[0];
+
+
+ return p->last;
+}
+
+
void tSampler_setMode (tSampler* const sp, PlayMode mode)
{
_tSampler* p = *sp;
@@ -518,8 +845,8 @@
void tSampler_play (tSampler* const sp)
{
_tSampler* p = *sp;
-
- if (p->active != 0)
+
+ if (p->active > 0)
{
p->active = -1;
p->retrigger = 1;
@@ -526,6 +853,15 @@
tRamp_setDest(&p->gain, 0.f);
}
+
+ else if (p->active < 0)
+ {
+ p->active = -1;
+ p->retrigger = 1;
+
+ //tRamp_setDest(&p->gain, 0.f);
+ }
+
else
{
p->active = 1;
@@ -740,6 +1076,7 @@
{
_tSampler* p = *sp;
+ rate = rate * p->rateFactor; //adjust for sampling rate of buffer (may be different from leaf.sampleRate if audio file was loaded form SD card)
if (rate < 0.f)
{
rate = -rate;
@@ -758,10 +1095,10 @@
void tAutoSampler_init (tAutoSampler* const as, tBuffer* const b, LEAF* const leaf)
{
- tAutoSampler_initToPool(as, b, &leaf->mempool);
+ tAutoSampler_initToPool(as, b, &leaf->mempool, leaf);
}
-void tAutoSampler_initToPool (tAutoSampler* const as, tBuffer* const b, tMempool* const mp)
+void tAutoSampler_initToPool (tAutoSampler* const as, tBuffer* const b, tMempool* const mp, LEAF* const leaf)
{
_tMempool* m = *mp;
_tAutoSampler* a = *as = (_tAutoSampler*) mpool_alloc(sizeof(_tAutoSampler), m);
@@ -768,7 +1105,7 @@
a->mempool = m;
tBuffer_setRecordMode(b, RecordOneShot);
- tSampler_initToPool(&a->sampler, b, mp);
+ tSampler_initToPool(&a->sampler, b, mp, leaf);
tSampler_setMode(&a->sampler, PlayLoop);
tEnvelopeFollower_initToPool(&a->ef, 0.05f, 0.9999f, mp);
}
@@ -939,7 +1276,7 @@
{
_tMBSampler* c = *sp;
- if (c->gain->curr == 0.0f && !c->active) return 0.0f;
+ if ((c->gain->curr == 0.0f) && (!c->active)) return 0.0f;
if (c->_w == 0.0f)
{
c->_last_w = 0.0f;
@@ -1031,8 +1368,10 @@
float nextSlope = (afterNext - next) / w;
float lastSlope = (last - beforeLast) / w;
place_slope_dd(c->_f, j, p - start, w, nextSlope - lastSlope);
-
- if (c->mode == PlayNormal) c->active = 0;
+ if (c->mode == PlayNormal)
+ {
+ c->active = 0;
+ }
else if (c->mode == PlayBackAndForth) w = -w;
}
// else if (p < (float) start) { /* start has been set ahead of the current phase */
@@ -1056,6 +1395,13 @@
int i = (int) f;
f -= i;
next = buff[i] * (1.0f - f) + buff[i+1] * f;
+
+
+ if ((end - p) < 480) // 480 samples should be enough to let the tExpSmooth go from 1 to 0 (10ms at 48k, 5ms at 192k)
+ if (c->mode == PlayNormal)
+ {
+ tExpSmooth_setDest(&c->gain, 0.0f);
+ }
}
if (c->_last_w < 0.0f)
@@ -1095,7 +1441,10 @@
float lastSlope = (last - beforeLast) / w;
place_slope_dd(c->_f, j, end - p, w, nextSlope - lastSlope);
- if (c->mode == PlayNormal) c->active = 0;
+ if (c->mode == PlayNormal)
+ {
+ c->active = 0;
+ }
else if (c->mode == PlayBackAndForth) w = -w;
}
// else if (p > (float) end) {
@@ -1115,6 +1464,11 @@
// }
else {
+ if ((p - start) < 480) // 480 samples should be enough to let the tExpSmooth go from 1 to 0 (10ms at 48k, 5ms at 192k)
+ if (c->mode == PlayNormal)
+ {
+ tExpSmooth_setDest(&c->gain, 0.0f);
+ }
float f = p;
int i = (int) f;
f -= i;