ref: ef023f65520b033e882dc48c8c6f9f5a1fda78c6
parent: 87cc8192ca2cdaa640486420c8e5836a1399a336
author: Matthew Wang <mjw7@princeton.edu>
date: Thu Jan 7 10:25:34 EST 2021
mb osc sync rework; general osc clean up
--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -17,6 +17,8 @@
tMBTriangle btri;
tMBPulse bpulse;
+tPhasor phasor;
+
tSVF lp, hp;
tPeriodDetection pd;
@@ -57,6 +59,16 @@
tWavetable_init(&wt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
tCompactWavetable_init(&cwt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
+
+ tMBTriangle_init(&btri, &leaf);
+ tMBPulse_init(&bpulse, &leaf);
+ tMBSaw_init(&bsaw, &leaf);
+ tMBSaw_setSyncMode(&bsaw, 1);
+ tMBTriangle_setSyncMode(&btri, 0);
+ tMBPulse_setSyncMode(&bpulse, 0);
+
+ tPhasor_init(&phasor, &leaf);
+ tPhasor_setFreq(&phasor, 220.f);
}
inline double getSawFall(double angle) {
@@ -72,8 +84,9 @@
{
// return tRetune_tick(&retune, input)[0];
// return tSimpleRetune_tick(&sretune, input);
+// tMBPulse_sync(&bpulse, tPhasor_tick(&phasor) * 2.f - 1.f);
+// return tMBPulse_tick(&bpulse);
return tWavetable_tick(&wt);
- return tCompactWavetable_tick(&cwt);
}
int firstFrame = 1;
@@ -81,7 +94,10 @@
void LEAFTest_block (void)
{
float val = getSliderValue("slider1");
- tWavetable_setFreq(&wt, val * 40000.);
+ tMBTriangle_setFreq(&btri, val * 440.f);
+ tMBPulse_setFreq(&bpulse, val * 160000.f - 80000.0f);
+ tMBSaw_setFreq(&bsaw, val * 10000.f);
+ tWavetable_setFreq(&wt, val * 160000.f - 80000.0f);
tCompactWavetable_setFreq(&cwt, val * 10000.);
// tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
// tSimpleRetune_tuneVoice(&sretune, 0, 300);
--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -104,7 +104,7 @@
@param osc A pointer to the tWavetable to initialize.
@param table A pointer to the wavetable data.
@param size The number of samples in the wave table.
- @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+ @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
@param mempool A pointer to the tMempool to use.
@fn void tWavetable_free (tWavetable* const osc)
@@ -444,162 +444,159 @@
//==============================================================================
/*!
- @defgroup ttri tTri
+ @defgroup tpbtriangle tPBTriangle
@ingroup oscillators
@brief Triangle wave oscillator with polyBLEP anti-aliasing.
@{
- @fn void tTri_init (tTri* const osc, LEAF* const leaf)
- @brief Initialize a tTri to the default mempool of a LEAF instance.
- @param osc A pointer to the tTri to initialize.
+ @fn void tPBTriangle_init (tPBTriangle* const osc, LEAF* const leaf)
+ @brief Initialize a tPBTriangle to the default mempool of a LEAF instance.
+ @param osc A pointer to the tPBTriangle to initialize.
@param leaf A pointer to the leaf instance.
- @fn void tTri_initToPool (tTri* const osc, tMempool* const mempool)
- @brief Initialize a tTri to a specified mempool.
- @param osc A pointer to the tTri to initialize.
+ @fn void tPBTriangle_initToPool (tPBTriangle* const osc, tMempool* const mempool)
+ @brief Initialize a tPBTriangle to a specified mempool.
+ @param osc A pointer to the tPBTriangle to initialize.
@param mempool A pointer to the tMempool to use.
- @fn void tTri_free (tTri* const osc)
+ @fn void tPBTriangle_free (tPBTriangle* const osc)
@brief Free a tTri from its mempool.
- @param osc A pointer to the tTri to free.
+ @param osc A pointer to the tPBTriangle to free.
- @fn float tTri_tick (tTri* const osc)
+ @fn float tPBTriangle_tick (tPBTriangle* const osc)
@brief
- @param osc A pointer to the relevant tTri.
+ @param osc A pointer to the relevant tPBTriangle.
- @fn void tTri_setFreq (tTri* const osc, float freq)
+ @fn void tPBTriangle_setFreq (tPBTriangle* const osc, float freq)
@brief
- @param osc A pointer to the relevant tTri.
+ @param osc A pointer to the relevant tPBTriangle.
- @fn void tTri_setSkew (tTri* const osc, float skew)
+ @fn void tPBTriangle_setSkew (tPBTriangle* const osc, float skew)
@brief
- @param osc A pointer to the relevant tTri.
+ @param osc A pointer to the relevant tPBTriangle.

@} */
- typedef struct _tTri
+ typedef struct _tPBTriangle
{
-
tMempool mempool;
float phase;
float inc,freq;
float skew;
float lastOut;
- } _tTri;
+ } _tPBTriangle;
- typedef _tTri* tTri;
+ typedef _tPBTriangle* tPBTriangle;
- void tTri_init (tTri* const osc, LEAF* const leaf);
- void tTri_initToPool (tTri* const osc, tMempool* const mempool);
- void tTri_free (tTri* const osc);
+ void tPBTriangle_init (tPBTriangle* const osc, LEAF* const leaf);
+ void tPBTriangle_initToPool (tPBTriangle* const osc, tMempool* const mempool);
+ void tPBTriangle_free (tPBTriangle* const osc);
- float tTri_tick (tTri* const osc);
- void tTri_setFreq (tTri* const osc, float freq);
- void tTri_setSkew (tTri* const osc, float skew);
+ float tPBTriangle_tick (tPBTriangle* const osc);
+ void tPBTriangle_setFreq (tPBTriangle* const osc, float freq);
+ void tPBTriangle_setSkew (tPBTriangle* const osc, float skew);
//==============================================================================
/*!
- @defgroup tpulse tPulse
+ @defgroup tpbpulse tPBPulse
@ingroup oscillators
@brief Pulse wave oscillator with polyBLEP anti-aliasing.
@{
- @fn void tPulse_init (tPulse* const osc, LEAF* const leaf)
- @brief Initialize a tPulse to the default mempool of a LEAF instance.
- @param osc A pointer to the tPulse to initialize.
+ @fn void tPBPulse_init (tPBPulse* const osc, LEAF* const leaf)
+ @brief Initialize a tPBPulse to the default mempool of a LEAF instance.
+ @param osc A pointer to the tPBPulse to initialize.
@param leaf A pointer to the leaf instance.
- @fn void tPulse_initToPool (tPulse* const osc, tMempool* const)
- @brief Initialize a tPulse to a specified mempool.
- @param osc A pointer to the tPulse to initialize.
+ @fn void tPBPulse_initToPool (tPBPulse* const osc, tMempool* const)
+ @brief Initialize a tPBPulse to a specified mempool.
+ @param osc A pointer to the tPBPulse to initialize.
@param mempool A pointer to the tMempool to use.
- @fn void tPulse_free (tPulse* const osc)
- @brief Free a tPulse from its mempool.
- @param osc A pointer to the tPulse to free.
+ @fn void tPBPulse_free (tPBPulse* const osc)
+ @brief Free a tPBPulse from its mempool.
+ @param osc A pointer to the tPBPulse to free.
- @fn float tPulse_tick (tPulse* const osc)
+ @fn float tPBPulse_tick (tPBPulse* const osc)
@brief
- @param osc A pointer to the relevant tPulse.
+ @param osc A pointer to the relevant tPBPulse.
- @fn void tPulse_setFreq (tPulse* const osc, float freq)
+ @fn void tPBPulse_setFreq (tPBPulse* const osc, float freq)
@brief
- @param osc A pointer to the relevant tPulse.
+ @param osc A pointer to the relevant tPBPulse.
- @fn void tPulse_setWidth (tPulse* const osc, float width)
+ @fn void tPBPulse_setWidth (tPBPulse* const osc, float width)
@brief
- @param osc A pointer to the relevant tPulse.
+ @param osc A pointer to the relevant tPBPulse.

@} */
- typedef struct _tPulse
+ typedef struct _tPBPulse
{
-
tMempool mempool;
float phase;
float inc,freq;
float width;
- } _tPulse;
+ } _tPBPulse;
- typedef _tPulse* tPulse;
+ typedef _tPBPulse* tPBPulse;
- void tPulse_init (tPulse* const osc, LEAF* const leaf);
- void tPulse_initToPool (tPulse* const osc, tMempool* const);
- void tPulse_free (tPulse* const osc);
+ void tPBPulse_init (tPBPulse* const osc, LEAF* const leaf);
+ void tPBPulse_initToPool (tPBPulse* const osc, tMempool* const);
+ void tPBPulse_free (tPBPulse* const osc);
- float tPulse_tick (tPulse* const osc);
- void tPulse_setFreq (tPulse* const osc, float freq);
- void tPulse_setWidth (tPulse* const osc, float width);
+ float tPBPulse_tick (tPBPulse* const osc);
+ void tPBPulse_setFreq (tPBPulse* const osc, float freq);
+ void tPBPulse_setWidth (tPBPulse* const osc, float width);
//==============================================================================
/*!
- @defgroup tsaw tSaw
+ @defgroup tpbsaw tPBSaw
@ingroup oscillators
@brief Saw wave oscillator with polyBLEP anti-aliasing.
@{
- @fn void tSaw_init (tSaw* const osc, LEAF* const leaf)
- @brief Initialize a tSaw to the default mempool of a LEAF instance.
- @param osc A pointer to the tSaw to initialize.
+ @fn void tPBSaw_init (tPBSaw* const osc, LEAF* const leaf)
+ @brief Initialize a tPBSaw to the default mempool of a LEAF instance.
+ @param osc A pointer to the tPBSaw to initialize.
@param leaf A pointer to the leaf instance.
- @fn void tSaw_initToPool (tSaw* const osc, tMempool* const mempool)
- @brief Initialize a tSaw to a specified mempool.
- @param osc A pointer to the tSaw to initialize.
+ @fn void tPBSaw_initToPool (tPBSaw* const osc, tMempool* const mempool)
+ @brief Initialize a tPBSaw to a specified mempool.
+ @param osc A pointer to the tPBSaw to initialize.
@param mempool A pointer to the tMempool to use.
- @fn void tSaw_free (tSaw* const osc)
- @brief Free a tSaw from its mempool.
- @param osc A pointer to the tSaw to free.
+ @fn void tPBSaw_free (tPBSaw* const osc)
+ @brief Free a tPBSaw from its mempool.
+ @param osc A pointer to the tPBSaw to free.
- @fn float tSaw_tick (tSaw* const osc)
+ @fn float tPBSaw_tick (tPBSaw* const osc)
@brief
- @param osc A pointer to the relevant tSaw.
+ @param osc A pointer to the relevant tPBSaw.
- @fn void tSaw_setFreq (tSaw* const osc, float freq)
+ @fn void tPBSaw_setFreq (tPBSaw* const osc, float freq)
@brief
- @param osc A pointer to the relevant tSaw.
+ @param osc A pointer to the relevant tPBSaw.

@} */
- typedef struct _tSaw
+ typedef struct _tPBSaw
{
-
tMempool mempool;
float phase;
float inc,freq;
- } _tSaw;
+ } _tPBSaw;
- typedef _tSaw* tSaw;
+ typedef _tPBSaw* tPBSaw;
- void tSaw_init (tSaw* const osc, LEAF* const leaf);
- void tSaw_initToPool (tSaw* const osc, tMempool* const mempool);
- void tSaw_free (tSaw* const osc);
+ void tPBSaw_init (tPBSaw* const osc, LEAF* const leaf);
+ void tPBSaw_initToPool (tPBSaw* const osc, tMempool* const mempool);
+ void tPBSaw_free (tPBSaw* const osc);
- float tSaw_tick (tSaw* const osc);
- void tSaw_setFreq (tSaw* const osc, float freq);
+ float tPBSaw_tick (tPBSaw* const osc);
+ void tPBSaw_setFreq (tPBSaw* const osc, float freq);
//==============================================================================
@@ -880,13 +877,13 @@
@brief
@param osc A pointer to the relevant tMBPulse.
- @fn void tMBPulse_syncIn(tMBPulse* const osc, float sync)
+ @fn float tMBPulse_sync(tMBPulse* const osc, float sync)
@brief
@param osc A pointer to the relevant tMBPulse.
- @fn float tMBPulse_syncOut(tMBPulse* const osc)
- @brief
- @param osc A pointer to the relevant tMBPulse.
+ @fn void tMBPulse_setSyncMode(tMBPulse* const osc, int hardOrSoft)
+ @brief Set the sync behavior of the oscillator.
+ @param hardOrSoft 0 for hard sync, 1 for soft sync

