ref: 96b6a59a61f0a4203e9c5720f378f45ad7d616fd
parent: 3c8c5ec4983d71b56b8c1f969c4aa7eb87ada9cd
author: Jeffrey Snyder <jeffsnyder@jeffreys-mbp.mynetworksettings.com>
date: Thu Dec 1 09:10:23 EST 2022
testing string simulations
--- a/TestPlugin/LEAF.jucer
+++ b/TestPlugin/LEAF.jucer
@@ -10,7 +10,7 @@
pluginRTASCategory="" aaxIdentifier="com.pumusic.LEAF" pluginAAXCategory="2"
companyName="Princeton University" companyEmail="mrmulshine@gmail.com"
displaySplashScreen="1" reportAppUsage="1" splashScreenColour="Dark"
- buildStandalone="1" enableIAA="0" cppLanguageStandard="11" companyCopyright="Princeton University"
+ buildStandalone="1" enableIAA="0" companyCopyright="Princeton University"
pluginFormats="buildAU,buildStandalone" pluginCharacteristicsValue="pluginWantsMidiIn"
jucerFormatVersion="1">
<MAINGROUP id="F7Bywq" name="LEAF">
--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -14,100 +14,27 @@
static void run_pool_test(void);
tMBSaw bsaw;
-tMBTriangle btri;
-tMBPulse bpulse;
-tPhasor phasor;
-
-tSVF lp, hp;
-
-tPeriodDetection pd;
-
-tZeroCrossingCounter zc;
-tEnvelopeFollower ef;
-
-tTriangle tri;
-
-tNoise noise;
-tButterworth bw;
-
-tWaveTable wt;
-tWaveTableS cwt;
-tWaveOsc ws;
-
-tBuffer samp;
-tMBSampler sampler;
-
-const int numWavetables = 4;
-tWaveTable wavetables[numWavetables];
-tSimpleRetune retune;
-
-float gain;
-float dtime;
-bool buttonState;
-int ratio = 2;
-float x = 0.0f;
-float y = 0.0f;
-float a, b, c, d;
-
-float* bufIn;
-float* bufOut;
-
LEAF leaf;
#define MSIZE 2048000
char memory[MSIZE];
-int lastLoadedAudioSize = 0;
void LEAFTest_init (float sampleRate, int blockSize)
{
LEAF_init(&leaf, sampleRate, memory, MSIZE, &getRandomFloat);
-
- tSimpleRetune_init(&retune, 1, 100, 1200, 2048, &leaf);
- tSimpleRetune_setMode(&retune, 1);
-
-// tWaveTable_init(&wt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
-// tWaveTableS_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);
-
- tWaveTable_init(&wavetables[0], (float*)__leaf_table_sinewave, 2048, 20000.f, &leaf);
- tWaveTable_init(&wavetables[1], (float*)__leaf_table_triangle, 2048, 20000.f, &leaf);
- tWaveTable_init(&wavetables[2], (float*)__leaf_table_squarewave, 2048, 20000.f, &leaf);
- tWaveTable_init(&wavetables[3], (float*)__leaf_table_sawtooth, 2048, 20000.f, &leaf);
-
- tWaveOsc_init(&ws, wavetables, numWavetables, &leaf);
-
- lastLoadedAudioSize = 0;
- loadedAudio.clear();
+ //tMBSaw_setSyncMode(&bsaw, 1);
}
-inline double getSawFall(double angle) {
-
- angle = fmod(angle + double_Pi, 2*double_Pi); // shift x
- double sample = angle/double_Pi - double(1); // computer as remainder
-
- return sample;
-
-}
+
float LEAFTest_tick (float input)
{
float out = tMBSaw_tick(&bsaw);
-// for (int i = 0; i < numWavetables; ++i)
-// {
-// out += tWaveOsc_tick(&ws);
-// }
return out;
}
@@ -116,31 +43,11 @@
void LEAFTest_block (void)
{
float val = getSliderValue("slider1");
- tMBTriangle_setFreq(&btri, val * 440.f);
- tMBPulse_setFreq(&bpulse, val * 160000.f - 80000.0f);
tMBSaw_setFreq(&bsaw, -val * 2000.f + 1000.0f);
-// tWaveTable_setFreq(&wt, val * 160000.f - 80000.0f);
-// tWaveTableS_setFreq(&cwt, val * 10000.);
- tWaveOsc_setFreq(&ws, val * 2000.f);
-// tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
-// tSimpleRetune_tuneVoice(&sretune, 0, 300);
val = getSliderValue("slider2");
- tWaveOsc_setIndex(&ws, val);
-// tRetune_setPitchFactor(&retune, val * 3.0f + 0.5f, 1);
val = getSliderValue("slider3");
-// tRetune_setPitchFactor(&retune, val * 3.0f + 0.5f, 2);
-
- if (lastLoadedAudioSize < loadedAudio.size())
- {
- int i = (loadedAudio.size() - 1) % numWavetables;
- if (loadedAudio.size() - 1 >= numWavetables) tWaveTable_free(&wavetables[i]);
- tWaveTable_init(&wavetables[i], (float*)loadedAudio[loadedAudio.size() - 1].getReadPointer(0), loadedAudio[loadedAudio.size() - 1].getNumSamples(), 20000, &leaf);
-
- lastLoadedAudioSize = loadedAudio.size();
- }
-// if (loadedAudio.size() > 0) tWaveTable_setFreq(&wavetables[0], 220);//val * 10000.f);
}
void LEAFTest_controllerInput (int cnum, float cval)
--- a/TestPlugin/Source/UIComponent.cpp
+++ b/TestPlugin/Source/UIComponent.cpp
@@ -163,7 +163,7 @@
{
juce::FileChooser chooser ("Select a Wave file to play...", {}, "*.wav");
- if (chooser.browseForFileToOpen())
+ /*if (chooser.browseForFileToOpen())
{
auto file = chooser.getResult();
auto* reader = formatManager.createReaderFor (file);
@@ -177,5 +177,6 @@
loadedAudio.add(buffer);
}
}
+ */
}
}
--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -873,8 +873,14 @@
float syncdir;
int softsync;
float _p, _w, _z;
+ float _inv_w;
int _j;
- float _f [FILLEN + STEP_DD_PULSE_LENGTH];
+ float _f[8];
+ uint16_t numBLEPs;
+ uint16_t mostRecentBLEP;
+ uint16_t maxBLEPphase;
+ uint16_t BLEPindices[64];
+ float BLEPproperties[64][2];
float invSampleRate;
} _tMBSaw;
@@ -883,7 +889,6 @@
void tMBSaw_init(tMBSaw* const osc, LEAF* const leaf);
void tMBSaw_initToPool(tMBSaw* const osc, tMempool* const mempool);
void tMBSaw_free(tMBSaw* const osc);
-
float tMBSaw_tick(tMBSaw* const osc);
void tMBSaw_setFreq(tMBSaw* const osc, float f);
float tMBSaw_sync(tMBSaw* const osc, float sync);
@@ -891,7 +896,13 @@
void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft);
void tMBSaw_setBufferOffset(tMBSaw* const osc, uint32_t offset);
void tMBSaw_setSampleRate (tMBSaw* const osc, float sr);
-
+#ifdef ITCMRAM
+ void __attribute__ ((section(".itcmram"))) __attribute__ ((aligned (32))) tMBSaw_place_step_dd_noBuffer(tMBSaw* const osc, int index, float phase, float w, float scale);
+#else
+ void tMBSaw_place_step_dd_noBuffer(tMBSaw* const osc, int index, float phase, float w, float scale);
+#endif
+
+
//==============================================================================
/*!
@defgroup tmbsaw tMBSawPulse
@@ -958,7 +969,6 @@
float tMBSawPulse_tick(tMBSawPulse* const osc);
- float tMBSawPulse_sync(tMBSawPulse* const osc, float value);
void tMBSawPulse_setFreq(tMBSawPulse* const osc, float f);
float tMBSawPulse_sync(tMBSawPulse* const osc, float sync);
void tMBSawPulse_setPhase(tMBSawPulse* const osc, float phase);
--- a/leaf/Inc/leaf-physical.h
+++ b/leaf/Inc/leaf-physical.h
@@ -339,6 +339,55 @@
+
+typedef struct _tSimpleLivingString3
+{
+
+ tMempool mempool;
+ float freq, waveLengthInSamples; // the frequency of the string, determining delay length
+ float dampFreq; // frequency for the bridge LP filter, in Hz
+ float decay; // amplitude damping factor for the string (only active in mode 0)
+ int levMode;
+ float curr;
+ float Uout;
+ float Lout;
+ tLinearDelay delayLineU;
+ tLinearDelay delayLineL;
+ tOnePole bridgeFilter;
+ tHighpass DCblocker;
+ tFeedbackLeveler fbLev;
+ tExpSmooth wlSmooth;
+ float sampleRate;
+} _tSimpleLivingString3;
+
+typedef _tSimpleLivingString3* tSimpleLivingString3;
+
+void tSimpleLivingString3_init (tSimpleLivingString3* const, float freq, float dampFreq,
+ float decay, float targetLev, float levSmoothFactor,
+ float levStrength, int levMode, LEAF* const leaf);
+void tSimpleLivingString3_initToPool (tSimpleLivingString3* const, float freq, float dampFreq,
+ float decay, float targetLev, float levSmoothFactor,
+ float levStrength, int levMode, tMempool* const);
+void tSimpleLivingString3_free (tSimpleLivingString3* const);
+
+float tSimpleLivingString3_pluck (tSimpleLivingString3* const pl, float input, float position);
+float tSimpleLivingString3_tick (tSimpleLivingString3* const, float input);
+float tSimpleLivingString3_sample (tSimpleLivingString3* const);
+void tSimpleLivingString3_setFreq (tSimpleLivingString3* const, float freq);
+void tSimpleLivingString3_setWaveLength (tSimpleLivingString3* const, float waveLength); // in samples
+void tSimpleLivingString3_setDampFreq (tSimpleLivingString3* const, float dampFreq);
+void tSimpleLivingString3_setDecay (tSimpleLivingString3* const, float decay); // should be near 1.0
+void tSimpleLivingString3_setTargetLev (tSimpleLivingString3* const, float targetLev);
+void tSimpleLivingString3_setLevSmoothFactor (tSimpleLivingString3* const, float levSmoothFactor);
+void tSimpleLivingString3_setLevStrength (tSimpleLivingString3* const, float levStrength);
+void tSimpleLivingString3_setLevMode (tSimpleLivingString3* const, int levMode);
+void tSimpleLivingString3_setSampleRate (tSimpleLivingString3* const, float sr);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+
+
+
typedef struct _tSimpleLivingString2
{
--- a/leaf/Src/leaf-math.c
+++ b/leaf/Src/leaf-math.c
@@ -887,6 +887,10 @@
index++;
}
}
+
+
+
+
#ifdef ITCMRAM
void __attribute__ ((section(".itcmram"))) __attribute__ ((aligned (32))) place_slope_dd(float *buffer, int index, float phase, float w, float slope_delta)
#else
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -1289,7 +1289,7 @@
invB1 = 1.0f / b1;
if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
- sw = w * c->syncdir + c->quarterwaveoffset;
+ sw = w * c->syncdir;
p += sw - (int)sw;
if (sync > 0.0f && c->softsync == 0) { /* sync to master */
@@ -1481,7 +1481,7 @@
_tMBTriangle* c = *osc;
c->freq = f;
c->_w = c->freq * c->invSampleRate; /* phase increment */
- c->quarterwaveoffset = c->_w * 0.25f;
+ //c->quarterwaveoffset = c->_w * 0.25f;
}
void tMBTriangle_setWidth(tMBTriangle* const osc, float w)
@@ -1558,8 +1558,12 @@
c->_j = 0;
c->_p = 0.0f; /* phase [0, 1) */
c->_w = c->freq * c->invSampleRate; /* phase increment */
-
- memset (c->_f, 0, (FILLEN + STEP_DD_PULSE_LENGTH) * sizeof (float));
+ c->_inv_w = 1.0f / c->_w;
+ c->numBLEPs = 0;
+ c->mostRecentBLEP = 0;
+ c->maxBLEPphase = MINBLEP_PHASES * STEP_DD_PULSE_LENGTH;
+ memset (c->BLEPindices, 0, 64 * sizeof (uint16_t));
+ memset (c->_f, 0, 8 * sizeof (float));
}
void tMBSaw_free(tMBSaw* const osc)
@@ -1568,39 +1572,65 @@
mpool_free((char*)c, c->mempool);
}
+
+#ifdef ITCMRAM
+void __attribute__ ((section(".itcmram"))) __attribute__ ((aligned (32))) tMBSaw_place_step_dd_noBuffer(tMBSaw* const osc, int index, float phase, float inv_w, float scale)
+#else
+void tMBSaw_place_step_dd_noBuffer(tMBSaw* const osc, int index, float phase, float inv_w, float scale)
+#endif
+{
+ _tMBSaw* c = *osc;
+ float r;
+ long i;
+
+ r = MINBLEP_PHASES * phase * inv_w;
+ i = lrintf(r - 0.5f);
+ r -= (float)i;
+ i &= MINBLEP_PHASE_MASK; /* extreme modulation can cause i to be out-of-range */
+ c->mostRecentBLEP = (c->mostRecentBLEP + 1) & 63;
+ c->BLEPindices[c->mostRecentBLEP] = i;
+ c->BLEPproperties[c->mostRecentBLEP][0] = r;
+ c->BLEPproperties[c->mostRecentBLEP][1] = scale;
+ c->numBLEPs = (c->numBLEPs + 1) & 63;
+}
+
+
+
float tMBSaw_tick(tMBSaw* const osc)
{
_tMBSaw* c = *osc;
-
+
int j;
float sync;
- float p, w, sw, z;
-
+ float p, sw, z;
+
sync = c->sync;
-
+
p = c->_p; /* phase [0, 1) */
- w = c->_w; /* phase increment */
z = c->_z; /* low pass filter state */
j = c->_j; /* index into buffer _f */
if (sync > 0.0f && c->softsync > 0) c->syncdir = -c->syncdir;
+ sw = c->_w * c->syncdir;
+ float inv_sw = c->_inv_w * c->syncdir;
+ p += sw - (int)sw;
+
+ //if (sync > 0.0f && c->softsync > 0) {
// 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);
+ // place_slope_dd(osc, j, p_at_reset + eof_offset, inv_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);
+ // place_slope_dd(osc, j, 1.0f - p_at_reset - eof_offset, -inv_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);
-
- sw = w * c->syncdir;
- p += sw - (int)sw;
-
+ // if (sw > 0) place_slope_dd(osc, j, p, inv_sw, 2.0f);
+ // else if (sw < 0) place_slope_dd(osc, j, 1.0f - p, -inv_sw, -2.0f);
+ //}
+
if (sync > 0.0f && c->softsync == 0) { /* sync to master */
float eof_offset = sync * sw;
float p_at_reset = p - eof_offset;
@@ -1607,48 +1637,66 @@
if (sw > 0) p = eof_offset;
else if (sw < 0) 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, sw, 1.0f);
+ tMBSaw_place_step_dd_noBuffer(osc, j, p_at_reset + eof_offset, inv_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, -sw, -1.0f);
+ tMBSaw_place_step_dd_noBuffer(osc, j, 1.0f - p_at_reset - eof_offset, -inv_sw, -1.0f);
}
-
+
/* now place reset DD */
if (sw > 0)
- place_step_dd(c->_f, j, p, sw, p_at_reset);
+ tMBSaw_place_step_dd_noBuffer(osc, j, p, inv_sw, p_at_reset);
else if (sw < 0)
- place_step_dd(c->_f, j, 1.0f - p, -sw, -p_at_reset);
+ tMBSaw_place_step_dd_noBuffer(osc, j, 1.0f - p, -inv_sw, -p_at_reset);
} else if (p >= 1.0f) { /* normal phase reset */
p -= 1.0f;
- place_step_dd(c->_f, j, p, sw, 1.0f);
-
+ tMBSaw_place_step_dd_noBuffer(osc, j, p, inv_sw, 1.0f);
+
} else if (p < 0.0f) {
p += 1.0f;
- place_step_dd(c->_f, j, 1.0f - p, -sw, -1.0f);
+ tMBSaw_place_step_dd_noBuffer(osc, j, 1.0f - p, -inv_sw, -1.0f);
}
- c->_f[j + DD_SAMPLE_DELAY] += 0.5f - p;
-
- z += 0.5f * (c->_f[j] - z); // LP filtering
- c->out = z;
-
- if (++j == FILLEN)
+
+ //construct the current output sample based on the state of the active BLEPs
+
+ int currentSamp = (j + DD_SAMPLE_DELAY) & 7;
+
+ c->_f[currentSamp] = 0.5f - p;
+
+ volatile uint8_t numBLEPsAtLoopStart = c->numBLEPs;
+ for (int i = 0; i < numBLEPsAtLoopStart; i++)
{
- 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));
+ volatile uint16_t whichBLEP = (c->mostRecentBLEP - i);
+ whichBLEP &= 63;
+
+ //use the scale and r values from the BLEPproperties array to compute the current state of each active BLEP and add it to the output value
+ c->_f[j] += c->BLEPproperties[whichBLEP][1] * (step_dd_table[c->BLEPindices[whichBLEP]].value + c->BLEPproperties[whichBLEP][0] * step_dd_table[c->BLEPindices[whichBLEP]].delta);
+
+ //increment the position in the BLEP table
+ c->BLEPindices[whichBLEP] += MINBLEP_PHASES;
+ //check if this BLEP is finished and if so mark it as inactive so it isn't computed anymore.
+ if (c->BLEPindices[whichBLEP] >= c->maxBLEPphase)
+ {
+ c->numBLEPs--;
+ }
+
}
-
+
+ z += 0.5f * (c->_f[j] - z); // LP filtering
+ c->out = z;
+ j = (j+1) & 7; //don't need 128 sample buffer just for lowpass, so only using the first 16 values before wrapping around (probably only need 4 or 8)
+
c->_p = p;
- c->_w = w;
c->_z = z;
c->_j = j;
-
+
+
return -c->out;
}
@@ -1658,6 +1706,7 @@
c->freq = f;
c->_w = c->freq * c->invSampleRate;
+ c->_inv_w = 1.0f / c->_w;
}
float tMBSaw_sync(tMBSaw* const osc, float value)
--- a/leaf/Src/leaf-physical.c
+++ b/leaf/Src/leaf-physical.c
@@ -499,7 +499,188 @@
}
+/* Simple Living String*/
+void tSimpleLivingString3_init(tSimpleLivingString3* const pl, float freq, float dampFreq,
+ float decay, float targetLev, float levSmoothFactor,
+ float levStrength, int levMode, LEAF* const leaf)
+{
+ tSimpleLivingString3_initToPool(pl, freq, dampFreq, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf->mempool);
+}
+
+void tSimpleLivingString3_initToPool (tSimpleLivingString3* const pl, float freq, float dampFreq,
+ float decay, float targetLev, float levSmoothFactor,
+ float levStrength, int levMode, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tSimpleLivingString3* p = *pl = (_tSimpleLivingString3*) mpool_alloc(sizeof(_tSimpleLivingString3), m);
+ p->mempool = m;
+ LEAF* leaf = p->mempool->leaf;
+
+ p->sampleRate = leaf->sampleRate;
+ p->curr=0.0f;
+ tExpSmooth_initToPool(&p->wlSmooth, p->sampleRate/freq/2.0f, 0.01f, mp); // smoother for string wavelength (not freq, to avoid expensive divisions)
+ tLinearDelay_initToPool(&p->delayLineU,p->waveLengthInSamples, 2400, mp);
+ tLinearDelay_initToPool(&p->delayLineL,p->waveLengthInSamples, 2400, mp);
+ tSimpleLivingString3_setFreq(pl, freq);
+ tLinearDelay_setDelay(&p->delayLineU, p->waveLengthInSamples);
+ tLinearDelay_setDelay(&p->delayLineL, p->waveLengthInSamples);
+ //tSimpleLivingString3_setWaveLength(pl, 4800);
+ tLinearDelay_clear(&p->delayLineU);
+ tLinearDelay_clear(&p->delayLineL);
+ p->dampFreq = dampFreq;
+ p->freq = freq;
+ tOnePole_initToPool(&p->bridgeFilter, dampFreq, mp);
+ tHighpass_initToPool(&p->DCblocker,13, mp);
+ p->decay=decay;
+ tFeedbackLeveler_initToPool(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode, mp);
+ p->levMode=levMode;
+}
+
+void tSimpleLivingString3_free (tSimpleLivingString3* const pl)
+{
+ _tSimpleLivingString3* p = *pl;
+
+ tExpSmooth_free(&p->wlSmooth);
+ tLinearDelay_free(&p->delayLineU);
+ tLinearDelay_free(&p->delayLineL);
+ tOnePole_free(&p->bridgeFilter);
+ tHighpass_free(&p->DCblocker);
+ tFeedbackLeveler_free(&p->fbLev);
+
+ mpool_free((char*)p, p->mempool);
+}
+
+void tSimpleLivingString3_setFreq(tSimpleLivingString3* const pl, float freq)
+{
+ _tSimpleLivingString3* p = *pl;
+
+ if (freq<20) freq=20;
+ else if (freq>10000) freq=10000;
+ p->waveLengthInSamples = (p->sampleRate/freq) * 0.5f;
+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+}
+
+void tSimpleLivingString3_setWaveLength(tSimpleLivingString3* const pl, float waveLength)
+{
+ _tSimpleLivingString3* p = *pl;
+
+ if (waveLength<4.8) waveLength=4.8f;
+ else if (waveLength>4800) waveLength=4800;
+ p->waveLengthInSamples = waveLength * 0.5f;
+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+}
+
+void tSimpleLivingString3_setDampFreq(tSimpleLivingString3* const pl, float dampFreq)
+{
+ _tSimpleLivingString3* p = *pl;
+ tOnePole_setFreq(&p->bridgeFilter, dampFreq);
+}
+
+void tSimpleLivingString3_setDecay(tSimpleLivingString3* const pl, float decay)
+{
+ _tSimpleLivingString3* p = *pl;
+ p->decay=decay;
+}
+
+void tSimpleLivingString3_setTargetLev(tSimpleLivingString3* const pl, float targetLev)
+{
+ _tSimpleLivingString3* p = *pl;
+ tFeedbackLeveler_setTargetLevel(&p->fbLev, targetLev);
+}
+
+void tSimpleLivingString3_setLevSmoothFactor(tSimpleLivingString3* const pl, float levSmoothFactor)
+{
+ _tSimpleLivingString3* p = *pl;
+ tFeedbackLeveler_setFactor(&p->fbLev, levSmoothFactor);
+}
+
+void tSimpleLivingString3_setLevStrength(tSimpleLivingString3* const pl, float levStrength)
+{
+ _tSimpleLivingString3* p = *pl;
+ tFeedbackLeveler_setStrength(&p->fbLev, levStrength);
+}
+
+void tSimpleLivingString3_setLevMode(tSimpleLivingString3* const pl, int levMode)
+{
+ _tSimpleLivingString3* p = *pl;
+ tFeedbackLeveler_setMode(&p->fbLev, levMode);
+ p->levMode=levMode;
+}
+
+float tSimpleLivingString3_pluck(tSimpleLivingString3* const pl, float input, float position)
+{
+ _tSimpleLivingString3* p = *pl;
+ int length = p->waveLengthInSamples;
+ int pluckPoint = (int)(length * position);
+ int remainder = length-pluckPoint;
+ for (int i = 0; i < length; i++)
+ {
+ float val = 0.0f;
+ if (i <= pluckPoint)
+ {
+ val = input * ((float)i/(float)pluckPoint);
+ }
+ else
+ {
+ val = input * (1.0f - (((float)i-(float)pluckPoint)/(float)remainder));
+
+ }
+ int bufWritePoint = (i+p->delayLineU->outPoint)%p->delayLineU->maxDelay;
+ p->delayLineU->buff[bufWritePoint] = val;
+ }
+ for (int i = 0; i < length; i++)
+ {
+ int currentBufWritePoint = (i+p->delayLineL->outPoint) % p->delayLineL->maxDelay;
+ int currentBufReadPoint = ((length-i)+p->delayLineU->outPoint);
+ int currentBufReadPointMod = currentBufReadPoint % p->delayLineU->maxDelay;
+ p->delayLineL->buff[currentBufWritePoint] = p->delayLineU->buff[currentBufReadPointMod];
+ }
+
+}
+
+float tSimpleLivingString3_tick(tSimpleLivingString3* const pl, float input)
+{
+ _tSimpleLivingString3* p = *pl;
+ tLinearDelay_setDelay(&p->delayLineU, tExpSmooth_tick(&p->wlSmooth));
+ tLinearDelay_setDelay(&p->delayLineL, tExpSmooth_tick(&p->wlSmooth));
+ //tLinearDelay_setDelay(&p->delayLineU, p->waveLengthInSamples);
+ //tLinearDelay_setDelay(&p->delayLineL, p->waveLengthInSamples);
+
+ p->Uout = tOnePole_tick(&p->bridgeFilter,tLinearDelay_tickOut(&p->delayLineU));
+ p->Lout = tLinearDelay_tickOut(&p->delayLineL);
+
+ tLinearDelay_tickIn(&p->delayLineU, -1.0f * p->Lout);
+ tLinearDelay_tickIn(&p->delayLineL, -1.0f * p->Uout);
+
+
+ //float stringInput=tHighpass_tick(&p->DCblocker, tFeedbackLeveler_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input));
+ //tLinearDelay_tickIn(&p->delayLine, stringInput);
+ //tLinearDelay_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth));
+ //p->curr = d1 + d2;
+ return p->curr;
+}
+
+float tSimpleLivingString3_sample(tSimpleLivingString3* const pl)
+{
+ _tSimpleLivingString3* p = *pl;
+ return p->curr;
+}
+
+void tSimpleLivingString3_setSampleRate(tSimpleLivingString3* const pl, float sr)
+{
+ _tSimpleLivingString3* p = *pl;
+ float freq = p->sampleRate/p->waveLengthInSamples;
+ p->sampleRate = sr;
+ p->waveLengthInSamples = p->sampleRate/freq;
+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+ tOnePole_setSampleRate(&p->bridgeFilter, p->sampleRate);
+ tHighpass_setSampleRate(&p->DCblocker, p->sampleRate);
+}
+
+
+
+
/* Simple Living String*/
void tSimpleLivingString2_init(tSimpleLivingString2* const pl, float freq, float brightness,
@@ -568,8 +749,8 @@
void tSimpleLivingString2_setBrightness(tSimpleLivingString2* const pl, float brightness)
{
_tSimpleLivingString2* p = *pl;
- float h0=(1.0 + brightness) * 0.5f;
- float h1=(1.0 - brightness) * 0.25f;
+ float h0 = (1.0f + brightness) * 0.5f;
+ float h1 = (1.0f - brightness) * 0.25f;
tTwoZero_setCoefficients(&p->bridgeFilter, h1, h0, h1);
}