History

added tLivingString2 and changed tHermiteDelay to use only power of 2 buffer sizes and do an integer mask to avoid modulo operators

spiricom committed 5 years ago

Commit debdbb41 parent a1615ef5 files · +514 −56Browse files

Unified · Split

5 files
  1. leaf/Inc/leaf-delay.h +10 −3
  2. leaf/Inc/leaf-physical.h +126 −0
  3. leaf/Src/leaf-delay.c +74 −52
  4. leaf/Src/leaf-physical.c +303 −0
  5. leaf/leaf-config.h +1 −1
leaf/Inc/leaf-delay.h+10−3
@@ -317,6 +317,13 @@ extern "C" { · 316 unmodified lines
317317 @param position
318318 @return
319319
320+ @fn float tHermiteDelay_tapOutInterpolated (tHermiteDelay* const dl, uint32_t tapDelay, float alpha);
321+ @brief
322+ @param delay A pointer to the relevant tHermiteDelay.
323+ @param integer position
324+ @param fractional portion of the position
325+ @return
326+
320327 @fn void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)
321328 @brief
322329 @param delay A pointer to the relevant tHermiteDelay.
@@ -361,15 +368,14 @@ extern "C" { · 38 unmodified lines
361368 {
362369 tMempool mempool;
363370
364− float gain;
365371 float* buff;
366−
372+ uint32_t bufferMask;
367373 float lastOut, lastIn;
368374
369375 uint32_t inPoint, outPoint;
370376
371377 uint32_t maxDelay;
372−
378+ float gain;
373379 float delay;
374380
375381 float alpha, omAlpha;
@@ -387,6 +393,7 @@ extern "C" { · 11 unmodified lines
387393 float tHermiteDelay_tickOut (tHermiteDelay* const dl);
388394 void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay);
389395 float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay);
396+ float tHermiteDelay_tapOutInterpolated (tHermiteDelay* const dl, uint32_t tapDelay, float alpha);
390397 void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay);
391398 float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay);
392399 float tHermiteDelay_getDelay (tHermiteDelay* const dl);
leaf/Inc/leaf-physical.h+126−0
@@ -444,7 +444,133 @@ extern "C" { · 443 unmodified lines
444444 void tLivingString_setLevMode (tLivingString* const, int levMode);
445445
446446
447+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
448+
449+
450+ /*!
451+ @defgroup tlivingstring2 tLivingString2
452+ @ingroup physical
453+ @brief String model with preparation and pick position separated.
454+ @{
455+
456+ @fn void tLivingString2_init (tLivingString2* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode, LEAF* const leaf)
457+ @brief Initialize a tLivingString to the default mempool of a LEAF instance.
458+ @param string A pointer to the tLivingString2 to initialize.
459+ @param leaf A pointer to the leaf instance.
460+
461+ @fn void tLivingString2_initToPool (tLivingString2* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode, tMempool* const)
462+ @brief Initialize a tLivingString2 to a specified mempool.
463+ @param string A pointer to the tLivingString2 to initialize.
464+ @param mempool A pointer to the tMempool to use.
465+
466+ @fn void tLivingString2_free (tLivingString2* const)
467+ @brief Free a tLivingString2 from its mempool.
468+ @param string A pointer to the tLivingString2 to free.
469+
470+ @fn float tLivingString2_tick (tLivingString2* const, float input)
471+ @brief
472+ @param string A pointer to the relevant tLivingString2.
473+
474+ @fn float tLivingString2_sample (tLivingString2* const)
475+ @brief
476+ @param string A pointer to the relevant tLivingString2.
477+
478+ @fn void tLivingString2_setFreq (tLivingString2* const, float freq)
479+ @brief
480+ @param string A pointer to the relevant tLivingString2.
481+
482+ @fn void tLivingString2_setWaveLength (tLivingString2* const, float waveLength)
483+ @brief
484+ @param string A pointer to the relevant tLivingString2.
485+
486+ @fn void tLivingString2_setPickPos (tLivingString2* const, float pickPos)
487+ @brief
488+ @param string A pointer to the relevant tLivingString2.
489+
490+ @fn void tLivingString2_setPrepPosition (tLivingString2* const, float prepPos)
491+ @brief
492+ @param string A pointer to the relevant tLivingString2.
493+
494+
495+ @fn void tLivingString2_setPrepIndex (tLivingString2* const, float prepIndex)
496+ @brief
497+ @param string A pointer to the relevant tLivingString2.
498+
499+ @fn void tLivingString2_setBrightness (tLivingString2* const, float brightness)
500+ @brief
501+ @param string A pointer to the relevant tLivingString2.
502+ @param float The brightness parameter from 0 to 1.
503+
504+ @fn void tLivingString2_setDecay (tLivingString2* const, float decay)
505+ @brief
506+ @param string A pointer to the relevant tLivingString2.
507+ @param float The decay parameter from 0 to 1.
508+
509+ @fn void tLivingString2_setTargetLev (tLivingString2* const, float targetLev)
510+ @brief
511+ @param string A pointer to the relevant tLivingString2.
512+
513+ @fn void tLivingString2_setLevSmoothFactor (tLivingString2* const, float levSmoothFactor)
514+ @brief
515+ @param string A pointer to the relevant tLivingString2.
516+
517+ @fn void tLivingString2_setLevStrength (tLivingString2* const, float levStrength)
518+ @brief
519+ @param string A pointer to the relevant tLivingString2.
520+
521+ @fn void tLivingString2_setLevMode (tLivingString2* const, int levMode)
522+ @brief
523+ @param string A pointer to the relevant tLivingString2.
524+
525+ @} */
526+ typedef struct _tLivingString2
527+ {
528+
529+ tMempool mempool;
530+ float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length
531+ float pickPos; // the pick position, dividing the string in two, in ratio
532+ float prepPos; // the preparation position, dividing the string in two, in ratio
533+ float pickupPos; // the preparation position, dividing the string in two, in ratio
534+ float prepIndex; // the amount of pressure on the preparation position of the string (near 0=soft obj, near 1=hard obj)
535+ float decay; // amplitude damping factor for the string (only active in mode 0)
536+ int levMode;
537+ float brightness;
538+ float curr;
539+ tHermiteDelay delLF,delUF,delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model
540+ tTwoZero bridgeFilter, nutFilter, prepFilterU, prepFilterL;
541+ tHighpass DCblockerL, DCblockerU;
542+ tFeedbackLeveler fbLevU, fbLevL;
543+ tExpSmooth wlSmooth, ppSmooth, prpSmooth, puSmooth;
544+ } _tLivingString2;
545+
546+ typedef _tLivingString2* tLivingString2;
547+
548+ void tLivingString2_init (tLivingString2* const, float freq, float pickPos, float prepPos, float pickupPos, float prepIndex,
549+ float brightness, float decay, float targetLev, float levSmoothFactor,
550+ float levStrength, int levMode, LEAF* const leaf);
551+ void tLivingString2_initToPool (tLivingString2* const, float freq, float pickPos, float prepPos, float pickupPos, float prepIndex,
552+ float brightness, float decay, float targetLev, float levSmoothFactor,
553+ float levStrength, int levMode, tMempool* const);
554+ void tLivingString2_free (tLivingString2* const);
555+
556+ float tLivingString2_tick (tLivingString2* const, float input);
557+ float tLivingString2_sample (tLivingString2* const);
558+ void tLivingString2_setFreq (tLivingString2* const, float freq);
559+ void tLivingString2_setWaveLength (tLivingString2* const, float waveLength); // in samples
560+ void tLivingString2_setPickPos (tLivingString2* const, float pickPos);
561+ void tLivingString2_setPrepPos (tLivingString2* const, float prepPos);
562+ void tLivingString2_setPickupPos (tLivingString2* const, float pickupPos);
563+ void tLivingString2_setPrepIndex (tLivingString2* const, float prepIndex);
564+ void tLivingString2_setBrightness (tLivingString2* const, float brightness);
565+ void tLivingString2_setDecay (tLivingString2* const, float decay); // from 0 to 1, gets converted to real decay factor
566+ void tLivingString2_setTargetLev (tLivingString2* const, float targetLev);
567+ void tLivingString2_setLevSmoothFactor (tLivingString2* const, float levSmoothFactor);
568+ void tLivingString2_setLevStrength (tLivingString2* const, float levStrength);
569+ void tLivingString2_setLevMode (tLivingString2* const, int levMode);
570+
571+
447572
573+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
448574 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
449575
450576 /*!
leaf/Src/leaf-delay.c+74−52
@@ -368,6 +368,25 @@ void tHermiteDelay_initToPool (tHermiteDelay* const dl, float delay, uint32_t m · 367 unmodified lines
368368 else if (delay < 0.0f) d->delay = 0.0f;
369369 else d->delay = delay;
370370
371+
372+ if ((maxDelay != 0) && ((maxDelay & (maxDelay - 1)) == 0))
373+ {
374+ d->maxDelay = maxDelay;
375+ d->bufferMask = maxDelay - 1;
376+ }
377+ else
378+ {
379+ //make the delay size into a power of 2
380+ maxDelay--;
381+ maxDelay |= maxDelay >> 1;
382+ maxDelay |= maxDelay >> 2;
383+ maxDelay |= maxDelay >> 4;
384+ maxDelay |= maxDelay >> 8;
385+ maxDelay |= maxDelay >> 16;
386+ maxDelay++;
387+ d->maxDelay = maxDelay;
388+ d->bufferMask = maxDelay - 1;
389+ }
371390 d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
372391
373392 d->gain = 1.0f;
@@ -405,19 +424,20 @@ float tHermiteDelay_tick (tHermiteDelay* const dl, float input) · 31 unmodified lines
405424
406425 d->buff[d->inPoint] = input * d->gain;
407426
427+
408428 // Increment input pointer modulo length.
409− if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
410−
411−
429+ d->inPoint = (d->inPoint + 1) & d->bufferMask;
430+
431+
412432 uint32_t idx = (uint32_t) d->outPoint;
413− d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
414− d->buff[idx],
415− d->buff[(idx + 1) % d->maxDelay],
416− d->buff[(idx + 2) % d->maxDelay],
417− d->alpha);
418−
433+ d->lastOut = LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) & d->bufferMask],
434+ d->buff[idx],
435+ d->buff[(idx + 1) & d->bufferMask],
436+ d->buff[(idx + 2) & d->bufferMask],
437+ d->alpha);
438+
419439 // Increment output pointer modulo length
420− if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;
440+ d->outPoint = (d->outPoint + 1) & d->bufferMask;
421441
422442 return d->lastOut;
423443 }
@@ -425,86 +445,88 @@ float tHermiteDelay_tick (tHermiteDelay* const dl, float input) · 1 unmodified line
425445 void tHermiteDelay_tickIn (tHermiteDelay* const dl, float input)
426446 {
427447 _tHermiteDelay* d = *dl;
428−
429− d->buff[d->inPoint] = input * d->gain;
430−
448+
449+ d->buff[d->inPoint] = input;
450+
431451 // Increment input pointer modulo length.
432− if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
452+ d->inPoint = (d->inPoint + 1) & d->bufferMask;
433453 }
434454
435455 float tHermiteDelay_tickOut (tHermiteDelay* const dl)
436456 {
437457 _tHermiteDelay* d = *dl;
438−
458+
439459 uint32_t idx = (uint32_t) d->outPoint;
440−
441−
442−
443− d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
444− d->buff[idx],
445− d->buff[(idx + 1) % d->maxDelay],
446− d->buff[(idx + 2) % d->maxDelay],
447− d->alpha);
448−
460+
461+
462+
463+ d->lastOut = LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) & d->bufferMask],
464+ d->buff[idx],
465+ d->buff[(idx + 1) & d->bufferMask],
466+ d->buff[(idx + 2) & d->bufferMask],
467+ d->alpha);
468+
449469 // Increment output pointer modulo length
450− if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;
451−
470+ d->outPoint = (d->outPoint + 1) & d->bufferMask;
471+
452472 return d->lastOut;
453473 }
454474
455475 void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay)
456476 {
457477 _tHermiteDelay* d = *dl;
458−
459− d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
460−
478+ //d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
479+ d->delay = delay; // not safe but faster
461480 float outPointer = d->inPoint - d->delay;
462−
463481 while ( outPointer < 0 )
464482 outPointer += d->maxDelay; // modulo maximum length
465−
483+
466484 d->outPoint = (uint32_t) outPointer; // integer part
467−
485+
468486 d->alpha = outPointer - d->outPoint; // fractional part
469487 d->omAlpha = 1.0f - d->alpha;
470−
471− if ( d->outPoint == d->maxDelay ) d->outPoint = 0;
488+
489+ d->outPoint &= d->bufferMask;
472490 }
473491
474492 float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay)
475493 {
476494 _tHermiteDelay* d = *dl;
477−
478− int32_t tap = d->inPoint - tapDelay - 1;
479−
480− // Check for wraparound.
481− while ( tap < 0 ) tap += d->maxDelay;
482−
495+
496+ int32_t tap = (d->inPoint - tapDelay - 1) & d->bufferMask;
497+
483498 return d->buff[tap];
484499
485500 }
486501
487−void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)
502+float tHermiteDelay_tapOutInterpolated (tHermiteDelay* const dl, uint32_t tapDelay, float alpha)
488503 {
489504 _tHermiteDelay* d = *dl;
505+
506+ int32_t idx = (d->inPoint - tapDelay - 1) & d->bufferMask;
507+
508+ return LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) & d->bufferMask],
509+ d->buff[idx],
510+ d->buff[(idx + 1) & d->bufferMask],
511+ d->buff[(idx + 2) & d->bufferMask],
512+ alpha);
513+}
490514
491− int32_t tap = d->inPoint - tapDelay - 1;
492−
493− // Check for wraparound.
494− while ( tap < 0 ) tap += d->maxDelay;
495−
515+void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)
516+{
517+ _tHermiteDelay* d = *dl;
518+
519+ int32_t tap = (d->inPoint - tapDelay - 1) & d->bufferMask;
520+
496521 d->buff[tap] = value;
497522 }
498523
499524 float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay)
500525 {
501526 _tHermiteDelay* d = *dl;
502−
503− int32_t tap = d->inPoint - tapDelay - 1;
504−
505− // Check for wraparound.
506− while ( tap < 0 ) tap += d->maxDelay;
507−
527+
528+ int32_t tap = (d->inPoint - tapDelay - 1) & d->bufferMask;
529+
508530 return (d->buff[tap] += value);
509531 }
510532
leaf/Src/leaf-physical.c+303−0
@@ -659,6 +659,309 @@ float tLivingString_sample(tLivingString* const pl) · 658 unmodified lines
659659 }
660660
661661
662+//////////---------------------------
663+/* Version of Living String with Hermite Interpolation */
664+/*Living String experiment 2 */
665+
666+/* Living String*/
667+
668+void tLivingString2_init(tLivingString2* const pl, float freq, float pickPos, float prepPos, float pickupPos, float prepIndex,
669+ float brightness, float decay, float targetLev, float levSmoothFactor,
670+ float levStrength, int levMode, LEAF* const leaf)
671+{
672+ tLivingString2_initToPool(pl, freq, pickPos, prepPos, pickupPos, prepIndex, brightness, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf->mempool);
673+}
674+
675+void tLivingString2_initToPool (tLivingString2* const pl, float freq, float pickPos, float prepPos, float pickupPos, float prepIndex,
676+ float brightness, float decay, float targetLev, float levSmoothFactor,
677+ float levStrength, int levMode, tMempool* const mp)
678+{
679+ _tMempool* m = *mp;
680+ _tLivingString2* p = *pl = (_tLivingString2*) mpool_alloc(sizeof(_tLivingString2), m);
681+ p->mempool = m;
682+ LEAF* leaf = p->mempool->leaf;
683+
684+ p->curr=0.0f;
685+ tExpSmooth_initToPool(&p->wlSmooth, leaf->sampleRate/freq, 0.01f, mp); // smoother for string wavelength (not freq, to avoid expensive divisions)
686+ tLivingString2_setFreq(pl, freq);
687+ p->freq = freq;
688+ p->prepPos = prepPos;
689+ tExpSmooth_initToPool(&p->ppSmooth, pickPos, 0.01f, mp); // smoother for pick position
690+ tExpSmooth_initToPool(&p->prpSmooth, prepPos, 0.01f, mp); // smoother for prep position
691+ tExpSmooth_initToPool(&p->puSmooth, pickupPos, 0.01f, mp); // smoother for pickup position
692+ tLivingString2_setPickPos(pl, pickPos);
693+ tLivingString2_setPrepPos(pl, prepPos);
694+ p->prepIndex=prepIndex;
695+ p->pickupPos = pickupPos;
696+ tHermiteDelay_initToPool(&p->delLF,p->waveLengthInSamples, 2400, mp);
697+ tHermiteDelay_initToPool(&p->delUF,p->waveLengthInSamples, 2400, mp);
698+ tHermiteDelay_initToPool(&p->delUB,p->waveLengthInSamples, 2400, mp);
699+ tHermiteDelay_initToPool(&p->delLB,p->waveLengthInSamples, 2400, mp);
700+ tHermiteDelay_clear(&p->delLF);
701+ tHermiteDelay_clear(&p->delUF);
702+ tHermiteDelay_clear(&p->delUB);
703+ tHermiteDelay_clear(&p->delLB);
704+ p->brightness = brightness;
705+ tTwoZero_initToPool(&p->bridgeFilter, mp);
706+ tTwoZero_initToPool(&p->nutFilter, mp);
707+ tTwoZero_initToPool(&p->prepFilterU, mp);
708+ tTwoZero_initToPool(&p->prepFilterL, mp);
709+ tHighpass_initToPool(&p->DCblockerU,13, mp);
710+ tHighpass_initToPool(&p->DCblockerL,13, mp);
711+ p->decay=decay;
712+ p->prepIndex = prepIndex;
713+ tFeedbackLeveler_initToPool(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode, mp);
714+ tFeedbackLeveler_initToPool(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode, mp);
715+ p->levMode=levMode;
716+}
717+
718+void tLivingString2_free (tLivingString2* const pl)
719+{
720+ _tLivingString2* p = *pl;
721+
722+ tExpSmooth_free(&p->wlSmooth);
723+ tExpSmooth_free(&p->ppSmooth);
724+ tExpSmooth_free(&p->prpSmooth);
725+ tExpSmooth_free(&p->puSmooth);
726+ tHermiteDelay_free(&p->delLF);
727+ tHermiteDelay_free(&p->delUF);
728+ tHermiteDelay_free(&p->delUB);
729+ tHermiteDelay_free(&p->delLB);
730+ tTwoZero_free(&p->bridgeFilter);
731+ tTwoZero_free(&p->nutFilter);
732+ tTwoZero_free(&p->prepFilterU);
733+ tTwoZero_free(&p->prepFilterL);
734+ tHighpass_free(&p->DCblockerU);
735+ tHighpass_free(&p->DCblockerL);
736+ tFeedbackLeveler_free(&p->fbLevU);
737+ tFeedbackLeveler_free(&p->fbLevL);
738+
739+ mpool_free((char*)p, p->mempool);
740+}
741+
742+void tLivingString2_setFreq(tLivingString2* const pl, float freq)
743+{ // NOTE: It is faster to set wavelength in samples directly
744+ _tLivingString2* p = *pl;
745+ LEAF* leaf = p->mempool->leaf;
746+ if (freq<20.f) freq=20.f;
747+ else if (freq>10000.f) freq=10000.f;
748+ p->freq = freq;
749+ p->waveLengthInSamples = (leaf->sampleRate/freq) - 1;
750+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
751+}
752+
753+void tLivingString2_setWaveLength(tLivingString2* const pl, float waveLength)
754+{
755+ _tLivingString2* p = *pl;
756+ LEAF* leaf = p->mempool->leaf;
757+ if (waveLength<4.8f) waveLength=4.8f;
758+ else if (waveLength>2400.f) waveLength=2400.f;
759+ p->waveLengthInSamples = waveLength - 1;
760+ p->freq = leaf->sampleRate / waveLength;
761+ tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
762+}
763+
764+void tLivingString2_setPickPos(tLivingString2* const pl, float pickPos)
765+{ // between 0 and 1
766+ _tLivingString2* p = *pl;
767+ if (pickPos<0.f) pickPos=0.f;
768+ else if (pickPos>1.f) pickPos=1.f;
769+ p->pickPos = pickPos;
770+ tExpSmooth_setDest(&p->ppSmooth, p->pickPos);
771+}
772+
773+void tLivingString2_setPrepPos(tLivingString2* const pl, float prepPos)
774+{ // between 0 and 1
775+ _tLivingString2* p = *pl;
776+ if (prepPos<0.f) prepPos=0.f;
777+ else if (prepPos>1.f) prepPos=1.f;
778+ p->prepPos = prepPos;
779+ tExpSmooth_setDest(&p->prpSmooth, p->prepPos);
780+}
781+
782+void tLivingString2_setPickupPos(tLivingString2* const pl, float pickupPos)
783+{ // between 0 and 1
784+ _tLivingString2* p = *pl;
785+ if (pickupPos<0.f) pickupPos=0.f;
786+ else if (pickupPos>1.f) pickupPos=1.f;
787+ p->pickupPos = pickupPos;
788+ tExpSmooth_setDest(&p->puSmooth, p->pickupPos);
789+}
790+
791+void tLivingString2_setPrepIndex(tLivingString2* const pl, float prepIndex)
792+{ // between 0 and 1
793+ _tLivingString2* p = *pl;
794+ if (prepIndex<0.f) prepIndex=0.f;
795+ else if (prepIndex>1.f) prepIndex=1.f;
796+ p->prepIndex = prepIndex;
797+}
798+
799+void tLivingString2_setBrightness(tLivingString2* const pl, float brightness)
800+{
801+ _tLivingString2* p = *pl;
802+ float h0=(1.0 + brightness) * 0.5f;
803+ float h1=(1.0 - brightness) * 0.25f;
804+
805+ tTwoZero_setCoefficients(&p->bridgeFilter, h1, h0, h1);
806+ tTwoZero_setCoefficients(&p->nutFilter, h1, h0, h1);
807+ tTwoZero_setCoefficients(&p->prepFilterU, h1, h0, h1);
808+ tTwoZero_setCoefficients(&p->prepFilterL, h1, h0, h1);
809+}
810+
811+void tLivingString2_setDecay(tLivingString2* const pl, float decay)
812+{
813+ _tLivingString2* p = *pl;
814+ p->decay=powf(0.001f,1.0f/(p->freq*decay));
815+}
816+
817+void tLivingString2_setTargetLev(tLivingString2* const pl, float targetLev)
818+{
819+ _tLivingString2* p = *pl;
820+ tFeedbackLeveler_setTargetLevel(&p->fbLevU, targetLev);
821+ tFeedbackLeveler_setTargetLevel(&p->fbLevL, targetLev);
822+}
823+
824+void tLivingString2_setLevSmoothFactor(tLivingString2* const pl, float levSmoothFactor)
825+{
826+ _tLivingString2* p = *pl;
827+ tFeedbackLeveler_setFactor(&p->fbLevU, levSmoothFactor);
828+ tFeedbackLeveler_setFactor(&p->fbLevL, levSmoothFactor);
829+}
830+
831+void tLivingString2_setLevStrength(tLivingString2* const pl, float levStrength)
832+{
833+ _tLivingString2* p = *pl;
834+ tFeedbackLeveler_setStrength(&p->fbLevU, levStrength);
835+ tFeedbackLeveler_setStrength(&p->fbLevL, levStrength);
836+}
837+
838+void tLivingString2_setLevMode(tLivingString2* const pl, int levMode)
839+{
840+ _tLivingString2* p = *pl;
841+ tFeedbackLeveler_setMode(&p->fbLevU, levMode);
842+ tFeedbackLeveler_setMode(&p->fbLevL, levMode);
843+ p->levMode=levMode;
844+}
845+
846+float tLivingString2_tick(tLivingString2* const pl, float input)
847+{
848+ _tLivingString2* p = *pl;
849+
850+ input = input * 0.5f; // drop gain by half since we'll be equally adding it at half amplitude to forward and backward waveguides
851+ // from prepPos upwards=forwards
852+ float wLen=tExpSmooth_tick(&p->wlSmooth);
853+
854+ float pickP=tExpSmooth_tick(&p->ppSmooth);
855+
856+ //float pickupPos=tExpSmooth_tick(&p->puSmooth);
857+
858+ //need to determine which delay line to put it into (should be half amplitude into forward and backward lines for the correct portion of string)
859+ float prepP=tExpSmooth_tick(&p->prpSmooth);
860+ float lowLen=prepP*wLen;
861+ float upLen=(1.0f-prepP)*wLen;
862+ uint32_t pickPInt;
863+/*
864+ if (pickP > prepP)
865+ {
866+ float fullPickPoint = ((pickP*wLen) - lowLen);
867+ pickPInt = (uint) fullPickPoint; // where does the input go? that's the pick point
868+ float pickPFloat = fullPickPoint - pickPInt;
869+
870+ tHermiteDelay_addTo(&p->delUF, input * (1.0f - pickPFloat), pickPInt);
871+ tHermiteDelay_addTo(&p->delUF, input * pickPFloat, pickPInt + 1);
872+ tHermiteDelay_addTo(&p->delUB, input * (1.0f - pickPFloat), (uint) (upLen - pickPInt));
873+ tHermiteDelay_addTo(&p->delUB, input * pickPFloat, (uint) (upLen - pickPInt - 1));
874+ }
875+ else
876+ {
877+ float fullPickPoint = pickP * wLen;
878+ pickPInt = (uint) fullPickPoint; // where does the input go? that's the pick point
879+ float pickPFloat = fullPickPoint - pickPInt;
880+
881+ tHermiteDelay_addTo(&p->delLF, input * (1.0f - pickPFloat), pickPInt);
882+ tHermiteDelay_addTo(&p->delLF, input * pickPFloat, pickPInt + 1);
883+ tHermiteDelay_addTo(&p->delLB, input * (1.0f - pickPFloat), (uint) (lowLen - pickPInt));
884+ tHermiteDelay_addTo(&p->delLB, input * pickPFloat, (uint) (lowLen - pickPInt - 1));
885+ }
886+*/
887+ if (pickP > prepP)
888+ {
889+ float fullPickPoint = ((pickP*wLen) - lowLen);
890+ pickPInt = (uint32_t) fullPickPoint; // where does the input go? that's the pick point
891+
892+ tHermiteDelay_addTo(&p->delUF, input, pickPInt);
893+ tHermiteDelay_addTo(&p->delUB, input, (uint32_t) (upLen - pickPInt));
894+ }
895+ else
896+ {
897+ float fullPickPoint = pickP * wLen;
898+ pickPInt = (uint32_t) fullPickPoint; // where does the input go? that's the pick point
899+
900+ tHermiteDelay_addTo(&p->delLF, input, pickPInt);
901+ tHermiteDelay_addTo(&p->delLB, input, (uint32_t) (lowLen - pickPInt));
902+ }
903+
904+ float fromLF=tHermiteDelay_tickOut(&p->delLF);
905+ float fromUF=tHermiteDelay_tickOut(&p->delUF);
906+ float fromUB=tHermiteDelay_tickOut(&p->delUB);
907+ float fromLB=tHermiteDelay_tickOut(&p->delLB);
908+ // into upper half of string, from bridge, going backwards
909+ float fromBridge=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tTwoZero_tick(&p->bridgeFilter, fromUF)));
910+ tHermiteDelay_tickIn(&p->delUB, fromBridge);
911+ // into lower half of string, from prepPoint, going backwards
912+ float fromLowerPrep=-tTwoZero_tick(&p->prepFilterL, fromLF);
913+ float intoLower=p->prepIndex*fromLowerPrep+(1.0f - p->prepIndex)*fromUB; //used to add input here
914+ tHermiteDelay_tickIn(&p->delLB, intoLower);
915+ // into lower half of string, from nut
916+ float fromNut=-tFeedbackLeveler_tick(&p->fbLevL, (p->levMode==0?p->decay:1.0f)*tHighpass_tick(&p->DCblockerL, tTwoZero_tick(&p->nutFilter, fromLB)));
917+ tHermiteDelay_tickIn(&p->delLF, fromNut);
918+ // into upper half of string, from prepPoint, going forwards/upwards
919+ float fromUpperPrep=-tTwoZero_tick(&p->prepFilterU, fromUB);
920+ float intoUpper=p->prepIndex*fromUpperPrep+(1.0f - p->prepIndex)*fromLF;
921+ tHermiteDelay_tickIn(&p->delUF, intoUpper);
922+ // update all delay lengths
923+
924+ tHermiteDelay_setDelay(&p->delLF, lowLen);
925+ tHermiteDelay_setDelay(&p->delLB, lowLen);
926+ tHermiteDelay_setDelay(&p->delUF, upLen);
927+ tHermiteDelay_setDelay(&p->delUB, upLen);
928+
929+ /*
930+ uint pickupPosInt;
931+ float pickupOut = 0.0f;
932+ if (pickupPos < 0.9f)
933+ {
934+ float fullPickupPos = (pickupPos*upLen);
935+ pickupPosInt = (uint) fullPickupPos;
936+ float pickupPosFloat = fullPickupPos - pickupPosInt;
937+ if (pickupPosInt == 0)
938+ {
939+ pickupPosInt = 1;
940+ }
941+ pickupOut = tHermiteDelay_tapOutInterpolated(&p->delUF, pickupPosInt, pickupPosFloat);
942+ pickupOut += tHermiteDelay_tapOutInterpolated(&p->delUB, (uint) (upLen - pickupPosInt), pickupPosFloat);
943+ p->curr = pickupOut;
944+ }
945+ else
946+ */
947+ //{
948+ p->curr = fromBridge;
949+ //}
950+
951+ //p->curr = fromBridge;
952+ //p->curr += fromNut;
953+
954+ return p->curr;
955+}
956+
957+float tLivingString2_sample(tLivingString2* const pl)
958+{
959+ _tLivingString2* p = *pl;
960+ return p->curr;
961+}
962+
963+
964+
662965 //////////---------------------------
663966
664967 /* Complex Living String (has pick position and preparation position separated) */
leaf/leaf-config.h+1−1
@@ -58,7 +58,7 @@ · 57 unmodified lines
5858
5959 #define LEAF_USE_CMSIS 0
6060
61−//! Use stdlib malloc() and free() internally instead of LEAF's normal mempool behavior for when you want to avoid being limited to and managing mempool a fixed mempool size. Usage of all object remains essentially the same.
61+//! Use stdlib malloc() and free() internally instead of LEAF's normal mempool behavior for when you want to avoid being limited to and managing mempool a fixed mempool size. Usage of all object remains essentially the same.
6262 #define LEAF_USE_DYNAMIC_ALLOCATION 1
6363
6464 //==============================================================================

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

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

Repository code

Go to file
t