Unified · Split
| @@ -317,6 +317,13 @@ extern "C" { · 316 unmodified lines | |||
| 317 | @param position | 317 | @param position |
| 318 | @return | 318 | @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 | @brief | 328 | @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); |
| @@ -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 | /*! |
| @@ -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 length | 439 | // 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 | |||
| 425 | void tHermiteDelay_tickIn (tHermiteDelay* const dl, float input) | 445 | void 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 | ||
| 435 | float tHermiteDelay_tickOut (tHermiteDelay* const dl) | 455 | float 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 length | 469 | // 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 | ||
| 455 | void tHermiteDelay_setDelay (tHermiteDelay* const dl, float delay) | 475 | void 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 length | 482 | outPointer += d->maxDelay; // modulo maximum length |
| 465 | 483 | ||
| 466 | d->outPoint = (uint32_t) outPointer; // integer part | 484 | d->outPoint = (uint32_t) outPointer; // integer part |
| 467 | 485 | ||
| 468 | d->alpha = outPointer - d->outPoint; // fractional part | 486 | 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 | ||
| 474 | float tHermiteDelay_tapOut (tHermiteDelay* const dl, uint32_t tapDelay) | 492 | float 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 | ||
| 487 | void tHermiteDelay_tapIn (tHermiteDelay* const dl, float value, uint32_t tapDelay) | 502 | float 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; | 515 | void 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 | ||
| 499 | float tHermiteDelay_addTo (tHermiteDelay* const dl, float value, uint32_t tapDelay) | 524 | float 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 | ||
| @@ -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 | |||
| 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 | |||
| 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) */ |
| @@ -58,7 +58,7 @@ · 57 unmodified lines | |||
| 58 | 58 | ||
| 59 | #define LEAF_USE_CMSIS 0 | 59 | #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 1 | 62 | #define LEAF_USE_DYNAMIC_ALLOCATION 1 |
| 63 | 63 | ||
| 64 | //============================================================================== | 64 | //============================================================================== |