Unified · Split
Binary file not shown.
Binary file not shown.
| @@ -51,6 +51,30 @@ extern "C" { · 50 unmodified lines | ||
| 51 | 51 | int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff); |
| 52 | 52 | int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh); |
| 53 | 53 | |
| 54 | + // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 55 | + | |
| 56 | + /* Zero Crossing Detector */ | |
| 57 | + typedef struct _tZeroCrossing { | |
| 58 | + int count; | |
| 59 | + int maxWindowSize; | |
| 60 | + int currentWindowSize; | |
| 61 | + float invCurrentWindowSize; | |
| 62 | + float* inBuffer; | |
| 63 | + uint16_t* countBuffer; | |
| 64 | + int prevPosition; | |
| 65 | + int position; | |
| 66 | + } _tZeroCrossing; | |
| 67 | + | |
| 68 | + typedef _tZeroCrossing* tZeroCrossing; | |
| 69 | + | |
| 70 | + void tZeroCrossing_init (tZeroCrossing* const, int maxWindowSize); | |
| 71 | + void tZeroCrossing_free (tZeroCrossing* const); | |
| 72 | + void tZeroCrossing_initToPool (tZeroCrossing* const, int maxWindowSize, tMempool* const); | |
| 73 | + void tZeroCrossing_freeFromPool (tZeroCrossing* const, tMempool* const); | |
| 74 | + | |
| 75 | + float tZeroCrossing_tick (tZeroCrossing* const, float input); | |
| 76 | + void tZeroCrossing_setWindow (tZeroCrossing* const, float windowSize); | |
| 77 | + | |
| 54 | 78 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ |
| 55 | 79 | |
| 56 | 80 | /* PowerEnvelopeFollower */ |
| @@ -86,6 +86,99 @@ int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attack · 85 unmodified lines | ||
| 86 | 86 | } |
| 87 | 87 | |
| 88 | 88 | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | +// zero crossing detector | |
| 93 | + | |
| 94 | +void tZeroCrossing_init (tZeroCrossing* const zc, int maxWindowSize) | |
| 95 | +{ | |
| 96 | + tZeroCrossing_initToPool (zc, maxWindowSize, &leaf.mempool); | |
| 97 | +} | |
| 98 | +void tZeroCrossing_free (tZeroCrossing* const zc) | |
| 99 | +{ | |
| 100 | + tZeroCrossing_freeFromPool (zc, &leaf.mempool); | |
| 101 | +} | |
| 102 | +void tZeroCrossing_initToPool (tZeroCrossing* const zc, int maxWindowSize, tMempool* const mp) | |
| 103 | +{ | |
| 104 | + _tMempool* m = *mp; | |
| 105 | + _tZeroCrossing* z = *zc = (_tZeroCrossing*) mpool_alloc(sizeof(_tZeroCrossing), m); | |
| 106 | + | |
| 107 | + z->count = 0; | |
| 108 | + z->maxWindowSize = maxWindowSize; | |
| 109 | + z->currentWindowSize = maxWindowSize; | |
| 110 | + z->invCurrentWindowSize = 1.0f / maxWindowSize; | |
| 111 | + z->position = 0; | |
| 112 | + z->prevPosition = maxWindowSize; | |
| 113 | + z->inBuffer = (float*) mpool_calloc(sizeof(float) * maxWindowSize, m); | |
| 114 | + z->countBuffer = (uint16_t*) mpool_calloc(sizeof(uint16_t) * maxWindowSize, m); | |
| 115 | +} | |
| 116 | +void tZeroCrossing_freeFromPool (tZeroCrossing* const zc, tMempool* const mp) | |
| 117 | +{ | |
| 118 | + _tMempool* m = *mp; | |
| 119 | + _tZeroCrossing* z = *zc; | |
| 120 | + | |
| 121 | + mpool_free(z, m); | |
| 122 | +} | |
| 123 | + | |
| 124 | +//returns proportion of zero crossings within window size (0.0 would be none in window, 1.0 would be all zero crossings) | |
| 125 | +float tZeroCrossing_tick (tZeroCrossing* const zc, float input) | |
| 126 | +{ | |
| 127 | + _tZeroCrossing* z = *zc; | |
| 128 | + | |
| 129 | + z->inBuffer[z->position] = input; | |
| 130 | + int futurePosition = ((z->position + 1) % z->currentWindowSize); | |
| 131 | + float output = 0.0f; | |
| 132 | + | |
| 133 | + //add new value to count | |
| 134 | + if ((z->inBuffer[z->position] * z->inBuffer[z->prevPosition]) < 0.0f) | |
| 135 | + { | |
| 136 | + //zero crossing happened, add it to the count array | |
| 137 | + z->countBuffer[z->position] = 1; | |
| 138 | + z->count++; | |
| 139 | + } | |
| 140 | + else | |
| 141 | + { | |
| 142 | + z->countBuffer[z->position] = 0; | |
| 143 | + } | |
| 144 | + | |
| 145 | + //remove oldest value from count | |
| 146 | + if (z->countBuffer[futurePosition] > 0) | |
| 147 | + { | |
| 148 | + z->count--; | |
| 149 | + if (z->count < 0) | |
| 150 | + { | |
| 151 | + z->count = 0; | |
| 152 | + } | |
| 153 | + } | |
| 154 | + | |
| 155 | + z->prevPosition = z->position; | |
| 156 | + z->position = futurePosition; | |
| 157 | + | |
| 158 | + output = z->count * z->invCurrentWindowSize; | |
| 159 | + | |
| 160 | + return output; | |
| 161 | +} | |
| 162 | + | |
| 163 | + | |
| 164 | +void tZeroCrossing_setWindow (tZeroCrossing* const zc, float windowSize) | |
| 165 | +{ | |
| 166 | + _tZeroCrossing* z = *zc; | |
| 167 | + if (windowSize <= z->maxWindowSize) | |
| 168 | + { | |
| 169 | + z->currentWindowSize = windowSize; | |
| 170 | + } | |
| 171 | + else | |
| 172 | + { | |
| 173 | + z->currentWindowSize = z->maxWindowSize; | |
| 174 | + } | |
| 175 | + z->invCurrentWindowSize = 1.0f / z->currentWindowSize; | |
| 176 | +} | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 89 | 182 | //=========================================================================== |
| 90 | 183 | /* Power Follower */ |
| 91 | 184 | //=========================================================================== |
| @@ -843,90 +843,79 @@ void tBiQuadSampleRateChanged(tBiQuad* const ft) · 842 unmodified lines | ||
| 843 | 843 | // is calculated when frequency changes. |
| 844 | 844 | void tSVF_init(tSVF* const svff, SVFType type, float freq, float Q) |
| 845 | 845 | { |
| 846 | − _tSVF* svf = *svff = (_tSVF*) leaf_alloc(sizeof(_tSVF)); | |
| 847 | − | |
| 846 | + tSVF_initToPool (svff, type, freq, Q, &leaf.mempool); | |
| 847 | + | |
| 848 | + // or maybe this? | |
| 849 | + /* | |
| 850 | + * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1 | |
| 851 | + */ | |
| 852 | + | |
| 853 | +} | |
| 854 | + | |
| 855 | +void tSVF_free(tSVF* const svff) | |
| 856 | +{ | |
| 857 | + tSVF_freeFromPool (svff, &leaf.mempool); | |
| 858 | +} | |
| 859 | + | |
| 860 | +void tSVF_initToPool (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp) | |
| 861 | +{ | |
| 862 | + _tMempool* m = *mp; | |
| 863 | + _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m); | |
| 864 | + | |
| 848 | 865 | svf->type = type; |
| 849 | − | |
| 866 | + | |
| 850 | 867 | svf->ic1eq = 0; |
| 851 | 868 | svf->ic2eq = 0; |
| 852 | − | |
| 869 | + svf->Q = Q; | |
| 870 | + svf->cutoff = freq; | |
| 853 | 871 | svf->g = tanf(PI * freq * leaf.invSampleRate); |
| 854 | 872 | svf->k = 1.0f/Q; |
| 855 | 873 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); |
| 856 | 874 | svf->a2 = svf->g*svf->a1; |
| 857 | 875 | svf->a3 = svf->g*svf->a2; |
| 876 | + svf->cH = 0.0f; | |
| 877 | + svf->cB = 0.0f; | |
| 878 | + svf->cL = 1.0f; | |
| 858 | 879 | |
| 859 | 880 | if (type == SVFTypeLowpass) |
| 860 | 881 | { |
| 861 | − svf->cH = 0.0f; | |
| 862 | − svf->cB = 0.0f; | |
| 863 | − svf->kAmount = 0.0f; | |
| 864 | − svf->cL = 1.0f; | |
| 882 | + svf->cH = 0.0f; | |
| 883 | + svf->cB = 0.0f; | |
| 884 | + svf->cBK = 0.0f; | |
| 885 | + svf->cL = 1.0f; | |
| 865 | 886 | } |
| 866 | 887 | else if (type == SVFTypeBandpass) |
| 867 | 888 | { |
| 868 | − svf->cH = 0.0f; | |
| 869 | − svf->cB = 1.0f; | |
| 870 | − svf->kAmount = 0.0f; | |
| 871 | − svf->cL = 0.0f; | |
| 889 | + svf->cH = 0.0f; | |
| 890 | + svf->cB = 1.0f; | |
| 891 | + svf->cBK = 0.0f; | |
| 892 | + svf->cL = 0.0f; | |
| 872 | 893 | } |
| 873 | 894 | |
| 874 | 895 | else if (type == SVFTypeHighpass) |
| 875 | 896 | { |
| 876 | − svf->cH = 1.0f; | |
| 877 | − svf->cB = svf->k * -1.0f; | |
| 878 | − svf->kAmount = 1.0f; | |
| 879 | − svf->cL = -1.0f; | |
| 897 | + svf->cH = 1.0f; | |
| 898 | + svf->cB = 0.0f; | |
| 899 | + svf->cBK = -1.0f; | |
| 900 | + svf->cL = -1.0f; | |
| 880 | 901 | } |
| 881 | 902 | |
| 882 | 903 | else if (type == SVFTypeNotch) |
| 883 | 904 | { |
| 884 | − svf->cH = 1.0f; | |
| 885 | − svf->cB = svf->k * -1.0f; | |
| 886 | − svf->kAmount = 1.0f; | |
| 887 | − svf->cL = 0.0f; | |
| 905 | + svf->cH = 1.0f; | |
| 906 | + svf->cB = 0.0f; | |
| 907 | + svf->cBK = -1.0f; | |
| 908 | + svf->cL = 0.0f; | |
| 888 | 909 | } |
| 889 | 910 | |
| 890 | 911 | |
| 891 | 912 | else if (type == SVFTypePeak) |
| 892 | 913 | { |
| 893 | − svf->cH = 1.0f; | |
| 894 | − svf->cB = svf->k * -1.0f; | |
| 895 | − svf->kAmount = 1.0f; | |
| 896 | − svf->cL = -2.0f; | |
| 914 | + svf->cH = 1.0f; | |
| 915 | + svf->cB = 0.0f; | |
| 916 | + svf->cBK = -1.0f; | |
| 917 | + svf->cL = -2.0f; | |
| 897 | 918 | } |
| 898 | − // or maybe this? | |
| 899 | − /* | |
| 900 | − * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1 | |
| 901 | − */ | |
| 902 | − | |
| 903 | −} | |
| 904 | − | |
| 905 | −void tSVF_free(tSVF* const svff) | |
| 906 | −{ | |
| 907 | − _tSVF* svf = *svff; | |
| 908 | − | |
| 909 | − leaf_free(svf); | |
| 910 | −} | |
| 911 | − | |
| 912 | −void tSVF_initToPool (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp) | |
| 913 | −{ | |
| 914 | − _tMempool* m = *mp; | |
| 915 | − _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m); | |
| 916 | − | |
| 917 | − svf->type = type; | |
| 918 | − | |
| 919 | − svf->ic1eq = 0; | |
| 920 | − svf->ic2eq = 0; | |
| 921 | − | |
| 922 | − svf->g = tanf(PI * freq * leaf.invSampleRate); | |
| 923 | − svf->k = 1.0f/Q; | |
| 924 | − svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); | |
| 925 | − svf->a2 = svf->g*svf->a1; | |
| 926 | − svf->a3 = svf->g*svf->a2; | |
| 927 | − svf->cH = 0.0f; | |
| 928 | − svf->cB = 0.0f; | |
| 929 | − svf->cL = 1.0f; | |
| 930 | 919 | } |
| 931 | 920 | |
| 932 | 921 | void tSVF_freeFromPool (tSVF* const svff, tMempool* const mp) |
| @@ -948,13 +937,13 @@ float tSVF_tick(tSVF* const svff, float v0) · 15 unmodified lines | ||
| 948 | 937 | svf->ic1eq = (2.0f * v1) - svf->ic1eq; |
| 949 | 938 | svf->ic2eq = (2.0f * v2) - svf->ic2eq; |
| 950 | 939 | |
| 951 | − return (v0 * svf->cH) + (svf->kAmount * svf->k * v1 * svf->cB) + (v2 * svf->cL); | |
| 940 | + return (v0 * svf->cH) + (v1 * svf->cB) + (svf->k * v1 * svf->cBK) + (v2 * svf->cL); | |
| 952 | 941 | } |
| 953 | 942 | |
| 954 | 943 | void tSVF_setFreq(tSVF* const svff, float freq) |
| 955 | 944 | { |
| 956 | 945 | _tSVF* svf = *svff; |
| 957 | − | |
| 946 | + svf->cutoff = freq; | |
| 958 | 947 | svf->g = tanf(PI * freq * leaf.invSampleRate); |
| 959 | 948 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); |
| 960 | 949 | svf->a2 = svf->g * svf->a1; |
| @@ -964,7 +953,7 @@ void tSVF_setFreq(tSVF* const svff, float freq) · 3 unmodified lines | ||
| 964 | 953 | void tSVF_setQ(tSVF* const svff, float Q) |
| 965 | 954 | { |
| 966 | 955 | _tSVF* svf = *svff; |
| 967 | − | |
| 956 | + svf->Q = Q; | |
| 968 | 957 | svf->k = 1.0f/Q; |
| 969 | 958 | |
| 970 | 959 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); |
| @@ -972,7 +961,7 @@ void tSVF_setQ(tSVF* const svff, float Q) · 1 unmodified line | ||
| 972 | 961 | svf->a3 = svf->g * svf->a2; |
| 973 | 962 | } |
| 974 | 963 | |
| 975 | −void tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q) | |
| 964 | +void tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q) | |
| 976 | 965 | { |
| 977 | 966 | _tSVF* svf = *svff; |
| 978 | 967 | svf->k = 1.0f/Q; |