ref: 382ddd1e8d09ecc06f4bd7e02e274e7fdcda63ee
parent: d634fb3b428b1cc7bc1f06b39a2ef43f8cc17f2c
author: Matthew Wang <mjw7@princeton.edu>
date: Fri Aug 7 12:04:58 EDT 2020
mostly working minblep sampler
--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -14,21 +14,6 @@
static void leaf_pool_dump(void);
static void run_pool_test(void);
-tNoise noise;
-tSVF bp1;
-tSVF bp2;
-tFormantShifter fs;
-
-tSampler samp;
-tBuffer buff;
-tEnvelope env;
-
-tAutotune at;
-
-tPhasor phasor;
-
-tHighpass hipass;
-
tMBSaw bsaw;
tMBTriangle btri;
tMBPulse bpulse;
@@ -42,6 +27,9 @@
tCycle sine;
+tBuffer samp;
+tMBSampler sampler;
+
float gain;
float dtime;
bool buttonState;
@@ -53,7 +41,7 @@
float* bufIn;
float* bufOut;
-#define MSIZE 500000
+#define MSIZE 2048000
char memory[MSIZE];
void LEAFTest_init (float sampleRate, int blockSize)
@@ -76,6 +64,12 @@
tCycle_init(&sine);
tCycle_setFreq(&sine, 100);
+
+ tBuffer_init(&samp, 5.0f * leaf.sampleRate);
+ tMBSampler_init(&sampler, &samp);
+
+ tMBSampler_setMode(&sampler, PlayLoop);
+ tMBSampler_setEnd(&sampler, samp->bufferLength);
}
inline double getSawFall(double angle) {
@@ -90,6 +84,11 @@
float lastFreq;
float LEAFTest_tick (float input)
{
+ tBuffer_tick(&samp, input);
+
+ return tMBSampler_tick(&sampler);
+
+
// tMBSaw_setFreq(&bsaw, x);
// tMBTriangle_setFreq(&btri, x);
// tMBPulse_setFreq(&bpulse, x);
@@ -102,21 +101,21 @@
// return tMBPulse_tick(&bpulse);
- float freq = 1.0f/tPeriodDetection_tick(&pd, input) * leaf.sampleRate;
- tPitchDetector_tick(&detector, input);
- float altFreq = tPitchDetector_getFrequency(&detector);
-
- if (fabsf(1.0f - (freq / altFreq)) < 0.05f)
-// if (tZeroCrossingCounter_tick(&zc, input) < 0.05 && freq > 0.0f)
- {
- tCycle_setFreq(&sine, altFreq);
- }
-
- float g = tEnvelopeFollower_tick(&ef, input);
-
- lastFreq = freq;
-
- return tCycle_tick(&sine) * g * 2.0f + input;
+// float freq = 1.0f/tPeriodDetection_tick(&pd, input) * leaf.sampleRate;
+// tPitchDetector_tick(&detector, input);
+// float altFreq = tPitchDetector_getFrequency(&detector);
+//
+// if (fabsf(1.0f - (freq / altFreq)) < 0.05f)
+//// if (tZeroCrossingCounter_tick(&zc, input) < 0.05 && freq > 0.0f)
+// {
+// tCycle_setFreq(&sine, altFreq);
+// }
+//
+// float g = tEnvelopeFollower_tick(&ef, input);
+//
+// lastFreq = freq;
+//
+// return tCycle_tick(&sine) * g * 2.0f + input;
}
int firstFrame = 1;
@@ -129,37 +128,27 @@
DBG(tPitchDetector_getFrequency(&detector));
DBG(tPitchDetector_getPeriodicity(&detector));
}
- // if (firstFrame == 1)
- // {
- // tBuffer_record(&buff); // starts recording
- // tSampler_play(&samp); // start spitting samples out
- // firstFrame = 0;
- // }
- float val = getSliderValue("mod freq");
+ float val = getSliderValue("on/off");
- x = val;
+ if (val > 0.5f && !sampler->active)
+ {
+ tBuffer_record(&samp);
+ tMBSampler_play(&sampler);
+ }
+ else if (val < 0.5f && sampler->active)
+ {
+ tMBSampler_stop(&sampler);
+ }
-
+ val = getSliderValue("mod freq");
- // a = val * tBuffer_getBufferLength(&buff);
+ tMBSampler_setStart(&sampler, val * 5.0f * leaf.sampleRate);
+
-// DBG("start: " + String(a));
-
val = getSliderValue("mod depth");
- y = val * 2.0f - 1.0f;
-// DBG(String(y));
- // b = val * tBuffer_getBufferLength(&buff);
-
-// DBG("rate: " + String(b));
- //
- // tSampler_setStart(&samp, a);
- // tSampler_setEnd(&samp, b);
- // tSampler_setRate(&samp, b);
-
- // tFormantShifter_setShiftFactor(&fs, x);
- // tFormantShifter_setIntensity(&fs, y);
+ tMBSampler_setRate(&sampler, val * 8.0f - 4.0f);
}
--- a/leaf/Inc/leaf-math.h
+++ b/leaf/Inc/leaf-math.h
@@ -225,6 +225,10 @@
float median3f(float a, float b, float c);
+ void place_step_dd(float *buffer, int index, float phase, float w, float scale);
+
+ void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta);
+
/*! @} */
//==============================================================================
--- a/leaf/Inc/leaf-sampling.h
+++ b/leaf/Inc/leaf-sampling.h
@@ -352,6 +352,108 @@
void tAutoSampler_setWindowSize (tAutoSampler* const, uint32_t size);
void tAutoSampler_setCrossfadeLength (tAutoSampler* const, uint32_t length);
void tAutoSampler_setRate (tAutoSampler* const, float rate);
+
+
+/*!
+ @defgroup tMBSampler tMBSampler
+ @ingroup sampling
+ @brief
+ @{
+
+ @fn void tMBSampler_init (tMBSampler* const, tBuffer* const)
+ @brief
+ @param
+
+ @fn void tMBSampler_initToPool (tMBSampler* const, tBuffer* const, tMempool* const)
+ @brief
+ @param
+
+ @fn void tMBSampler_free (tMBSampler* const)
+ @brief
+ @param
+
+ @fn float tMBSampler_tick (tMBSampler* const)
+ @brief
+ @param
+
+ @fn void tMBSampler_setSample (tMBSampler* const, tBuffer* const)
+ @brief
+ @param
+
+ @fn void tMBSampler_setMode (tMBSampler* const, PlayMode mode)
+ @brief
+ @param
+
+ @fn void tMBSampler_play (tMBSampler* const)
+ @brief
+ @param
+
+ @fn void tMBSampler_stop (tMBSampler* const)
+ @brief
+ @param
+
+ @fn void tMBSampler_setStart (tMBSampler* const, int32_t start)
+ @brief
+ @param
+
+ @fn void tMBSampler_setEnd (tMBSampler* const, int32_t end)
+ @brief
+ @param
+
+ @fn void tMBSampler_setLength (tMBSampler* const, int32_t length)
+ @brief
+ @param
+
+ @fn void tMBSampler_setCrossfadeLength (tMBSampler* const sp, uint32_t length)
+ @brief
+ @param
+
+ @fn void tMBSampler_setRate (tMBSampler* const, float rate)
+ @brief
+ @param
+
+ @} */
+
+#define FILLEN 256
+
+ typedef struct _tMBSampler
+ {
+ tMempool mempool;
+
+ tBuffer samp;
+ PlayMode mode;
+ int active;
+
+ tExpSmooth gain;
+
+ float out;
+ float last_delta;
+ float amp;
+ float last_amp;
+ float syncin;
+ float _p, _w, _z;
+ float _last_w;
+ float _f [FILLEN + STEP_DD_PULSE_LENGTH];
+ int _j;
+
+ int start, end;
+ } _tMBSampler;
+
+ typedef _tMBSampler* tMBSampler;
+
+ void tMBSampler_init (tMBSampler* const, tBuffer* const);
+ void tMBSampler_initToPool (tMBSampler* const, tBuffer* const, tMempool* const);
+ void tMBSampler_free (tMBSampler* const);
+
+ float tMBSampler_tick (tMBSampler* const);
+ void tMBSampler_setSample (tMBSampler* const, tBuffer* const);
+ void tMBSampler_setMode (tMBSampler* const, PlayMode mode);
+ void tMBSampler_play (tMBSampler* const);
+ void tMBSampler_stop (tMBSampler* const);
+ void tMBSampler_setStart (tMBSampler* const, int32_t start);
+ void tMBSampler_setEnd (tMBSampler* const, int32_t end);
+ void tMBSampler_setLength (tMBSampler* const, int32_t length);
+ void tMBSampler_setRate (tMBSampler* const, float rate);
#ifdef __cplusplus
}
--- a/leaf/Src/leaf-math.c
+++ b/leaf/Src/leaf-math.c
@@ -786,3 +786,51 @@
{
return fmax(fmin(a, b), fmin(fmax(a, b), c));
}
+
+/// MINBLEPS
+
+// https://github.com/MrBlueXav/Dekrispator_v2 blepvco.c
+
+
+void place_step_dd(float *buffer, int index, float phase, float w, float scale)
+{
+ float r;
+ int i;
+
+ r = MINBLEP_PHASES * phase / w;
+ i = floorf(r); //rintf(r - 0.5f); is there a reason to use rintf here
+ r -= (float)i;
+ i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
+ /* this would be better than the above, but more expensive:
+ * while (i < 0) {
+ * i += MINBLEP_PHASES;
+ * index++;
+ * }
+ */
+
+ while (i < MINBLEP_PHASES * STEP_DD_PULSE_LENGTH) {
+ buffer[index] += scale * (step_dd_table[i].value + r * step_dd_table[i].delta);
+ i += MINBLEP_PHASES;
+ index++;
+ }
+}
+//----------------------------------------------------------------------------------------------------------
+
+void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta)
+{
+ float r;
+ int i;
+
+ r = MINBLEP_PHASES * phase / w;
+ i = rintf(r - 0.5f);
+ r -= (float)i;
+ i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
+
+ slope_delta *= w;
+
+ while (i < MINBLEP_PHASES * SLOPE_DD_PULSE_LENGTH) {
+ buffer[index] += slope_delta * (slope_dd_table[i] + r * (slope_dd_table[i + 1] - slope_dd_table[i]));
+ i += MINBLEP_PHASES;
+ index++;
+ }
+}
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -868,53 +868,7 @@
}
-/// MINBLEPS
-// https://github.com/MrBlueXav/Dekrispator_v2 blepvco.c
-
-
-static void place_step_dd(float *buffer, int index, float phase, float w, float scale)
-{
- float r;
- int i;
-
- r = MINBLEP_PHASES * phase / w;
- i = rintf(r - 0.5f);
- r -= (float)i;
- i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
- /* this would be better than the above, but more expensive:
- * while (i < 0) {
- * i += MINBLEP_PHASES;
- * index++;
- * }
- */
-
- while (i < MINBLEP_PHASES * STEP_DD_PULSE_LENGTH) {
- buffer[index] += scale * (step_dd_table[i].value + r * step_dd_table[i].delta);
- i += MINBLEP_PHASES;
- index++;
- }
-}
-//----------------------------------------------------------------------------------------------------------
-
-static void place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta)
-{
- float r;
- int i;
-
- r = MINBLEP_PHASES * phase / w;
- i = rintf(r - 0.5f);
- r -= (float)i;
- i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
-
- slope_delta *= w;
-
- while (i < MINBLEP_PHASES * SLOPE_DD_PULSE_LENGTH) {
- buffer[index] += slope_delta * (slope_dd_table[i] + r * (slope_dd_table[i + 1] - slope_dd_table[i]));
- i += MINBLEP_PHASES;
- index++;
- }
-}
//----------------------------------------------------------------------------------------------------------
void tMBPulse_init(tMBPulse* const osc)
--- a/leaf/Src/leaf-sampling.c
+++ b/leaf/Src/leaf-sampling.c
@@ -875,3 +875,285 @@
{
;
}
+
+
+
+void tMBSampler_init(tMBSampler* const sp, tBuffer* const b)
+{
+ tMBSampler_initToPool(sp, b, &leaf.mempool);
+}
+
+void tMBSampler_initToPool(tMBSampler* const sp, tBuffer* const b, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tMBSampler* c = *sp = (_tMBSampler*) mpool_alloc(sizeof(_tMBSampler), m);
+ c->mempool = m;
+
+ c->samp = *b;
+
+ c->mode = PlayLoop;
+ c->active = 0;
+
+ tExpSmooth_initToPool(&c->gain, 0.0f, 0.01f, mp);
+
+ c->amp = 1.0f;
+ c->_p = 0.0f;
+ c->_w = 1.0f;
+ c->syncin = 0.0f;
+ c->_z = 0.0f;
+ c->_j = 0;
+ memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
+
+ c->start = 0;
+ tMBSampler_setEnd(sp, c->samp->bufferLength);
+}
+
+void tMBSampler_free (tMBSampler* const sp)
+{
+ _tMBSampler* p = *sp;
+
+ tExpSmooth_free(&p->gain);
+
+ mpool_free((char*)p, p->mempool);
+}
+
+void tMBSampler_setSample (tMBSampler* const sp, tBuffer* const b)
+{
+ _tMBSampler* p = *sp;
+
+ p->samp = *b;;
+
+ p->start = 0;
+ tMBSampler_setEnd(sp, p->samp->bufferLength);
+
+ p->_p = 0.0f;
+}
+
+
+
+float tMBSampler_tick (tMBSampler* const sp)
+{
+ _tMBSampler* c = *sp;
+
+ if (c->gain->curr == 0.0f && !c->active) return 0.0f;
+ if (c->_w == 0.0f) return c->out;
+
+ int start, end, length;
+ float* buff;
+ int j;
+ float syncin;
+ float a, p, w, z;
+ syncin = c->syncin;
+
+ start = c->start;
+ end = c->end;
+
+ buff = c->samp->buff;
+
+ p = c->_p; /* position */
+ w = c->_w; /* rate */
+ z = c->_z; /* low pass filter state */
+ j = c->_j; /* index into buffer _f */
+
+ length = end - start;
+
+ //a = 0.2 + 0.8 * vco->_port [FILT];
+ a = 0.5f; // when a = 1, LPfilter is disabled
+
+ p += w;
+
+ float next;
+
+// if (syncin >= 1e-20f) { /* sync to master */
+//
+// float eof_offset = (syncin - 1e-20f) * w;
+// float p_at_reset = p - eof_offset;
+// p = eof_offset;
+//
+// /* place any DD that may have occurred in subsample before reset */
+// if (p_at_reset >= end) {
+// while (p_at_reset >= (float) end) p_at_reset -= (float) length;
+//
+// float f = p_at_reset + eof_offset;
+// int i = (int) f;
+// f -= i;
+// float n = buff[i] * (1.0f - f) + buff[i+1] * f;
+//
+// place_step_dd(c->_f, j, p_at_reset + eof_offset, w,
+// n - c->out);
+// place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, (n - c->out) - c->last_delta);
+// }
+//
+// float f = p_at_reset;
+// int i = (int) f;
+// f -= i;
+// next = buff[i] * (1.0f - f) + buff[i+1] * f;
+//
+// /* now place reset DD */
+// place_step_dd(c->_f, j, p, w, next - c->out);
+// place_slope_dd(c->_f, j, p, w, (next - c->out) - c->last_delta);
+//
+// } else
+ if (w > 0.0f) {
+
+ if (p >= (float) end) { /* normal phase reset */
+
+ // start and end are never negative and end must also be greater than start
+ // so this loop is fine
+ while (p >= (float) end) p -= (float) length;
+
+ float f = p;
+ int i = (int) f;
+ f -= i;
+ next = buff[i] * (1.0f - f) + buff[i+1] * f;
+
+ place_step_dd(c->_f, j, p - start, w, next - c->out);
+ place_slope_dd(c->_f, j, p - start, w, (next - c->out) - c->last_delta);
+
+ 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 */
+//
+// p = (float) start;
+// next = buff[start];
+//
+// place_step_dd(c->_f, j, p, w, next - c->last);
+// place_slope_dd(c->_f, j, p, w, (next - c->last) - c->last_delta);
+// }
+ else {
+
+ float f = p;
+ int i = (int) f;
+ f -= i;
+ next = buff[i] * (1.0f - f) + buff[i+1] * f;
+ }
+
+ if (c->_last_w < 0.0f)
+ {
+ place_slope_dd(c->_f, j, p - start, w, (next - c->out) - c->last_delta);
+ }
+
+ } else { // if (w < 0.0f) {
+
+ if (p < (float) start) {
+
+ while (p < (float) start) p += (float) length;
+
+ float f = p;
+ int i = (int) f;
+ f -= i;
+ next = buff[i] * (1.0f - f) + buff[i+1] * f;
+
+ place_step_dd(c->_f, j, end - p, w, next - c->out);
+ place_slope_dd(c->_f, j, end - p, w, (next - c->out) - c->last_delta);
+
+ if (c->mode == PlayNormal) c->active = 0;
+ else if (c->mode == PlayBackAndForth) w = -w;
+ }
+// else if (p >= (float) end) {
+//
+// p = (float) end - 1;
+// next = buff[end - 1];
+// place_step_dd(c->_f, j, p, w, next - c->last);
+// place_slope_dd(c->_f, j, p, w, (next - c->last) - c->last_delta);
+// }
+ else {
+
+ float f = p;
+ int i = (int) f;
+ f -= i;
+ next = buff[i] * (1.0f - f) + buff[i+1] * f;
+ }
+
+ if (c->_last_w > 0.0f)
+ {
+ place_slope_dd(c->_f, j, end - p, w, (next - c->out) - c->last_delta);
+ }
+ }
+
+ c->_f[j + DD_SAMPLE_DELAY] += next;
+
+ z += a * (c->_f[j] - z); // LP filtering
+ next = c->amp * z;
+
+ c->last_delta = next - c->out;
+
+ c->out = next;
+
+ if (++j == FILLEN)
+ {
+ j = 0;
+ memcpy (c->_f, c->_f + FILLEN, STEP_DD_PULSE_LENGTH * sizeof (float));
+ memset (c->_f + STEP_DD_PULSE_LENGTH, 0, FILLEN * sizeof (float));
+ }
+
+ c->_p = p;
+ c->_w = c->_last_w = w;
+ c->_z = z;
+ c->_j = j;
+
+ return c->out * tExpSmooth_tick(&c->gain);
+}
+
+void tMBSampler_setMode (tMBSampler* const sp, PlayMode mode)
+{
+ _tMBSampler* p = *sp;
+ p->mode = mode;
+}
+
+void tMBSampler_play (tMBSampler* const sp)
+{
+ _tMBSampler* p = *sp;
+
+ if (p->active > 0)
+ {
+ p->syncin = 1e-20f;
+ }
+ tExpSmooth_setDest(&p->gain, 1.0f);
+ p->active = 1;
+ p->_p = p->start;
+ p->_z = 0.0f;
+ p->_j = 0;
+}
+
+void tMBSampler_stop (tMBSampler* const sp)
+{
+ _tMBSampler* p = *sp;
+
+ tExpSmooth_setDest(&p->gain, 0.0f);
+ p->active = 0;
+}
+
+void tMBSampler_setStart (tMBSampler* const sp, int32_t start)
+{
+ _tMBSampler* p = *sp;
+
+ if (start > p->end - 1) p->start = p->end - 1;
+ else if (start < 0) p->start = 0;
+ else p->start = start;
+}
+
+void tMBSampler_setEnd (tMBSampler* const sp, int32_t end)
+{
+ _tMBSampler* p = *sp;
+
+ if (end < p->start + 1) p->end = p->start + 1;
+ // always leave a trailing sample after the end
+ else if (end >= p->samp->bufferLength) p->end = p->samp->bufferLength - 1;
+ else p->end = end;
+}
+
+void tMBSampler_setLength (tMBSampler* const sp, int32_t length)
+{
+ _tMBSampler* p = *sp;
+ tMBSampler_setEnd(sp, p->start + length);
+}
+
+void tMBSampler_setRate (tMBSampler* const sp, float rate)
+{
+ _tMBSampler* p = *sp;
+
+ p->_w = rate;
+}
+