| @@ -668,6 +668,252 @@ float tLivingString_sample(tLivingString* const pl) · 667 unmodified lines |
| 668 | return p->curr; | 668 | return p->curr; |
| 669 | } | 669 | } |
| 670 | | 670 | |
| | 671 | |
| | 672 | //////////--------------------------- |
| | 673 | |
| | 674 | /* Complex Living String (has pick position and preparation position separated) */ |
| | 675 | |
| | 676 | void tComplexLivingString_init(tComplexLivingString* const pl, float freq, float pickPos, float prepPos, float prepIndex, |
| | 677 | float dampFreq, float decay, float targetLev, float levSmoothFactor, |
| | 678 | float levStrength, int levMode) |
| | 679 | { |
| | 680 | tComplexLivingString_initToPool(pl, freq, pickPos, prepPos, prepIndex, dampFreq, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf.mempool); |
| | 681 | } |
| | 682 | |
| | 683 | void tComplexLivingString_free(tComplexLivingString* const pl) |
| | 684 | { |
| | 685 | tComplexLivingString_freeFromPool(pl, &leaf.mempool); |
| | 686 | } |
| | 687 | |
| | 688 | void tComplexLivingString_initToPool (tComplexLivingString* const pl, float freq, float pickPos, float prepPos, float prepIndex, |
| | 689 | float dampFreq, float decay, float targetLev, float levSmoothFactor, |
| | 690 | float levStrength, int levMode, tMempool* const mp) |
| | 691 | { |
| | 692 | _tMempool* m = *mp; |
| | 693 | _tComplexLivingString* p = *pl = (_tComplexLivingString*) mpool_alloc(sizeof(_tComplexLivingString), m); |
| | 694 | |
| | 695 | p->curr=0.0f; |
| | 696 | tExpSmooth_initToPool(&p->wlSmooth, leaf.sampleRate/freq, 0.01, mp); // smoother for string wavelength (not freq, to avoid expensive divisions) |
| | 697 | tComplexLivingString_setFreq(pl, freq); |
| | 698 | p->freq = freq; |
| | 699 | tExpSmooth_initToPool(&p->pickPosSmooth, pickPos, 0.01f, mp); // smoother for pick position |
| | 700 | tExpSmooth_initToPool(&p->prepPosSmooth, prepPos, 0.01f, mp); // smoother for pick position |
| | 701 | |
| | 702 | tComplexLivingString_setPickPos(pl, pickPos); |
| | 703 | tComplexLivingString_setPrepPos(pl, prepPos); |
| | 704 | |
| | 705 | p->prepPos=prepPos; |
| | 706 | p->pickPos=pickPos; |
| | 707 | tLinearDelay_initToPool(&p->delLF,p->waveLengthInSamples, 2400, mp); |
| | 708 | tLinearDelay_initToPool(&p->delMF,p->waveLengthInSamples, 2400, mp); |
| | 709 | tLinearDelay_initToPool(&p->delUF,p->waveLengthInSamples, 2400, mp); |
| | 710 | tLinearDelay_initToPool(&p->delUB,p->waveLengthInSamples, 2400, mp); |
| | 711 | tLinearDelay_initToPool(&p->delMB,p->waveLengthInSamples, 2400, mp); |
| | 712 | tLinearDelay_initToPool(&p->delLB,p->waveLengthInSamples, 2400, mp); |
| | 713 | tLinearDelay_clear(&p->delLF); |
| | 714 | tLinearDelay_clear(&p->delMF); |
| | 715 | tLinearDelay_clear(&p->delUF); |
| | 716 | tLinearDelay_clear(&p->delUB); |
| | 717 | tLinearDelay_clear(&p->delMB); |
| | 718 | tLinearDelay_clear(&p->delLB); |
| | 719 | p->dampFreq = dampFreq; |
| | 720 | tOnePole_initToPool(&p->bridgeFilter, dampFreq, mp); |
| | 721 | tOnePole_initToPool(&p->nutFilter, dampFreq, mp); |
| | 722 | tOnePole_initToPool(&p->prepFilterU, dampFreq, mp); |
| | 723 | tOnePole_initToPool(&p->prepFilterL, dampFreq, mp); |
| | 724 | tHighpass_initToPool(&p->DCblockerU,13, mp); |
| | 725 | tHighpass_initToPool(&p->DCblockerL,13, mp); |
| | 726 | p->decay=decay; |
| | 727 | p->prepIndex = prepIndex; |
| | 728 | tFeedbackLeveler_initToPool(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode, mp); |
| | 729 | tFeedbackLeveler_initToPool(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode, mp); |
| | 730 | p->levMode=levMode; |
| | 731 | } |
| | 732 | |
| | 733 | void tComplexLivingString_freeFromPool (tComplexLivingString* const pl, tMempool* const mp) |
| | 734 | { |
| | 735 | _tMempool* m = *mp; |
| | 736 | _tComplexLivingString* p = *pl; |
| | 737 | |
| | 738 | tExpSmooth_freeFromPool(&p->wlSmooth, mp); |
| | 739 | tExpSmooth_freeFromPool(&p->pickPosSmooth, mp); |
| | 740 | tExpSmooth_freeFromPool(&p->prepPosSmooth, mp); |
| | 741 | tLinearDelay_freeFromPool(&p->delLF, mp); |
| | 742 | tLinearDelay_freeFromPool(&p->delMF, mp); |
| | 743 | tLinearDelay_freeFromPool(&p->delUF, mp); |
| | 744 | tLinearDelay_freeFromPool(&p->delUB, mp); |
| | 745 | tLinearDelay_freeFromPool(&p->delMB, mp); |
| | 746 | tLinearDelay_freeFromPool(&p->delLB, mp); |
| | 747 | tOnePole_freeFromPool(&p->bridgeFilter, mp); |
| | 748 | tOnePole_freeFromPool(&p->nutFilter, mp); |
| | 749 | tOnePole_freeFromPool(&p->prepFilterU, mp); |
| | 750 | tOnePole_freeFromPool(&p->prepFilterL, mp); |
| | 751 | tHighpass_freeFromPool(&p->DCblockerU, mp); |
| | 752 | tHighpass_freeFromPool(&p->DCblockerL, mp); |
| | 753 | tFeedbackLeveler_freeFromPool(&p->fbLevU, mp); |
| | 754 | tFeedbackLeveler_freeFromPool(&p->fbLevL, mp); |
| | 755 | |
| | 756 | mpool_free((char*)p, m); |
| | 757 | } |
| | 758 | |
| | 759 | void tComplexLivingString_setFreq(tComplexLivingString* const pl, float freq) |
| | 760 | { // NOTE: It is faster to set wavelength in samples directly |
| | 761 | _tComplexLivingString* p = *pl; |
| | 762 | if (freq<20.0f) freq=20.0f; |
| | 763 | else if (freq>10000.0f) freq=10000.0f; |
| | 764 | p->waveLengthInSamples = leaf.sampleRate/freq; |
| | 765 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); |
| | 766 | } |
| | 767 | |
| | 768 | void tComplexLivingString_setWaveLength(tComplexLivingString* const pl, float waveLength) |
| | 769 | { |
| | 770 | _tComplexLivingString* p = *pl; |
| | 771 | if (waveLength<4.8f) waveLength=4.8f; |
| | 772 | else if (waveLength>2400.0f) waveLength=2400.0f; |
| | 773 | p->waveLengthInSamples = waveLength; |
| | 774 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); |
| | 775 | } |
| | 776 | |
| | 777 | void tComplexLivingString_setPickPos(tComplexLivingString* const pl, float pickPos) |
| | 778 | { // between 0 and 1 |
| | 779 | _tComplexLivingString* p = *pl; |
| | 780 | if (pickPos<0.5f) pickPos=0.5f; |
| | 781 | else if (pickPos>1.f) pickPos=1.f; |
| | 782 | p->pickPos = pickPos; |
| | 783 | tExpSmooth_setDest(&p->pickPosSmooth, p->pickPos); |
| | 784 | } |
| | 785 | |
| | 786 | void tComplexLivingString_setPrepPos(tComplexLivingString* const pl, float prepPos) |
| | 787 | { // between 0 and 1 |
| | 788 | _tComplexLivingString* p = *pl; |
| | 789 | if (prepPos<0.f) prepPos=0.f; |
| | 790 | else if (prepPos>0.5f) prepPos=0.5f; |
| | 791 | p->prepPos = prepPos; |
| | 792 | tExpSmooth_setDest(&p->prepPosSmooth, p->prepPos); |
| | 793 | } |
| | 794 | |
| | 795 | void tComplexLivingString_setPrepIndex(tComplexLivingString* const pl, float prepIndex) |
| | 796 | { // between 0 and 1 |
| | 797 | _tComplexLivingString* p = *pl; |
| | 798 | if (prepIndex<0.f) prepIndex=0.f; |
| | 799 | else if (prepIndex>1.f) prepIndex=1.f; |
| | 800 | p->prepIndex = prepIndex; |
| | 801 | } |
| | 802 | |
| | 803 | void tComplexLivingString_setDampFreq(tComplexLivingString* const pl, float dampFreq) |
| | 804 | { |
| | 805 | _tComplexLivingString* p = *pl; |
| | 806 | tOnePole_setFreq(&p->bridgeFilter, dampFreq); |
| | 807 | tOnePole_setFreq(&p->nutFilter, dampFreq); |
| | 808 | tOnePole_setFreq(&p->prepFilterU, dampFreq); |
| | 809 | tOnePole_setFreq(&p->prepFilterL, dampFreq); |
| | 810 | } |
| | 811 | |
| | 812 | void tComplexLivingString_setDecay(tComplexLivingString* const pl, float decay) |
| | 813 | { |
| | 814 | _tComplexLivingString* p = *pl; |
| | 815 | p->decay=decay; |
| | 816 | } |
| | 817 | |
| | 818 | void tComplexLivingString_setTargetLev(tComplexLivingString* const pl, float targetLev) |
| | 819 | { |
| | 820 | _tComplexLivingString* p = *pl; |
| | 821 | tFeedbackLeveler_setTargetLevel(&p->fbLevU, targetLev); |
| | 822 | tFeedbackLeveler_setTargetLevel(&p->fbLevL, targetLev); |
| | 823 | } |
| | 824 | |
| | 825 | void tComplexLivingString_setLevSmoothFactor(tComplexLivingString* const pl, float levSmoothFactor) |
| | 826 | { |
| | 827 | _tComplexLivingString* p = *pl; |
| | 828 | tFeedbackLeveler_setFactor(&p->fbLevU, levSmoothFactor); |
| | 829 | tFeedbackLeveler_setFactor(&p->fbLevL, levSmoothFactor); |
| | 830 | } |
| | 831 | |
| | 832 | void tComplexLivingString_setLevStrength(tComplexLivingString* const pl, float levStrength) |
| | 833 | { |
| | 834 | _tComplexLivingString* p = *pl; |
| | 835 | tFeedbackLeveler_setStrength(&p->fbLevU, levStrength); |
| | 836 | tFeedbackLeveler_setStrength(&p->fbLevL, levStrength); |
| | 837 | } |
| | 838 | |
| | 839 | void tComplexLivingString_setLevMode(tComplexLivingString* const pl, int levMode) |
| | 840 | { |
| | 841 | _tComplexLivingString* p = *pl; |
| | 842 | tFeedbackLeveler_setMode(&p->fbLevU, levMode); |
| | 843 | tFeedbackLeveler_setMode(&p->fbLevL, levMode); |
| | 844 | p->levMode=levMode; |
| | 845 | } |
| | 846 | |
| | 847 | float tComplexLivingString_tick(tComplexLivingString* const pl, float input) |
| | 848 | { |
| | 849 | _tComplexLivingString* p = *pl; |
| | 850 | |
| | 851 | // from pickPos upwards=forwards |
| | 852 | float fromLF=tLinearDelay_tickOut(&p->delLF); |
| | 853 | float fromMF=tLinearDelay_tickOut(&p->delMF); |
| | 854 | float fromUF=tLinearDelay_tickOut(&p->delUF); |
| | 855 | float fromUB=tLinearDelay_tickOut(&p->delUB); |
| | 856 | float fromMB=tLinearDelay_tickOut(&p->delMB); |
| | 857 | float fromLB=tLinearDelay_tickOut(&p->delLB); |
| | 858 | |
| | 859 | // into upper part of string, from bridge, going backwards |
| | 860 | float fromBridge=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->bridgeFilter, fromUF))); |
| | 861 | tLinearDelay_tickIn(&p->delUB, fromBridge); |
| | 862 | |
| | 863 | // into pick position, take input and add it into the waveguide, going to come out of middle segment |
| | 864 | tLinearDelay_tickIn(&p->delMB, fromUB+input); |
| | 865 | |
| | 866 | // into lower part of string, from prepPos, going backwards |
| | 867 | float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF); |
| | 868 | float intoLower=p->prepIndex*fromLowerPrep+(1.0f - p->prepIndex)*fromMB; |
| | 869 | tLinearDelay_tickIn(&p->delLB, intoLower); |
| | 870 | |
| | 871 | // into lower part of string, from nut, going forwards toward prep position |
| | 872 | float fromNut=-tFeedbackLeveler_tick(&p->fbLevL, (p->levMode==0?p->decay:1.0f)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->nutFilter, fromLB))); |
| | 873 | tLinearDelay_tickIn(&p->delLF, fromNut); |
| | 874 | |
| | 875 | // into middle part of string, from prep going toward pick position |
| | 876 | float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB); |
| | 877 | float intoMiddle=p->prepIndex*fromUpperPrep+(1.0f - p->prepIndex)*fromLF; |
| | 878 | |
| | 879 | //pick position, take input and add it into the waveguide, going to come out of middle segment |
| | 880 | tLinearDelay_tickIn(&p->delMF, intoMiddle + input); |
| | 881 | |
| | 882 | //take output of middle segment and put it into upper segment connecting to the bridge |
| | 883 | tLinearDelay_tickIn(&p->delUF, fromMF); |
| | 884 | |
| | 885 | // update all delay lengths |
| | 886 | float pickP=tExpSmooth_tick(&p->pickPosSmooth); |
| | 887 | float prepP=tExpSmooth_tick(&p->prepPosSmooth); |
| | 888 | float wLen=tExpSmooth_tick(&p->wlSmooth); |
| | 889 | |
| | 890 | float midLen = (pickP-prepP) * wLen; // the length between the pick and the prep; |
| | 891 | float lowLen = prepP*wLen; // the length from prep to nut |
| | 892 | float upLen = (1.0f-pickP)*wLen; // the length from pick to bridge |
| | 893 | |
| | 894 | |
| | 895 | tLinearDelay_setDelay(&p->delLF, lowLen); |
| | 896 | tLinearDelay_setDelay(&p->delLB, lowLen); |
| | 897 | |
| | 898 | tLinearDelay_setDelay(&p->delMF, midLen); |
| | 899 | tLinearDelay_setDelay(&p->delMB, midLen); |
| | 900 | |
| | 901 | tLinearDelay_setDelay(&p->delUF, upLen); |
| | 902 | tLinearDelay_setDelay(&p->delUB, upLen); |
| | 903 | |
| | 904 | //update this to allow pickup position variation |
| | 905 | p->curr = fromBridge; |
| | 906 | return p->curr; |
| | 907 | } |
| | 908 | |
| | 909 | float tComplexLivingString_sample(tComplexLivingString* const pl) |
| | 910 | { |
| | 911 | _tComplexLivingString* p = *pl; |
| | 912 | return p->curr; |
| | 913 | } |
| | 914 | |
| | 915 | |
| | 916 | |
| 671 | ///Reed Table model | 917 | ///Reed Table model |
| 672 | //default values from STK are 0.6 offset and -0.8 slope | 918 | //default values from STK are 0.6 offset and -0.8 slope |
| 673 | | 919 | |