History

added complex living string with separate pluck and prep position

spiricom committed 6 years ago

Commit d5135fd1 parent 77f3ac52 files · +294 −0Browse files

Unified · Split

2 files
  1. leaf/Inc/leaf-physical.h +48 −0
  2. leaf/Src/leaf-physical.c +246 −0
leaf/Inc/leaf-physical.h+48−0
@@ -228,7 +228,55 @@ extern "C" { · 227 unmodified lines
228 void tLivingString_setLevStrength (tLivingString* const, float levStrength);228 void tLivingString_setLevStrength (tLivingString* const, float levStrength);
229 void tLivingString_setLevMode (tLivingString* const, int levMode);229 void tLivingString_setLevMode (tLivingString* const, int levMode);
230 230
231
232
233 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
234
235 /* Complex Living String */
236 typedef struct _tComplexLivingString {
237 float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length
238 float pickPos; // the pick position, dividing the string, in ratio
239 float prepPos; // preparation position, in ratio
240 int prepLower;
241 float prepIndex; // the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj)
242 float dampFreq; // frequency for the bridge LP filter, in Hz
243 float decay; // amplitude damping factor for the string (only active in mode 0)
244 float levMode;
245 float curr;
246 tLinearDelay delLF,delUF, delMF, delMB, delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model
247 tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL;
248 tHighpass DCblockerL, DCblockerU;
249 tFeedbackLeveler fbLevU, fbLevL;
250 tExpSmooth wlSmooth, pickPosSmooth, prepPosSmooth;
251 } _tComplexLivingString;
252
253 typedef _tComplexLivingString* tComplexLivingString;
254
255 void tComplexLivingString_init (tComplexLivingString* const, float freq, float pickPos, float prepPos, float prepIndex,
256 float dampFreq, float decay, float targetLev, float levSmoothFactor,
257 float levStrength, int levMode);
258 void tComplexLivingString_free (tComplexLivingString* const);
259 void tComplexLivingString_initToPool (tComplexLivingString* const, float freq, float pickPos, float prepPos, float prepIndex,
260 float dampFreq, float decay, float targetLev, float levSmoothFactor,
261 float levStrength, int levMode, tMempool* const);
262 void tComplexLivingString_freeFromPool (tComplexLivingString* const, tMempool* const);
263
264 float tComplexLivingString_tick (tComplexLivingString* const, float input);
265 float tComplexLivingString_sample (tComplexLivingString* const);
266 void tComplexLivingString_setFreq (tComplexLivingString* const, float freq);
267 void tComplexLivingString_setWaveLength (tComplexLivingString* const, float waveLength); // in samples
268 void tComplexLivingString_setPickPos (tComplexLivingString* const, float pickPos);
269 void tComplexLivingString_setPrepPos (tComplexLivingString* const, float prepPos);
270 void tComplexLivingString_setPrepIndex (tComplexLivingString* const, float prepIndex);
271 void tComplexLivingString_setDampFreq (tComplexLivingString* const, float dampFreq);
272 void tComplexLivingString_setDecay (tComplexLivingString* const, float decay); // should be near 1.0
273 void tComplexLivingString_setTargetLev (tComplexLivingString* const, float targetLev);
274 void tComplexLivingString_setLevSmoothFactor (tComplexLivingString* const, float levSmoothFactor);
275 void tComplexLivingString_setLevStrength (tComplexLivingString* const, float levStrength);
276 void tComplexLivingString_setLevMode (tComplexLivingString* const, int levMode);
231 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~277 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
278
279
232 280
233 //Reed Table - borrowed from STK281 //Reed Table - borrowed from STK
234 typedef struct _tReedTable {282 typedef struct _tReedTable {
leaf/Src/leaf-physical.c+246−0
@@ -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
676void 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
683void tComplexLivingString_free(tComplexLivingString* const pl)
684{
685 tComplexLivingString_freeFromPool(pl, &leaf.mempool);
686}
687
688void 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
733void 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
759void 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
768void 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
777void 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
786void 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
795void 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
803void 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
812void tComplexLivingString_setDecay(tComplexLivingString* const pl, float decay)
813{
814 _tComplexLivingString* p = *pl;
815 p->decay=decay;
816}
817
818void 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
825void 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
832void 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
839void 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
847float 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
909float tComplexLivingString_sample(tComplexLivingString* const pl)
910{
911 _tComplexLivingString* p = *pl;
912 return p->curr;
913}
914
915
916
671///Reed Table model917///Reed Table model
672//default values from STK are 0.6 offset and -0.8 slope918//default values from STK are 0.6 offset and -0.8 slope
673 919

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