@} */
@@ -899,8 +896,10 @@
float last_amp;
float freq;
float waveform; // duty cycle, must be in [-1, 1]
- float syncin;
- float syncout;
+ float lastsyncin;
+ float sync;
+ float syncdir;
+ int softsync;
float _p, _w, _b, _x, _z;
float _f [FILLEN + STEP_DD_PULSE_LENGTH];
int _j, _k;
@@ -916,8 +915,8 @@
float tMBPulse_tick(tMBPulse* const osc);
void tMBPulse_setFreq(tMBPulse* const osc, float f);
void tMBPulse_setWidth(tMBPulse* const osc, float w);
- void tMBPulse_syncIn(tMBPulse* const osc, float sync);
- float tMBPulse_syncOut(tMBPulse* const osc);
+ float tMBPulse_sync(tMBPulse* const osc, float sync);
+ void tMBPulse_setSyncMode(tMBPulse* const osc, int hardOrSoft);
/*!
@defgroup tmbtriangle tMBTriangle
@@ -949,14 +948,14 @@
@brief
@param osc A pointer to the relevant tMBTriangle.
- @fn void tMBTriangle_syncIn(tMBTriangle* const osc, float sync)
+ @fn float tMBTriangle_sync(tMBTriangle* const osc, float sync)
@brief
@param osc A pointer to the relevant tMBTriangle.
- @fn float tMBTriangle_syncOut(tMBTriangle* const osc)
- @brief
- @param osc A pointer to the relevant tMBTriangle.
- 
+ @fn void tMBTriangle_setSyncMode(tMBTriangle* const osc, int hardOrSoft)
+ @brief Set the sync behavior of the oscillator.
+ @param hardOrSoft 0 for hard sync, 1 for soft sync
+
@} */
typedef struct _tMBTriangle
@@ -968,8 +967,10 @@
float last_amp;
float freq;
float waveform; // duty cycle, must be in [-1, 1]
- float syncin;
- float syncout;
+ float lastsyncin;
+ float sync;
+ float syncdir;
+ int softsync;
float _p, _w, _b, _z;
float _f [FILLEN + LONGEST_DD_PULSE_LENGTH];
int _j, _k;
@@ -985,8 +986,8 @@
float tMBTriangle_tick(tMBTriangle* const osc);
void tMBTriangle_setFreq(tMBTriangle* const osc, float f);
void tMBTriangle_setWidth(tMBTriangle* const osc, float w);
- void tMBTriangle_syncIn(tMBTriangle* const osc, float sync);
- float tMBTriangle_syncOut(tMBTriangle* const osc);
+ float tMBTriangle_sync(tMBTriangle* const osc, float sync);
+ void tMBTriangle_setSyncMode(tMBTriangle* const osc, int hardOrSoft);
/*!
@@ -1008,33 +1009,38 @@
@param osc A pointer to the tMBSaw to free.
@fn float tMBSaw_tick(tMBSaw* const osc)
- @brief
+ @brief Tick the oscillator.
@param osc A pointer to the relevant tMBSaw.
+ @return The ticked sample.
@fn void tMBSaw_setFreq(tMBSaw* const osc, float f)
- @brief
+ @brief Set the frequency of the oscillator.
@param osc A pointer to the relevant tMBSaw.
+ @param freq The new frequency.
- @fn void tMBSaw_syncIn(tMBSaw* const osc, float sync)
- @brief
+ @fn float tMBSaw_sync(tMBSaw* const osc, float sync)
+ @brief Sync this oscillator to another signal.
@param osc A pointer to the relevant tMBSaw.
+ @param sync A sample of the signal to sync to.
+ @return The passed in sample.
- @fn float tMBSaw_syncOut(tMBSaw* const osc)
- @brief
- @param osc A pointer to the relevant tMBSaw.
+ @fn void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft)
+ @brief Set the sync behavior of the oscillator.
+ @param hardOrSoft 0 for hard sync, 1 for soft sync

@} */
typedef struct _tMBSaw
{
-
tMempool mempool;
float out;
float amp;
float last_amp;
float freq;
- float syncin;
- float syncout;
+ float lastsyncin;
+ float sync;
+ float syncdir;
+ int softsync;
float _p, _w, _z;
float _f [FILLEN + STEP_DD_PULSE_LENGTH];
int _j;
@@ -1049,11 +1055,9 @@
float tMBSaw_tick(tMBSaw* const osc);
void tMBSaw_setFreq(tMBSaw* const osc, float f);
- void tMBSaw_syncIn(tMBSaw* const osc, float sync);
- float tMBSaw_syncOut(tMBSaw* const osc);
-
-
-
+ float tMBSaw_sync(tMBSaw* const osc, float sync);
+ void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft);
+
#ifdef __cplusplus
}
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -50,6 +50,7 @@
c->freq = freq;
c->inc = freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
float tTable_tick(tTable* const cy)
@@ -63,8 +64,8 @@
// Phasor increment
c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
- while (c->phase < 0.0f) c->phase += 1.0f;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
// Wavetable synthesis
@@ -84,6 +85,7 @@
LEAF* leaf = c->mempool->leaf;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
void tWavetable_init(tWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
@@ -179,8 +181,8 @@
// Phasor increment
c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
- while (c->phase < 0.0f) c->phase += 1.0f;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
// Wavetable synthesis
temp = c->size * c->phase;
@@ -212,6 +214,7 @@
c->freq = freq;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
// abs for negative frequencies
c->w = fabsf(c->freq * c->invBaseFreq);
@@ -328,8 +331,8 @@
// Phasor increment
c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
- while (c->phase < 0.0f) c->phase += 1.0f;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
// Wavetable synthesis
temp = c->sizes[c->oct] * c->phase;
@@ -362,6 +365,7 @@
c->freq = freq;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
// abs for negative frequencies
c->w = fabsf(c->freq * c->invBaseFreq);
@@ -416,6 +420,7 @@
c->freq = freq;
c->inc = freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
//need to check bounds and wrap table properly to allow through-zero FM
@@ -430,8 +435,8 @@
// Phasor increment
c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
- while (c->phase < 0.0f) c->phase += 1.0f;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
// Wavetable synthesis
@@ -451,6 +456,7 @@
LEAF* leaf = c->mempool->leaf;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
#endif // LEAF_INCLUDE_SINE_TABLE
@@ -488,6 +494,7 @@
c->freq = freq;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
// abs for negative frequencies
c->w = fabsf(c->freq * (TRI_TABLE_SIZE * leaf->invSampleRate));
@@ -512,8 +519,8 @@
// Phasor increment
c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
- while (c->phase < 0.0f) c->phase += 1.0f;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
// Wavetable synthesis
temp = TRI_TABLE_SIZE * c->phase;
@@ -542,6 +549,7 @@
LEAF* leaf = c->mempool->leaf;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
#endif // LEAF_INCLUDE_TRIANGLE_TABLE
@@ -579,6 +587,7 @@
c->freq = freq;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
// abs for negative frequencies
c->w = fabsf(c->freq * (SQR_TABLE_SIZE * leaf->invSampleRate));
@@ -602,8 +611,8 @@
// Phasor increment
c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
- while (c->phase < 0.0f) c->phase += 1.0f;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
// Wavetable synthesis
temp = SQR_TABLE_SIZE * c->phase;
@@ -632,6 +641,7 @@
LEAF* leaf = c->mempool->leaf;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
#endif // LEAF_INCLUDE_SQUARE_TABLE
@@ -669,6 +679,7 @@
c->freq = freq;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
// abs for negative frequencies
c->w = fabsf(c->freq * (SAW_TABLE_SIZE * leaf->invSampleRate));
@@ -722,6 +733,7 @@
LEAF* leaf = c->mempool->leaf;
c->inc = c->freq * leaf->invSampleRate;
+ c->inc -= (int)c->inc;
}
#endif // LEAF_INCLUDE_SAWTOOTH_TABLE
@@ -728,15 +740,15 @@
//==============================================================================
/* tTri: Anti-aliased Triangle waveform. */
-void tTri_init (tTri* const osc, LEAF* const leaf)
+void tPBTriangle_init (tPBTriangle* const osc, LEAF* const leaf)
{
- tTri_initToPool(osc, &leaf->mempool);
+ tPBTriangle_initToPool(osc, &leaf->mempool);
}
-void tTri_initToPool (tTri* const osc, tMempool* const mp)
+void tPBTriangle_initToPool (tPBTriangle* const osc, tMempool* const mp)
{
_tMempool* m = *mp;
- _tTri* c = *osc = (_tTri*) mpool_alloc(sizeof(_tTri), m);
+ _tPBTriangle* c = *osc = (_tPBTriangle*) mpool_alloc(sizeof(_tPBTriangle), m);
c->mempool = m;
c->inc = 0.0f;
@@ -745,16 +757,16 @@
c->lastOut = 0.0f;
}
-void tTri_free (tTri* const cy)
+void tPBTriangle_free (tPBTriangle* const cy)
{
- _tTri* c = *cy;
+ _tPBTriangle* c = *cy;
mpool_free((char*)c, c->mempool);
}
-float tTri_tick (tTri* const osc)
+float tPBTriangle_tick (tPBTriangle* const osc)
{
- _tTri* c = *osc;
+ _tPBTriangle* c = *osc;
float out;
float skew;
@@ -776,18 +788,16 @@
out = (skew * c->inc * out) + ((1 - c->inc) * c->lastOut);
c->lastOut = out;
- c->phase += c->inc;
- if (c->phase >= 1.0f)
- {
- c->phase -= 1.0f;
- }
+ c->phase += c->inc - (int)c->inc;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
return out;
}
-void tTri_setFreq (tTri* const osc, float freq)
+void tPBTriangle_setFreq (tPBTriangle* const osc, float freq)
{
- _tTri* c = *osc;
+ _tPBTriangle* c = *osc;
LEAF* leaf = c->mempool->leaf;
c->freq = freq;
@@ -794,9 +804,9 @@
c->inc = freq * leaf->invSampleRate;
}
-void tTri_setSkew (tTri* const osc, float skew)
+void tPBTriangle_setSkew (tPBTriangle* const osc, float skew)
{
- _tTri* c = *osc;
+ _tPBTriangle* c = *osc;
c->skew = (skew + 1.0f) * 0.5f;
}
@@ -804,15 +814,15 @@
//==============================================================================
/* tPulse: Anti-aliased pulse waveform. */
-void tPulse_init (tPulse* const osc, LEAF* const leaf)
+void tPBPulse_init (tPBPulse* const osc, LEAF* const leaf)
{
- tPulse_initToPool(osc, &leaf->mempool);
+ tPBPulse_initToPool(osc, &leaf->mempool);
}
-void tPulse_initToPool (tPulse* const osc, tMempool* const mp)
+void tPBPulse_initToPool (tPBPulse* const osc, tMempool* const mp)
{
_tMempool* m = *mp;
- _tPulse* c = *osc = (_tPulse*) mpool_alloc(sizeof(_tPulse), m);
+ _tPBPulse* c = *osc = (_tPBPulse*) mpool_alloc(sizeof(_tPBPulse), m);
c->mempool = m;
c->inc = 0.0f;
@@ -820,16 +830,16 @@
c->width = 0.5f;
}
-void tPulse_free (tPulse* const osc)
+void tPBPulse_free (tPBPulse* const osc)
{
- _tPulse* c = *osc;
+ _tPBPulse* c = *osc;
mpool_free((char*)c, c->mempool);
}
-float tPulse_tick (tPulse* const osc)
+float tPBPulse_tick (tPBPulse* const osc)
{
- _tPulse* c = *osc;
+ _tPBPulse* c = *osc;
float out;
if (c->phase < c->width) out = 1.0f;
@@ -837,18 +847,16 @@
out += LEAF_poly_blep(c->phase, c->inc);
out -= LEAF_poly_blep(fmodf(c->phase + (1.0f - c->width), 1.0f), c->inc);
- c->phase += c->inc;
- if (c->phase >= 1.0f)
- {
- c->phase -= 1.0f;
- }
+ c->phase += c->inc - (int)c->inc;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
return out;
}
-void tPulse_setFreq (tPulse* const osc, float freq)
+void tPBPulse_setFreq (tPBPulse* const osc, float freq)
{
- _tPulse* c = *osc;
+ _tPBPulse* c = *osc;
LEAF* leaf = c->mempool->leaf;
c->freq = freq;
@@ -855,9 +863,9 @@
c->inc = freq * leaf->invSampleRate;
}
-void tPulse_setWidth (tPulse* const osc, float width)
+void tPBPulse_setWidth (tPBPulse* const osc, float width)
{
- _tPulse* c = *osc;
+ _tPBPulse* c = *osc;
c->width = width;
}
@@ -865,15 +873,15 @@
//==============================================================================
/* tSawtooth: Anti-aliased Sawtooth waveform. */
-void tSaw_init (tSaw* const osc, LEAF* const leaf)
+void tPBSaw_init (tPBSaw* const osc, LEAF* const leaf)
{
- tSaw_initToPool(osc, &leaf->mempool);
+ tPBSaw_initToPool(osc, &leaf->mempool);
}
-void tSaw_initToPool (tSaw* const osc, tMempool* const mp)
+void tPBSaw_initToPool (tPBSaw* const osc, tMempool* const mp)
{
_tMempool* m = *mp;
- _tSaw* c = *osc = (_tSaw*) mpool_alloc(sizeof(_tSaw), m);
+ _tPBSaw* c = *osc = (_tPBSaw*) mpool_alloc(sizeof(_tPBSaw), m);
c->mempool = m;
c->inc = 0.0f;
@@ -880,32 +888,30 @@
c->phase = 0.0f;
}
-void tSaw_free (tSaw* const osc)
+void tPBSaw_free (tPBSaw* const osc)
{
- _tSaw* c = *osc;
+ _tPBSaw* c = *osc;
mpool_free((char*)c, c->mempool);
}
-float tSaw_tick (tSaw* const osc)
+float tPBSaw_tick (tPBSaw* const osc)
{
- _tSaw* c = *osc;
+ _tPBSaw* c = *osc;
float out = (c->phase * 2.0f) - 1.0f;
out -= LEAF_poly_blep(c->phase, c->inc);
- c->phase += c->inc;
- if (c->phase >= 1.0f)
- {
- c->phase -= 1.0f;
- }
+ c->phase += c->inc - (int)c->inc;
+ if (c->phase >= 1.0f) c->phase -= 1.0f;
+ if (c->phase < 0.0f) c->phase += 1.0f;
return out;
}
-void tSaw_setFreq (tSaw* const osc, float freq)
+void tPBSaw_setFreq (tPBSaw* const osc, float freq)
{
- _tSaw* c = *osc;
+ _tPBSaw* c = *osc;
LEAF* leaf = c->mempool->leaf;
c->freq = freq;
@@ -954,6 +960,7 @@
p->freq = freq;
p->inc = freq * leaf->invSampleRate;
+ p->inc -= (int)p->inc;
}
float tPhasor_tick(tPhasor* const ph)
@@ -961,8 +968,7 @@
_tPhasor* p = *ph;
p->phase += p->inc;
-
-
+
p->phaseDidReset = 0;
if (p->phase >= 1.0f)
{
@@ -969,6 +975,11 @@
p->phaseDidReset = 1;
p->phase -= 1.0f;
}
+ else if (p->phase < 0.0f)
+ {
+ p->phaseDidReset = 1;
+ p->phase += 1.0f;
+ }
return p->phase;
}
@@ -1021,17 +1032,17 @@
//=================================================================================
/* Neuron */
-void tNeuronSampleRateChanged(tNeuron* nr)
+void tNeuronSampleRateChanged(tNeuron* nr)
{
}
-void tNeuron_init(tNeuron* const nr, LEAF* const leaf)
+void tNeuron_init(tNeuron* const nr, LEAF* const leaf)
{
tNeuron_initToPool(nr, &leaf->mempool);
}
-void tNeuron_initToPool (tNeuron* const nr, tMempool* const mp)
+void tNeuron_initToPool (tNeuron* const nr, tMempool* const mp)
{
_tMempool* m = *mp;
_tNeuron* n = *nr = (_tNeuron*) mpool_alloc(sizeof(_tNeuron), m);
@@ -1101,7 +1112,7 @@
n->rate[2] = n->gL/n->C;
}
-void tNeuron_setV1(tNeuron* const nr, float V1)
+void tNeuron_setV1(tNeuron* const nr, float V1)
{
_tNeuron* n = *nr;
n->V[0] = V1;
@@ -1108,31 +1119,31 @@
}
-void tNeuron_setV2(tNeuron* const nr, float V2)
+void tNeuron_setV2(tNeuron* const nr, float V2)
{
_tNeuron* n = *nr;
n->V[1] = V2;
}
-void tNeuron_setV3(tNeuron* const nr, float V3)
+void tNeuron_setV3(tNeuron* const nr, float V3)
{
_tNeuron* n = *nr;
n->V[2] = V3;
}
-void tNeuron_setTimeStep(tNeuron* const nr, float timeStep)
+void tNeuron_setTimeStep(tNeuron* const nr, float timeStep)
{
_tNeuron* n = *nr;
n->timeStep = timeStep;
}
-void tNeuron_setK(tNeuron* const nr, float K)
+void tNeuron_setK(tNeuron* const nr, float K)
{
_tNeuron* n = *nr;
n->gK = K;
}
-void tNeuron_setL(tNeuron* const nr, float L)
+void tNeuron_setL(tNeuron* const nr, float L)
{
_tNeuron* n = *nr;
n->gL = L;
@@ -1139,13 +1150,13 @@
n->rate[2] = n->gL/n->C;
}
-void tNeuron_setN(tNeuron* const nr, float N)
+void tNeuron_setN(tNeuron* const nr, float N)
{
_tNeuron* n = *nr;
n->gN = N;
}
-void tNeuron_setC(tNeuron* const nr, float C)
+void tNeuron_setC(tNeuron* const nr, float C)
{
_tNeuron* n = *nr;
n->C = C;
@@ -1152,7 +1163,7 @@
n->rate[2] = n->gL/n->C;
}
-float tNeuron_tick(tNeuron* const nr)
+float tNeuron_tick(tNeuron* const nr)
{
_tNeuron* n = *nr;
@@ -1228,13 +1239,13 @@
}
-void tNeuron_setMode (tNeuron* const nr, NeuronMode mode)
+void tNeuron_setMode (tNeuron* const nr, NeuronMode mode)
{
_tNeuron* n = *nr;
n->mode = mode;
}
-void tNeuron_setCurrent (tNeuron* const nr, float current)
+void tNeuron_setCurrent (tNeuron* const nr, float current)
{
_tNeuron* n = *nr;
n->current = current;
@@ -1258,7 +1269,10 @@
c->_init = true;
c->amp = 1.0f;
c->freq = 440.f;
- c->syncin = 0.0f;
+ c->lastsyncin = 0.0f;
+ c->sync = 0.0f;
+ c->syncdir = 1.0f;
+ c->softsync = 0;
c->waveform = 0.0f;
c->_z = 0.0f;
c->_j = 0;
@@ -1277,10 +1291,10 @@
LEAF* leaf = c->mempool->leaf;
int j, k;
- float freq, syncin;
- float a, b, db, p, tw, tb, w, dw, x, z;
+ float freq, sync;
+ float a, b, p, w, x, z, sw;
- syncin = c->syncin;
+ sync = c->sync;
freq = c->freq;
p = c->_p; /* phase [0, 1) */
w = c->_w; /* phase increment */
@@ -1293,22 +1307,9 @@
if (c->_init) {
p = 0.0f;
- w = freq / leaf->sampleRate;
+ w = freq * leaf->invSampleRate;
b = 0.5f * (1.0f + c->waveform );
- if (w >= 0)
- {
- if (w < 1e-5f) w = 1e-5f;
- if (w > 0.5f) w = 0.5f;
- if (b < w) b = w;
- if (b > 1.0f - w) b = 1.0f - w;
- }
- else
- {
- if (w > -1e-5f) w = -1e-5f;
- if (w < -0.5f) w = -0.5f;
- if (b < -w) b = -w;
- if (b > 1.0f + w) b = 1.0f + w;
- }
+
/* for variable-width rectangular wave, we could do DC compensation with:
* x = 1.0f - b;
* but that doesn't work well with highly modulated hard sync. Instead,
@@ -1324,100 +1325,76 @@
// a = 0.2 + 0.8 * vco->_port [FILT];
a = 0.5f; // when a = 1, LPfilter is disabled
- tw = freq / leaf->sampleRate;
- if (tw >= 0)
- {
- if (tw < 1e-5f) tw = 1e-5f;
- if (tw > 0.5f) tw = 0.5f;
- }
- else
- {
- if (tw > -1e-5f) tw = -1e-5f;
- if (tw < -0.5f) tw = -0.5f;
- }
+ w = freq * leaf->invSampleRate;
+ b = 0.5f * (1.0f + c->waveform);
+
+ if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
- tb = 0.5f * (1.0f + c->waveform);
- if (w >= 0)
- {
- if (tb < w) tb = w;
- if (tb > 1.0f - w) tb = 1.0f - w;
- }
- else
- {
- if (tb < -w) tb = -w;
- if (tb > 1.0f + w) tb = 1.0f + w;
- }
+ sw = w * c->syncdir;
+ p += sw - (int)sw;
- dw = (tw - w);
- db = (tb - b);
-
- w += dw;
- b += db;
- p += w;
-
- if (syncin >= 1e-20f) { /* sync to master */
- //
- float eof_offset = (syncin - 1e-20f) * w;
+ if (sync > 0.0f && c->softsync == 0) { /* sync to master */
+ float eof_offset = sync * sw;
float p_at_reset = p - eof_offset;
- if (w > 0) p = eof_offset;
- else p = 1.0f - eof_offset;
+ if (sw > 0) p = eof_offset;
+ else if (sw < 0) p = 1.0f - eof_offset;
/* place any DDs that may have occurred in subsample before reset */
if (!k) {
- if (w > 0)
+ if (sw > 0)
{
if (p_at_reset >= b) {
- place_step_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f);
+ place_step_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f);
k = 1;
x = -0.5f;
}
if (p_at_reset >= 1.0f) {
p_at_reset -= 1.0f;
- place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
+ place_step_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f);
k = 0;
x = 0.5f;
}
}
- else
+ else if (sw < 0)
{
if (p_at_reset < 0.0f) {
p_at_reset += 1.0f;
- place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -1.0f);
k = 1;
x = -0.5f;
}
if (k && p_at_reset < b) {
- place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -w, 1.0f);
+ place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, 1.0f);
k = 0;
x = 0.5f;
}
}
} else {
- if (w > 0)
+ if (sw > 0)
{
if (p_at_reset >= 1.0f) {
p_at_reset -= 1.0f;
- place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
+ place_step_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f);
k = 0;
x = 0.5f;
}
if (!k && p_at_reset >= b) {
- place_step_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f);
+ place_step_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f);
k = 1;
x = -0.5f;
}
}
- else
+ else if (sw < 0)
{
if (p_at_reset < b) {
- place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -w, 1.0f);
+ place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, 1.0f);
k = 0;
x = 0.5f;
}
if (p_at_reset < 0.0f) {
p_at_reset += 1.0f;
- place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -1.0f);
k = 1;
x = -0.5f;
}
@@ -1425,67 +1402,58 @@
}
/* now place reset DD */
- if (w > 0)
+ if (sw > 0)
{
if (k) {
- place_step_dd(c->_f, j, p, w, 1.0f);
+ place_step_dd(c->_f, j, p, sw, 1.0f);
k = 0;
x = 0.5f;
}
if (p >= b) {
- place_step_dd(c->_f, j, p - b, w, -1.0f);
+ place_step_dd(c->_f, j, p - b, sw, -1.0f);
k = 1;
x = -0.5f;
}
}
- else
+ else if (sw < 0)
{
if (!k) {
- place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
k = 1;
x = -0.5f;
}
if (p < b) {
- place_step_dd(c->_f, j, b - p, -w, 1.0f);
+ place_step_dd(c->_f, j, b - p, -sw, 1.0f);
k = 0;
x = 0.5f;
}
}
-
- c->syncout = syncin; /* best we can do is pass on upstream sync */
-
} else if (!k) { /* normal operation, signal currently high */
- if (w > 0)
+ if (sw > 0)
{
if (p >= b) {
- place_step_dd(c->_f, j, p - b, w, -1.0f);
+ place_step_dd(c->_f, j, p - b, sw, -1.0f);
k = 1;
x = -0.5f;
}
if (p >= 1.0f) {
p -= 1.0f;
- c->syncout = p / w + 1e-20f;
- place_step_dd(c->_f, j, p, w, 1.0f);
+ place_step_dd(c->_f, j, p, sw, 1.0f);
k = 0;
x = 0.5f;
- } else {
- c->syncout = 0.0f;
}
}
- else
+ else if (sw < 0)
{
if (p < 0.0f) {
p += 1.0f;
- c->syncout = (1.0f - p) / -w + 1e-20f;
- place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
k = 1;
x = -0.5f;
- } else {
- c->syncout = 0.0f;
}
if (k && p < b) {
- place_step_dd(c->_f, j, b - p, -w, 1.0f);
+ place_step_dd(c->_f, j, b - p, -sw, 1.0f);
k = 0;
x = 0.5f;
}
@@ -1493,40 +1461,33 @@
} else { /* normal operation, signal currently low */
- if (w > 0)
+ if (sw > 0)
{
if (p >= 1.0f) {
p -= 1.0f;
- c->syncout = p / w + 1e-20f;
- place_step_dd(c->_f, j, p, w, 1.0f);
+ place_step_dd(c->_f, j, p, sw, 1.0f);
k = 0;
x = 0.5f;
- } else {
- c->syncout = 0.0f;
}
if (!k && p >= b) {
- place_step_dd(c->_f, j, p - b, w, -1.0f);
+ place_step_dd(c->_f, j, p - b, sw, -1.0f);
k = 1;
x = -0.5f;
}
}
- else
+ else if (sw < 0)
{
if (p < b) {
- place_step_dd(c->_f, j, b - p, -w, 1.0f);
+ place_step_dd(c->_f, j, b - p, -sw, 1.0f);
k = 0;
x = 0.5f;
}
if (p < 0.0f) {
p += 1.0f;
- c->syncout = (1.0f - p) / -w + 1e-20f;
- place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
k = 1;
x = -0.5f;
- } else {
- c->syncout = 0.0f;
}
-
}
}
c->_f[j + DD_SAMPLE_DELAY] += x;
@@ -1564,19 +1525,30 @@
c->waveform = w;
}
-void tMBPulse_syncIn(tMBPulse* const osc, float sync)
+float tMBPulse_sync(tMBPulse* const osc, float value)
{
_tMBPulse* c = *osc;
- c->syncin = sync;
+
+ //based on https://github.com/VCVRack/Fundamental/blob/5799ee2a9b21492b42ebcb9b65d5395ef5c1cbe2/src/VCO.cpp#L123
+ float last = c->lastsyncin;
+ float delta = value - last;
+ float crossing = -last / delta;
+ c->lastsyncin = value;
+ if ((0.f < crossing) && (crossing <= 1.f) && (value >= 0.f))
+ c->sync = (1.f - crossing) * delta;
+ else c->sync = 0.f;
+
+ return value;
}
-float tMBPulse_syncOut(tMBPulse* const osc)
+void tMBPulse_setSyncMode(tMBPulse* const osc, int hardOrSoft)
{
_tMBPulse* c = *osc;
- return c->syncout;
+ c->softsync = hardOrSoft > 0 ? 1 : 0;
}
-//----------------------------------------------------------------------------------------------------------
+//==========================================================================================================
+//==========================================================================================================
void tMBTriangle_init(tMBTriangle* const osc, LEAF* const leaf)
{
@@ -1591,7 +1563,10 @@
c->amp = 1.0f;
c->freq = 440.f;
- c->syncin = 0.0f;
+ c->lastsyncin = 0.0f;
+ c->sync = 0.0f;
+ c->syncdir = 1.0f;
+ c->softsync = 0;
c->waveform = 0.0f;
c->_init = true;
c->_z = 0.0f;
@@ -1610,11 +1585,12 @@
_tMBTriangle* c = *osc;
LEAF* leaf = c->mempool->leaf;
- int j, k;
- float freq, syncin;
- float a, b, b1, db, p, tw, tb, w, dw, x, z;
+ int j, k, dir;
+ float freq, sync;
+ float a, b, b1, p, w, sw, x, z;
- syncin = c->syncin;
+ sync = c->sync;
+ dir = c->syncdir;
freq = c->freq;
p = c->_p; /* phase [0, 1) */
w = c->_w; /* phase increment */
@@ -1626,23 +1602,8 @@
if (c->_init) {
// w = (exp2ap (freq[1] + vco->_port[OCTN] + vco->_port[TUNE] + expm[1] * vco->_port[EXPG] + 8.03136)
// + 1e3 * linm[1] * vco->_port[LING]) / SAMPLERATE;
- w = freq / leaf->sampleRate;
+ w = freq * leaf->invSampleRate;
b = 0.5f * (1.0f + c->waveform);
- if (w >= 0)
- {
- if (w < 1e-5f) w = 1e-5f;
- if (w > 0.5f) w = 0.5f;
- if (b < w) b = w;
- if (b > 1.0f - w) b = 1.0f - w;
- }
- else
- {
- if (w > -1e-5f) w = -1e-5f;
- if (w < -0.5f) w = -0.5f;
- if (b < -w) b = -w;
- if (b > 1.0f + w) b = 1.0f + w;
- }
-
p = 0.5f * b;
/* if we valued alias-free startup over low startup time, we could do:
* p -= w;
@@ -1654,105 +1615,81 @@
// a = 0.2 + 0.8 * vco->_port [FILT];
a = 0.5f; // when a = 1, LPfilter is disabled
- tw = freq / leaf->sampleRate;
- if (tw >= 0)
- {
- if (tw < 1e-5f) tw = 1e-5f;
- if (tw > 0.5f) tw = 0.5f;
- }
- else
- {
- if (tw > -1e-5f) tw = -1e-5f;
- if (tw < -0.5f) tw = -0.5f;
- }
+ w = freq * leaf->invSampleRate;
+ b = 0.5f * (1.0f + c->waveform);
+ b1 = 1.0f - b;
- tb = 0.5f * (1.0f + c->waveform);
- if (w >= 0)
- {
- if (tb < w) tb = w;
- if (tb > 1.0f - w) tb = 1.0f - w;
- }
- else
- {
- if (tb < -w) tb = -w;
- if (tb > 1.0f + w) tb = 1.0f + w;
- }
+ if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
- dw = (tw - w);
- db = (tb - b);
+ sw = w * c->syncdir;
+ p += sw - (int)sw;
- w += dw;
- b += db;
- b1 = 1.0f - b;
- p += w;
-
- if (syncin >= 1e-20f) { /* sync to master */
-
- float eof_offset = (syncin - 1e-20f) * w;
+ if (sync > 0.0f && c->softsync == 0) { /* sync to master */
+ float eof_offset = sync * sw;
float p_at_reset = p - eof_offset;
- if (w > 0) p = eof_offset;
- else p = 1.0f - eof_offset;
+ if (sw > 0) p = eof_offset;
+ else if (sw < 0) p = 1.0f - eof_offset;
//
/* place any DDs that may have occurred in subsample before reset */
if (!k) {
x = -0.5f + p_at_reset / b;
- if (w > 0)
+ if (sw > 0)
{
if (p_at_reset >= b) {
x = 0.5f - (p_at_reset - b) / b1;
- place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f / b1 - 1.0f / b);
k = 1;
}
if (p_at_reset >= 1.0f) {
p_at_reset -= 1.0f;
x = -0.5f + p_at_reset / b;
- place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f / b + 1.0f / b1);
k = 0;
}
}
- else
+ else if (sw < 0)
{
if (p_at_reset < 0.0f) {
p_at_reset += 1.0f;
x = 0.5f - (p_at_reset - b) / b1;
- place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, 1.0f / b + 1.0f / b1);
k = 1;
}
if (k && p_at_reset < b) {
x = -0.5f + p_at_reset / b;
- place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, -1.0f / b1 - 1.0f / b);
k = 0;
}
}
} else {
x = 0.5f - (p_at_reset - b) / b1;
- if (w > 0)
+ if (sw > 0)
{
if (p_at_reset >= 1.0f) {
p_at_reset -= 1.0f;
x = -0.5f + p_at_reset / b;
- place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f / b + 1.0f / b1);
k = 0;
}
if (!k && p_at_reset >= b) {
x = 0.5f - (p_at_reset - b) / b1;
- place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, sw, -1.0f / b1 - 1.0f / b);
k = 1;
}
}
- else
+ else if (sw < 0)
{
if (p_at_reset < b) {
x = -0.5f + p_at_reset / b;
- place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -sw, -1.0f / b1 - 1.0f / b);
k = 0;
}
if (p_at_reset < 0.0f) {
p_at_reset += 1.0f;
x = 0.5f - (p_at_reset - b) / b1;
- place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, 1.0f / b + 1.0f / b1);
k = 1;
}
}
@@ -1759,69 +1696,60 @@
}
/* now place reset DDs */
- if (w > 0)
+ if (sw > 0)
{
if (k)
- place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
- place_step_dd(c->_f, j, p, w, -0.5f - x);
+ place_slope_dd(c->_f, j, p, sw, 1.0f / b + 1.0f / b1);
+ place_step_dd(c->_f, j, p, sw, -0.5f - x);
x = -0.5f + p / b;
k = 0;
if (p >= b) {
x = 0.5f - (p - b) / b1;
- place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, p - b, sw, -1.0f / b1 - 1.0f / b);
k = 1;
}
}
- else
+ else if (sw < 0)
{
if (!k)
- place_slope_dd(c->_f, j, 1.0f - p, -w, 1.0f / b + 1.0f / b1);
- place_step_dd(c->_f, j, 1.0f - p, -w, -0.5f - x);
+ place_slope_dd(c->_f, j, 1.0f - p, -sw, 1.0f / b + 1.0f / b1);
+ place_step_dd(c->_f, j, 1.0f - p, -sw, -0.5f - x);
x = 0.5f - (p - b) / b1;
k = 1;
if (p < b) {
x = -0.5f + p / b;
- place_slope_dd(c->_f, j, b - p, -w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, b - p, -sw, -1.0f / b1 - 1.0f / b);
k = 0;
}
}
-
- c->syncout = syncin; /* best we can do is pass on upstream sync */
-
} else if (!k) { /* normal operation, slope currently up */
x = -0.5f + p / b;
- if (w > 0)
+ if (sw > 0)
{
if (p >= b) {
x = 0.5f - (p - b) / b1;
- place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, p - b, sw, -1.0f / b1 - 1.0f / b);
k = 1;
}
if (p >= 1.0f) {
p -= 1.0f;
- c->syncout = p / w + 1e-20f;
x = -0.5f + p / b;
- place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, p, sw, 1.0f / b + 1.0f / b1);
k = 0;
- } else {
- c->syncout = 0.0f;
}
}
- else
+ else if (sw < 0)
{
if (p < 0.0f) {
p += 1.0f;
- c->syncout = (1.0f - p) / -w + 1e-20f;
x = 0.5f - (p - b) / b1;
- place_slope_dd(c->_f, j, 1.0f - p, -w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, 1.0f - p, -sw, 1.0f / b + 1.0f / b1);
k = 1;
- } else {
- c->syncout = 0.0f;
}
if (k && p < b) {
x = -0.5f + p / b;
- place_slope_dd(c->_f, j, b - p, -w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, b - p, -sw, -1.0f / b1 - 1.0f / b);
k = 0;
}
}
@@ -1829,38 +1757,32 @@
} else { /* normal operation, slope currently down */
x = 0.5f - (p - b) / b1;
- if (w > 0)
+ if (sw > 0)
{
if (p >= 1.0f) {
p -= 1.0f;
- c->syncout = p / w + 1e-20f;
x = -0.5f + p / b;
- place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, p, sw, 1.0f / b + 1.0f / b1);
k = 0;
- } else {
- c->syncout = 0.0f;
}
if (!k && p >= b) {
x = 0.5f - (p - b) / b1;
- place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, p - b, sw, -1.0f / b1 - 1.0f / b);
k = 1;
}
}
- else
+ else if (sw < 0)
{
if (p < b) {
x = -0.5f + p / b;
- place_slope_dd(c->_f, j, b - p, -w, -1.0f / b1 - 1.0f / b);
+ place_slope_dd(c->_f, j, b - p, -sw, -1.0f / b1 - 1.0f / b);
k = 0;
}
if (p < 0.0f) {
p += 1.0f;
- c->syncout = (1.0f - p) / -w + 1e-20f;
x = 0.5f - (p - b) / b1;
- place_slope_dd(c->_f, j, 1.0f - p, -w, 1.0f / b + 1.0f / b1);
+ place_slope_dd(c->_f, j, 1.0f - p, -sw, 1.0f / b + 1.0f / b1);
k = 1;
- } else {
- c->syncout = 0.0f;
}
}
}
@@ -1898,21 +1820,31 @@
c->waveform = w;
}
-void tMBTriangle_syncIn(tMBTriangle* const osc, float sync)
+float tMBTriangle_sync(tMBTriangle* const osc, float value)
{
_tMBTriangle* c = *osc;
- c->syncin = sync;
+
+ //based on https://github.com/VCVRack/Fundamental/blob/5799ee2a9b21492b42ebcb9b65d5395ef5c1cbe2/src/VCO.cpp#L123
+ float last = c->lastsyncin;
+ float delta = value - last;
+ float crossing = -last / delta;
+ c->lastsyncin = value;
+ if ((0.f < crossing) && (crossing <= 1.f) && (value >= 0.f))
+ c->sync = (1.f - crossing) * delta;
+ else c->sync = 0.f;
+
+ return value;
}
-float tMBTriangle_syncOut(tMBTriangle* const osc)
+void tMBTriangle_setSyncMode(tMBTriangle* const osc, int hardOrSoft)
{
_tMBTriangle* c = *osc;
- return c->syncout;
+ c->softsync = hardOrSoft > 0 ? 1 : 0;
}
+//==========================================================================================================
+//==========================================================================================================
-//----------------------------------------------------------------------------------------------------------
-
void tMBSaw_init(tMBSaw* const osc, LEAF* const leaf)
{
tMBSaw_initToPool(osc, &leaf->mempool);
@@ -1927,7 +1859,10 @@
c->_init = true;
c->amp = 1.0f;
c->freq = 440.f;
- c->syncin = 0.0f;
+ c->lastsyncin = 0.0f;
+ c->sync = 0.0f;
+ c->syncdir = 1.0f;
+ c->softsync = 0;
c->_z = 0.0f;
c->_j = 0;
memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
@@ -1945,9 +1880,10 @@
LEAF* leaf = c->mempool->leaf;
int j;
- float freq, syncin;
- float a, p, t, w, dw, z;
- syncin = c->syncin;
+ float freq, sync;
+ float a, p, w, sw, z;
+
+ sync = c->sync;
freq = c->freq;
p = c->_p; /* phase [0, 1) */
@@ -1957,19 +1893,8 @@
if (c->_init) {
p = 0.5f;
- w = freq / leaf->sampleRate;
+ w = freq * leaf->invSampleRate;
- if (w >= 0)
- {
- if (w < 1e-5f) w = 1e-5f;
- if (w > 0.5f) w = 0.5f;
- }
- else
- {
- if (w > -1e-5f) w = -1e-5f;
- if (w < -0.5f) w = -0.5f;
- }
-
/* if we valued alias-free startup over low startup time, we could do:
* p -= w;
* place_slope_dd(_f, j, 0.0f, w, -1.0f); */
@@ -1979,63 +1904,55 @@
//a = 0.2 + 0.8 * vco->_port [FILT];
a = 0.5f; // when a = 1, LPfilter is disabled
- t = freq / leaf->sampleRate;
+ w = freq * leaf->invSampleRate;
- if (t >= 0)
- {
- if (t < 1e-5f) t = 1e-5f;
- if (t > 0.5f) t = 0.5f;
- }
- else
- {
- if (t > -1e-5f) t = -1e-5f;
- if (t < -0.5f) t = -0.5f;
- }
+ if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
+ // Should insert minblep for softsync?
+ // if (p_at_reset >= 1.0f) {
+ // p_at_reset -= (int)p_at_reset;
+ // place_slope_dd(c->_f, j, p_at_reset + eof_offset, sw, 2.0f);
+ // }
+ // if (p_at_reset < 0.0f) {
+ // p_at_reset += 1.0f - (int)p_at_reset;
+ // place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -2.0f);
+ // }
+ // if (sw > 0) place_slope_dd(c->_f, j, p, sw, 2.0f);
+ // else if (sw < 0) place_slope_dd(c->_f, j, 1.0f - p, -sw, -2.0f);
- dw = (t - w); // n= 1
- w += dw;
- p += w;
+ sw = w * c->syncdir;
+ p += sw - (int)sw;
- if (syncin >= 1e-20f) { /* sync to master */
-
- float eof_offset = (syncin - 1e-20f) * w;
+ if (sync > 0.0f && c->softsync == 0) { /* sync to master */
+ float eof_offset = sync * sw;
float p_at_reset = p - eof_offset;
+
+ if (sw > 0) p = eof_offset;
+ else if (sw < 0) p = 1.0f - eof_offset;
- if (w > 0) p = eof_offset;
- else p = 1.0f - eof_offset;
-
/* place any DD that may have occurred in subsample before reset */
if (p_at_reset >= 1.0f) {
p_at_reset -= 1.0f;
- place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
+ place_step_dd(c->_f, j, p_at_reset + eof_offset, sw, 1.0f);
}
if (p_at_reset < 0.0f) {
p_at_reset += 1.0f;
- place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -sw, -1.0f);
}
/* now place reset DD */
- if (w > 0)
- place_step_dd(c->_f, j, p, w, p_at_reset);
- else
- place_step_dd(c->_f, j, 1.0f - p, -w, -p_at_reset);
-
- c->syncout = syncin; /* best we can do is pass on upstream sync */
-
+ if (sw > 0)
+ place_step_dd(c->_f, j, p, sw, p_at_reset);
+ else if (sw < 0)
+ place_step_dd(c->_f, j, 1.0f - p, -sw, -p_at_reset);
+
} else if (p >= 1.0f) { /* normal phase reset */
-
p -= 1.0f;
- c->syncout = p / w + 1e-20f;
- place_step_dd(c->_f, j, p, w, 1.0f);
+ place_step_dd(c->_f, j, p, sw, 1.0f);
} else if (p < 0.0f) {
p += 1.0f;
- c->syncout = (1.0f - p) / -w + 1e-20f;
- place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+ place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
}
- else {
- c->syncout = 0.0f;
- }
c->_f[j + DD_SAMPLE_DELAY] += 0.5f - p;
z += a * (c->_f[j] - z); // LP filtering
@@ -2062,14 +1979,24 @@
c->freq = f;
}
-void tMBSaw_syncIn(tMBSaw* const osc, float sync)
+float tMBSaw_sync(tMBSaw* const osc, float value)
{
_tMBSaw* c = *osc;
- c->syncin = sync;
+
+ //based on https://github.com/VCVRack/Fundamental/blob/5799ee2a9b21492b42ebcb9b65d5395ef5c1cbe2/src/VCO.cpp#L123
+ float last = c->lastsyncin;
+ float delta = value - last;
+ float crossing = -last / delta;
+ c->lastsyncin = value;
+ if ((0.f < crossing) && (crossing <= 1.f) && (value >= 0.f))
+ c->sync = (1.f - crossing) * delta;
+ else c->sync = 0.f;
+
+ return value;
}
-float tMBSaw_syncOut(tMBSaw* const osc)
+void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft)
{
_tMBSaw* c = *osc;
- return c->syncout;
+ c->softsync = hardOrSoft > 0 ? 1 : 0;
}