| @@ -668,6 +668,252 @@ float tLivingString_sample(tLivingString* const pl) · 667 unmodified lines |
| 668 | 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 | 917 | ///Reed Table model |
| 672 | 918 | //default values from STK are 0.6 offset and -0.8 slope |
| 673 | 919 | |