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
317 @param position317 @param position
318 @return318 @return
319 319
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
320 @fn void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)327 @fn void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)
321 @brief328 @brief
322 @param delay A pointer to the relevant tHermiteDelay.329 @param delay A pointer to the relevant tHermiteDelay.
@@ -361,15 +368,14 @@ extern "C" { · 38 unmodified lines
361 {368 {
362 tMempool mempool;369 tMempool mempool;
363 370
364 float gain;
365 float* buff;371 float* buff;
366 372 uint32_t bufferMask;
367 float lastOut, lastIn;373 float lastOut, lastIn;
368 374
369 uint32_t inPoint, outPoint;375 uint32_t inPoint, outPoint;
370 376
371 uint32_t maxDelay;377 uint32_t maxDelay;
372 378 float gain;
373 float delay;379 float delay;
374 380
375 float alpha, omAlpha;381 float alpha, omAlpha;
@@ -387,6 +393,7 @@ extern "C" { · 11 unmodified lines
387 float tHermiteDelay_tickOut (tHermiteDelay* const dl);393 float tHermiteDelay_tickOut (tHermiteDelay* const dl);
388 void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay);394 void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay);
389 float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay);395 float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay);
396 float tHermiteDelay_tapOutInterpolated (tHermiteDelay* const dl, uint32_t tapDelay, float alpha);
390 void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay);397 void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay);
391 float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay);398 float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay);
392 float tHermiteDelay_getDelay (tHermiteDelay* const dl);399 float tHermiteDelay_getDelay (tHermiteDelay* const dl);
leaf/Inc/leaf-physical.h+126−0
@@ -444,7 +444,133 @@ extern "C" { · 443 unmodified lines
444 void tLivingString_setLevMode (tLivingString* const, int levMode);444 void tLivingString_setLevMode (tLivingString* const, int levMode);
445 445
446 446
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
447 572
573 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
448 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~574 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
449 575
450 /*!576 /*!
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
368 else if (delay < 0.0f) d->delay = 0.0f;368 else if (delay < 0.0f) d->delay = 0.0f;
369 else d->delay = delay;369 else d->delay = delay;
370 370
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 }
371 d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);390 d->buff = (float*) mpool_alloc(sizeof(float) * maxDelay, m);
372 391
373 d->gain = 1.0f;392 d->gain = 1.0f;
@@ -405,19 +424,20 @@ float tHermiteDelay_tick (tHermiteDelay* const dl, float input) · 31 unmodified lines
405 424
406 d->buff[d->inPoint] = input * d->gain;425 d->buff[d->inPoint] = input * d->gain;
407 426
427
408 // Increment input pointer modulo length.428 // Increment input pointer modulo length.
409 if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;429 d->inPoint = (d->inPoint + 1) & d->bufferMask;
410 430
411 431
412 uint32_t idx = (uint32_t) d->outPoint;432 uint32_t idx = (uint32_t) d->outPoint;
413 d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],433 d->lastOut = LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) & d->bufferMask],
414 d->buff[idx],434 d->buff[idx],
415 d->buff[(idx + 1) % d->maxDelay],435 d->buff[(idx + 1) & d->bufferMask],
416 d->buff[(idx + 2) % d->maxDelay],436 d->buff[(idx + 2) & d->bufferMask],
417 d->alpha);437 d->alpha);
418 438
419 // Increment output pointer modulo length439 // Increment output pointer modulo length
420 if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;440 d->outPoint = (d->outPoint + 1) & d->bufferMask;
421 441
422 return d->lastOut;442 return d->lastOut;
423}443}
@@ -425,86 +445,88 @@ float tHermiteDelay_tick (tHermiteDelay* const dl, float input) · 1 unmodified line
425void tHermiteDelay_tickIn (tHermiteDelay* const dl, float input)445void tHermiteDelay_tickIn (tHermiteDelay* const dl, float input)
426{446{
427 _tHermiteDelay* d = *dl;447 _tHermiteDelay* d = *dl;
428 448
429 d->buff[d->inPoint] = input * d->gain;449 d->buff[d->inPoint] = input;
430 450
431 // Increment input pointer modulo length.451 // Increment input pointer modulo length.
432 if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;452 d->inPoint = (d->inPoint + 1) & d->bufferMask;
433}453}
434 454
435float tHermiteDelay_tickOut (tHermiteDelay* const dl)455float tHermiteDelay_tickOut (tHermiteDelay* const dl)
436{456{
437 _tHermiteDelay* d = *dl;457 _tHermiteDelay* d = *dl;
438 458
439 uint32_t idx = (uint32_t) d->outPoint;459 uint32_t idx = (uint32_t) d->outPoint;
440 460
441 461
442 462
443 d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],463 d->lastOut = LEAF_interpolate_hermite_x (d->buff[((idx - 1) + d->maxDelay) & d->bufferMask],
444 d->buff[idx],464 d->buff[idx],
445 d->buff[(idx + 1) % d->maxDelay],465 d->buff[(idx + 1) & d->bufferMask],
446 d->buff[(idx + 2) % d->maxDelay],466 d->buff[(idx + 2) & d->bufferMask],
447 d->alpha);467 d->alpha);
448 468
449 // Increment output pointer modulo length469 // Increment output pointer modulo length
450 if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0;470 d->outPoint = (d->outPoint + 1) & d->bufferMask;
451 471
452 return d->lastOut;472 return d->lastOut;
453}473}
454 474
455void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay)475void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay)
456{476{
457 _tHermiteDelay* d = *dl;477 _tHermiteDelay* d = *dl;
458 478 //d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
459 d->delay = LEAF_clip(0.0f, delay, d->maxDelay);479 d->delay = delay; // not safe but faster
460
461 float outPointer = d->inPoint - d->delay;480 float outPointer = d->inPoint - d->delay;
462
463 while ( outPointer < 0 )481 while ( outPointer < 0 )
464 outPointer += d->maxDelay; // modulo maximum length482 outPointer += d->maxDelay; // modulo maximum length
465 483
466 d->outPoint = (uint32_t) outPointer; // integer part484 d->outPoint = (uint32_t) outPointer; // integer part
467 485
468 d->alpha = outPointer - d->outPoint; // fractional part486 d->alpha = outPointer - d->outPoint; // fractional part
469 d->omAlpha = 1.0f - d->alpha;487 d->omAlpha = 1.0f - d->alpha;
470 488
471 if ( d->outPoint == d->maxDelay ) d->outPoint = 0;489 d->outPoint &= d->bufferMask;
472}490}
473 491
474float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay)492float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay)
475{493{
476 _tHermiteDelay* d = *dl;494 _tHermiteDelay* d = *dl;
477 495
478 int32_t tap = d->inPoint - tapDelay - 1;496 int32_t tap = (d->inPoint - tapDelay - 1) & d->bufferMask;
479 497
480 // Check for wraparound.
481 while ( tap < 0 ) tap += d->maxDelay;
482
483 return d->buff[tap];498 return d->buff[tap];
484 499
485}500}
486 501
487void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)502float tHermiteDelay_tapOutInterpolated (tHermiteDelay* const dl, uint32_t tapDelay, float alpha)
488{503{
489 _tHermiteDelay* d = *dl;504 _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}
490 514
491 int32_t tap = d->inPoint - tapDelay - 1;515void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay)
492 516{
493 // Check for wraparound.517 _tHermiteDelay* d = *dl;
494 while ( tap < 0 ) tap += d->maxDelay;518
495 519 int32_t tap = (d->inPoint - tapDelay - 1) & d->bufferMask;
520
496 d->buff[tap] = value;521 d->buff[tap] = value;
497}522}
498 523
499float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay)524float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay)
500{525{
501 _tHermiteDelay* d = *dl;526 _tHermiteDelay* d = *dl;
502 527
503 int32_t tap = d->inPoint - tapDelay - 1;528 int32_t tap = (d->inPoint - tapDelay - 1) & d->bufferMask;
504 529
505 // Check for wraparound.
506 while ( tap < 0 ) tap += d->maxDelay;
507
508 return (d->buff[tap] += value);530 return (d->buff[tap] += value);
509}531}
510 532
leaf/Src/leaf-physical.c+303−0
@@ -659,6 +659,309 @@ float tLivingString_sample(tLivingString* const pl) · 658 unmodified lines
659}659}
660 660
661 661
662//////////---------------------------
663/* Version of Living String with Hermite Interpolation */
664/*Living String experiment 2 */
665
666/* Living String*/
667
668void 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
675void 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
718void 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
742void 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
753void 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
764void 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
773void 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
782void 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
791void 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
799void 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
811void 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
817void 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
824void 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
831void 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
838void 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
846float 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
957float tLivingString2_sample(tLivingString2* const pl)
958{
959 _tLivingString2* p = *pl;
960 return p->curr;
961}
962
963
964
662//////////---------------------------965//////////---------------------------
663 966
664/* Complex Living String (has pick position and preparation position separated) */967/* Complex Living String (has pick position and preparation position separated) */
leaf/leaf-config.h+1−1
@@ -58,7 +58,7 @@ · 57 unmodified lines
58 58
59#define LEAF_USE_CMSIS 059#define LEAF_USE_CMSIS 0
60 60
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.
62#define LEAF_USE_DYNAMIC_ALLOCATION 162#define LEAF_USE_DYNAMIC_ALLOCATION 1
63 63
64//==============================================================================64//==============================================================================

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