Unified · Split
Binary file not shown.
| @@ -0,0 +1,226 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-analysis.h | ||
| 4 | Created: 25 Oct 2019 10:30:52am | ||
| 5 | Author: Matthew Wang | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_ANALYSIS_H_INCLUDED | ||
| 10 | #define LEAF_ANALYSIS_H_INCLUDED | ||
| 11 | |||
| 12 | #ifdef __cplusplus | ||
| 13 | extern "C" { | ||
| 14 | #endif | ||
| 15 | |||
| 16 | //============================================================================== | ||
| 17 | |||
| 18 | #include "leaf-global.h" | ||
| 19 | #include "leaf-mempool.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | #include "leaf-filters.h" | ||
| 22 | |||
| 23 | //============================================================================== | ||
| 24 | |||
| 25 | /* Envelope Follower */ | ||
| 26 | typedef struct _tEnvelopeFollower | ||
| 27 | { | ||
| 28 | float y; | ||
| 29 | float a_thresh; | ||
| 30 | float d_coeff; | ||
| 31 | |||
| 32 | } tEnvelopeFollower; | ||
| 33 | |||
| 34 | void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff); | ||
| 35 | void tEnvelopeFollower_free (tEnvelopeFollower* const); | ||
| 36 | |||
| 37 | float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x); | ||
| 38 | int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff); | ||
| 39 | int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh); | ||
| 40 | |||
| 41 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 42 | |||
| 43 | /* PowerEnvelopeFollower */ | ||
| 44 | typedef struct _tPowerFollower { | ||
| 45 | float factor, oneminusfactor; | ||
| 46 | float curr; | ||
| 47 | |||
| 48 | } tPowerFollower; | ||
| 49 | |||
| 50 | void tPowerFollower_init (tPowerFollower* const, float factor); | ||
| 51 | void tPowerFollower_free (tPowerFollower* const); | ||
| 52 | float tPowerFollower_tick (tPowerFollower* const, float input); | ||
| 53 | float tPowerFollower_sample (tPowerFollower* const); | ||
| 54 | int tPowerFollower_setFactor (tPowerFollower* const, float factor); | ||
| 55 | |||
| 56 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 57 | |||
| 58 | // ENV~ from PD, modified for LEAF | ||
| 59 | #define MAXOVERLAP 32 | ||
| 60 | #define INITVSTAKEN 64 | ||
| 61 | #define ENV_WINDOW_SIZE 1024 | ||
| 62 | #define ENV_HOP_SIZE 256 | ||
| 63 | |||
| 64 | typedef struct _tEnvPD | ||
| 65 | { | ||
| 66 | float buf[ENV_WINDOW_SIZE + INITVSTAKEN]; | ||
| 67 | uint16_t x_phase; /* number of points since last output */ | ||
| 68 | uint16_t x_period; /* requested period of output */ | ||
| 69 | uint16_t x_realperiod; /* period rounded up to vecsize multiple */ | ||
| 70 | uint16_t x_npoints; /* analysis window size in samples */ | ||
| 71 | float x_result; /* result to output */ | ||
| 72 | float x_sumbuf[MAXOVERLAP]; /* summing buffer */ | ||
| 73 | float x_f; | ||
| 74 | uint16_t windowSize, hopSize, blockSize; | ||
| 75 | uint16_t x_allocforvs; /* extra buffer for DSP vector size */ | ||
| 76 | } tEnvPD; | ||
| 77 | |||
| 78 | void tEnvPD_init (tEnvPD* const, int windowSize, int hopSize, int blockSize); | ||
| 79 | void tEnvPD_free (tEnvPD* const); | ||
| 80 | float tEnvPD_tick (tEnvPD* const); | ||
| 81 | void tEnvPD_processBlock (tEnvPD* const, float* in); | ||
| 82 | |||
| 83 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 84 | |||
| 85 | /* tAttackDetection */ | ||
| 86 | #define DEFBLOCKSIZE 1024 | ||
| 87 | #define DEFTHRESHOLD 6 | ||
| 88 | #define DEFATTACK 10 | ||
| 89 | #define DEFRELEASE 10 | ||
| 90 | |||
| 91 | typedef struct _tAttackDetection | ||
| 92 | { | ||
| 93 | float env; | ||
| 94 | |||
| 95 | //Attack & Release times in msec | ||
| 96 | int atk; | ||
| 97 | int rel; | ||
| 98 | |||
| 99 | //Attack & Release coefficients based on times | ||
| 100 | float atk_coeff; | ||
| 101 | float rel_coeff; | ||
| 102 | |||
| 103 | int blocksize; | ||
| 104 | int samplerate; | ||
| 105 | |||
| 106 | //RMS amplitude of previous block - used to decide if attack is present | ||
| 107 | float prevAmp; | ||
| 108 | |||
| 109 | float threshold; | ||
| 110 | } tAttackDetection; | ||
| 111 | |||
| 112 | void tAttackDetection_init (tAttackDetection* const, int blocksize); | ||
| 113 | void tAttackDetection_init_expanded (tAttackDetection* const, int blocksize, int atk, int rel); | ||
| 114 | void tAttackDetection_free (tAttackDetection* const); | ||
| 115 | |||
| 116 | // set expected input blocksize | ||
| 117 | void tAttackDetection_setBlocksize (tAttackDetection* const, int size); | ||
| 118 | |||
| 119 | // change atkDetector sample rate | ||
| 120 | void tAttackDetection_setSamplerate (tAttackDetection* const, int inRate); | ||
| 121 | |||
| 122 | // set attack time and coeff | ||
| 123 | void tAttackDetection_setAtk (tAttackDetection* const, int inAtk); | ||
| 124 | |||
| 125 | // set release time and coeff | ||
| 126 | void tAttackDetection_setRel (tAttackDetection* const, int inRel); | ||
| 127 | |||
| 128 | // set level above which values are identified as attacks | ||
| 129 | void tAttackDetection_setThreshold (tAttackDetection* const, float thres); | ||
| 130 | |||
| 131 | // find largest transient in input block, return index of attack | ||
| 132 | int tAttackDetection_detect (tAttackDetection* const, float *in); | ||
| 133 | |||
| 134 | //============================================================================== | ||
| 135 | |||
| 136 | // tSNAC: period detector | ||
| 137 | #define SNAC_FRAME_SIZE 1024 // default analysis framesize // should be the same as (or smaller than?) PS_FRAME_SIZE | ||
| 138 | #define DEFOVERLAP 1 // default overlap | ||
| 139 | #define DEFBIAS 0.2f // default bias | ||
| 140 | #define DEFMINRMS 0.003f // default minimum RMS | ||
| 141 | #define SEEK 0.85f // seek-length as ratio of framesize | ||
| 142 | |||
| 143 | typedef struct _tSNAC | ||
| 144 | { | ||
| 145 | float* inputbuf; | ||
| 146 | float* processbuf; | ||
| 147 | float* spectrumbuf; | ||
| 148 | float* biasbuf; | ||
| 149 | uint16_t timeindex; | ||
| 150 | uint16_t framesize; | ||
| 151 | uint16_t overlap; | ||
| 152 | uint16_t periodindex; | ||
| 153 | |||
| 154 | float periodlength; | ||
| 155 | float fidelity; | ||
| 156 | float biasfactor; | ||
| 157 | float minrms; | ||
| 158 | |||
| 159 | } tSNAC; | ||
| 160 | |||
| 161 | void tSNAC_init (tSNAC* const, int overlaparg); // constructor | ||
| 162 | void tSNAC_free (tSNAC* const); // destructor | ||
| 163 | |||
| 164 | void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size); | ||
| 165 | void tSNAC_setOverlap (tSNAC *s, int lap); | ||
| 166 | void tSNAC_setBias (tSNAC *s, float bias); | ||
| 167 | void tSNAC_setMinRMS (tSNAC *s, float rms); | ||
| 168 | |||
| 169 | /*To get freq, perform SAMPLE_RATE/snac_getperiod() */ | ||
| 170 | float tSNAC_getPeriod (tSNAC *s); | ||
| 171 | float tSNAC_getfidelity (tSNAC *s); | ||
| 172 | |||
| 173 | #define DEFPITCHRATIO 2.0f | ||
| 174 | #define DEFTIMECONSTANT 100.0f | ||
| 175 | #define DEFHOPSIZE 64 | ||
| 176 | #define DEFWINDOWSIZE 64 | ||
| 177 | #define FBA 20 | ||
| 178 | #define HPFREQ 40.0f | ||
| 179 | |||
| 180 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 181 | // Period detection | ||
| 182 | typedef struct _tPeriodDetection | ||
| 183 | { | ||
| 184 | tEnvPD env; | ||
| 185 | tSNAC snac; | ||
| 186 | float* inBuffer; | ||
| 187 | float* outBuffer; | ||
| 188 | int frameSize; | ||
| 189 | int bufSize; | ||
| 190 | int framesPerBuffer; | ||
| 191 | int curBlock; | ||
| 192 | int lastBlock; | ||
| 193 | int i; | ||
| 194 | int indexstore; | ||
| 195 | int iLast; | ||
| 196 | int index; | ||
| 197 | float period; | ||
| 198 | |||
| 199 | uint16_t hopSize; | ||
| 200 | uint16_t windowSize; | ||
| 201 | uint8_t fba; | ||
| 202 | |||
| 203 | float timeConstant; | ||
| 204 | float radius; | ||
| 205 | float max; | ||
| 206 | float lastmax; | ||
| 207 | float deltamax; | ||
| 208 | |||
| 209 | }tPeriodDetection; | ||
| 210 | |||
| 211 | void tPeriodDetection_init (tPeriodDetection* const, float* in, float* out, int bufSize, int frameSize); | ||
| 212 | void tPeriodDetection_free (tPeriodDetection* const); | ||
| 213 | |||
| 214 | float tPeriodDetection_findPeriod (tPeriodDetection* const, float sample); | ||
| 215 | void tPeriodDetection_setHopSize (tPeriodDetection* p, int hs); | ||
| 216 | void tPeriodDetection_setWindowSize (tPeriodDetection* p, int ws); | ||
| 217 | |||
| 218 | //============================================================================== | ||
| 219 | |||
| 220 | #ifdef __cplusplus | ||
| 221 | } | ||
| 222 | #endif | ||
| 223 | |||
| 224 | #endif // LEAF_ANALYSIS_H_INCLUDED | ||
| 225 | |||
| 226 | //============================================================================== | ||
| @@ -1,64 +0,0 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | leaf-crusher.h | ||
| 5 | Created: 7 Feb 2019 10:58:22am | ||
| 6 | Author: airship | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef LEAF_CRUSHER_H_INCLUDED | ||
| 12 | #define LEAF_CRUSHER_H_INCLUDED | ||
| 13 | |||
| 14 | |||
| 15 | #ifdef __cplusplus | ||
| 16 | extern "C" { | ||
| 17 | #endif | ||
| 18 | |||
| 19 | //============================================================================== | ||
| 20 | |||
| 21 | #include "leaf-global.h" | ||
| 22 | #include "leaf-math.h" | ||
| 23 | |||
| 24 | //============================================================================== | ||
| 25 | |||
| 26 | typedef struct _tCrusher | ||
| 27 | { | ||
| 28 | float srr; | ||
| 29 | float mult, div; | ||
| 30 | float rnd; | ||
| 31 | |||
| 32 | uint32_t op; //which bitwise operation (0-7) | ||
| 33 | |||
| 34 | float gain; | ||
| 35 | |||
| 36 | } tCrusher; | ||
| 37 | |||
| 38 | |||
| 39 | void tCrusher_init (tCrusher* const); | ||
| 40 | void tCrusher_free (tCrusher* const); | ||
| 41 | |||
| 42 | float tCrusher_tick (tCrusher* const, float input); | ||
| 43 | |||
| 44 | // 0.0 - 1.0 | ||
| 45 | void tCrusher_setOperation (tCrusher* const, float op); | ||
| 46 | |||
| 47 | // 0.0 - 1.0 | ||
| 48 | void tCrusher_setQuality (tCrusher* const, float val); | ||
| 49 | |||
| 50 | // what division to round to | ||
| 51 | void tCrusher_setRound (tCrusher* const, float rnd); | ||
| 52 | |||
| 53 | // sampling ratio | ||
| 54 | void tCrusher_setSamplingRatio (tCrusher* const, float ratio); | ||
| 55 | |||
| 56 | //============================================================================== | ||
| 57 | |||
| 58 | #ifdef __cplusplus | ||
| 59 | } | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #endif // LEAF_WAVEFOLDER_H_INCLUDED | ||
| 63 | |||
| 64 | //============================================================================== | ||
| @@ -48,7 +48,7 @@ float tDelay_getLastIn (tDelay* const); · 47 unmodified lines | |||
| 48 | //============================================================================== | 48 | //============================================================================== |
| 49 | 49 | ||
| 50 | /* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */ | 50 | /* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */ |
| 51 | typedef struct _tDelayL | 51 | typedef struct _tLinearDelay |
| 52 | { | 52 | { |
| 53 | float gain; | 53 | float gain; |
| 54 | float* buff; | 54 | float* buff; |
| @@ -63,26 +63,26 @@ typedef struct _tDelayL · 8 unmodified lines | |||
| 63 | 63 | ||
| 64 | float alpha, omAlpha; | 64 | float alpha, omAlpha; |
| 65 | 65 | ||
| 66 | } tDelayL; | 66 | } tLinearDelay; |
| 67 | 67 | ||
| 68 | void tDelayL_init (tDelayL* const, float delay, uint32_t maxDelay); | 68 | void tLinearDelay_init (tLinearDelay* const, float delay, uint32_t maxDelay); |
| 69 | void tDelayL_free (tDelayL* const); | 69 | void tLinearDelay_free (tLinearDelay* const); |
| 70 | 70 | ||
| 71 | int tDelayL_setDelay (tDelayL* const, float delay); | 71 | int tLinearDelay_setDelay (tLinearDelay* const, float delay); |
| 72 | float tDelayL_getDelay (tDelayL* const); | 72 | float tLinearDelay_getDelay (tLinearDelay* const); |
| 73 | void tDelayL_tapIn (tDelayL* const, float in, uint32_t tapDelay); | 73 | void tLinearDelay_tapIn (tLinearDelay* const, float in, uint32_t tapDelay); |
| 74 | float tDelayL_tapOut (tDelayL* const, float tapDelay); | 74 | float tLinearDelay_tapOut (tLinearDelay* const, float tapDelay); |
| 75 | float tDelayL_addTo (tDelayL* const, float value, uint32_t tapDelay); | 75 | float tLinearDelay_addTo (tLinearDelay* const, float value, uint32_t tapDelay); |
| 76 | float tDelayL_tick (tDelayL* const, float sample); | 76 | float tLinearDelay_tick (tLinearDelay* const, float sample); |
| 77 | void tDelayL_tickIn (tDelayL* const d, float input); | 77 | void tLinearDelay_tickIn (tLinearDelay* const d, float input); |
| 78 | float tDelayL_tickOut (tDelayL* const d); | 78 | float tLinearDelay_tickOut (tLinearDelay* const d); |
| 79 | float tDelayL_getLastOut (tDelayL* const); | 79 | float tLinearDelay_getLastOut (tLinearDelay* const); |
| 80 | float tDelayL_getLastIn (tDelayL* const); | 80 | float tLinearDelay_getLastIn (tLinearDelay* const); |
| 81 | 81 | ||
| 82 | //============================================================================== | 82 | //============================================================================== |
| 83 | 83 | ||
| 84 | /* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */ | 84 | /* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */ |
| 85 | typedef struct _tDelayA | 85 | typedef struct _tAllpassDelay |
| 86 | { | 86 | { |
| 87 | float gain; | 87 | float gain; |
| 88 | float* buff; | 88 | float* buff; |
| @@ -99,19 +99,19 @@ typedef struct _tDelayA · 10 unmodified lines | |||
| 99 | 99 | ||
| 100 | float apInput; | 100 | float apInput; |
| 101 | 101 | ||
| 102 | } tDelayA; | 102 | } tAllpassDelay; |
| 103 | 103 | ||
| 104 | void tDelayA_init (tDelayA* const, float delay, uint32_t maxDelay); | 104 | void tAllpassDelay_init (tAllpassDelay* const, float delay, uint32_t maxDelay); |
| 105 | void tDelayA_free (tDelayA* const); | 105 | void tAllpassDelay_free (tAllpassDelay* const); |
| 106 | 106 | ||
| 107 | int tDelayA_setDelay (tDelayA* const, float delay); | 107 | int tAllpassDelay_setDelay (tAllpassDelay* const, float delay); |
| 108 | float tDelayA_getDelay (tDelayA* const); | 108 | float tAllpassDelay_getDelay (tAllpassDelay* const); |
| 109 | void tDelayA_tapIn (tDelayA* const, float in, uint32_t tapDelay); | 109 | void tAllpassDelay_tapIn (tAllpassDelay* const, float in, uint32_t tapDelay); |
| 110 | float tDelayA_tapOut (tDelayA* const, uint32_t tapDelay); | 110 | float tAllpassDelay_tapOut (tAllpassDelay* const, uint32_t tapDelay); |
| 111 | float tDelayA_addTo (tDelayA* const, float value, uint32_t tapDelay); | 111 | float tAllpassDelay_addTo (tAllpassDelay* const, float value, uint32_t tapDelay); |
| 112 | float tDelayA_tick (tDelayA* const, float sample); | 112 | float tAllpassDelay_tick (tAllpassDelay* const, float sample); |
| 113 | float tDelayA_getLastOut (tDelayA* const); | 113 | float tAllpassDelay_getLastOut (tAllpassDelay* const); |
| 114 | float tDelayA_getLastIn (tDelayA* const); | 114 | float tAllpassDelay_getLastIn (tAllpassDelay* const); |
| 115 | 115 | ||
| 116 | //============================================================================== | 116 | //============================================================================== |
| 117 | 117 | ||
| @@ -0,0 +1,99 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-distortion.h | ||
| 4 | Created: 25 Oct 2019 10:23:28am | ||
| 5 | Author: Matthew Wang | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_DISTORTION_H_INCLUDED | ||
| 10 | #define LEAF_DISTORTION_H_INCLUDED | ||
| 11 | |||
| 12 | #ifdef __cplusplus | ||
| 13 | extern "C" { | ||
| 14 | #endif | ||
| 15 | |||
| 16 | //============================================================================== | ||
| 17 | |||
| 18 | #include "leaf-global.h" | ||
| 19 | #include "leaf-mempool.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | |||
| 22 | //============================================================================== | ||
| 23 | |||
| 24 | /* tLockhartWavefolder */ | ||
| 25 | |||
| 26 | typedef struct _tLockhartWavefolder | ||
| 27 | { | ||
| 28 | double Ln1; | ||
| 29 | double Fn1; | ||
| 30 | float xn1; | ||
| 31 | |||
| 32 | } tLockhartWavefolder; | ||
| 33 | |||
| 34 | void tLockhartWavefolder_init (tLockhartWavefolder* const); | ||
| 35 | void tLockhartWavefolder_free (tLockhartWavefolder* const); | ||
| 36 | |||
| 37 | float tLockhartWavefolder_tick (tLockhartWavefolder* const, float samp); | ||
| 38 | |||
| 39 | //============================================================================== | ||
| 40 | |||
| 41 | typedef struct _tCrusher | ||
| 42 | { | ||
| 43 | float srr; | ||
| 44 | float mult, div; | ||
| 45 | float rnd; | ||
| 46 | |||
| 47 | uint32_t op; //which bitwise operation (0-7) | ||
| 48 | |||
| 49 | float gain; | ||
| 50 | |||
| 51 | } tCrusher; | ||
| 52 | |||
| 53 | |||
| 54 | void tCrusher_init (tCrusher* const); | ||
| 55 | void tCrusher_free (tCrusher* const); | ||
| 56 | |||
| 57 | float tCrusher_tick (tCrusher* const, float input); | ||
| 58 | |||
| 59 | // 0.0 - 1.0 | ||
| 60 | void tCrusher_setOperation (tCrusher* const, float op); | ||
| 61 | |||
| 62 | // 0.0 - 1.0 | ||
| 63 | void tCrusher_setQuality (tCrusher* const, float val); | ||
| 64 | |||
| 65 | // what division to round to | ||
| 66 | void tCrusher_setRound (tCrusher* const, float rnd); | ||
| 67 | |||
| 68 | // sampling ratio | ||
| 69 | void tCrusher_setSamplingRatio (tCrusher* const, float ratio); | ||
| 70 | |||
| 71 | //============================================================================== | ||
| 72 | |||
| 73 | typedef struct _tOversampler | ||
| 74 | { | ||
| 75 | int ratio; | ||
| 76 | float* pCoeffs; | ||
| 77 | float* upState; | ||
| 78 | float* downState; | ||
| 79 | int numTaps; | ||
| 80 | int phaseLength; | ||
| 81 | } tOversampler; | ||
| 82 | |||
| 83 | void tOversampler_init(tOversampler* const, int order, oBool extraQuality); | ||
| 84 | void tOversampler_free(tOversampler* const); | ||
| 85 | void tOversampler_upsample(tOversampler* const, float input, float* output); | ||
| 86 | float tOversampler_downsample(tOversampler *const os, float* input); | ||
| 87 | float tOversampler_tick(tOversampler* const, float input, float (*effectTick)(float)); | ||
| 88 | int tOversampler_getLatency(tOversampler* const os); | ||
| 89 | |||
| 90 | //============================================================================== | ||
| 91 | |||
| 92 | #ifdef __cplusplus | ||
| 93 | } | ||
| 94 | #endif | ||
| 95 | |||
| 96 | #endif // LEAF_DISTORTION_H_INCLUDED | ||
| 97 | |||
| 98 | //============================================================================== | ||
| 99 | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-dynamics.h | ||
| 4 | Created: 30 Nov 2018 11:57:05am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_DYNAMICS_H_INCLUDED | ||
| 10 | #define LEAF_DYNAMICS_H_INCLUDED | ||
| 11 | |||
| 12 | |||
| 13 | #ifdef __cplusplus | ||
| 14 | extern "C" { | ||
| 15 | #endif | ||
| 16 | |||
| 17 | //============================================================================== | ||
| 18 | |||
| 19 | #include "leaf-global.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | #include "leaf-analysis.h" | ||
| 22 | |||
| 23 | //============================================================================== | ||
| 24 | |||
| 25 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 26 | |||
| 27 | /* Compressor */ | ||
| 28 | typedef struct _tCompressor | ||
| 29 | { | ||
| 30 | float tauAttack, tauRelease; | ||
| 31 | float T, R, W, M; // Threshold, compression Ratio, decibel Width of knee transition, decibel Make-up gain | ||
| 32 | |||
| 33 | float x_G[2], y_G[2], x_T[2], y_T[2]; | ||
| 34 | |||
| 35 | oBool isActive; | ||
| 36 | |||
| 37 | }tCompressor; | ||
| 38 | |||
| 39 | void tCompressor_init (tCompressor* const); | ||
| 40 | void tCompressor_free (tCompressor* const); | ||
| 41 | float tCompressor_tick (tCompressor* const, float input); | ||
| 42 | |||
| 43 | /// | ||
| 44 | /* Feedback leveller */ | ||
| 45 | // An auto VCA that you put into a feedback circuit to make it stay at the same level. | ||
| 46 | // It can enforce level bidirectionally (amplifying and attenuating as needed) or | ||
| 47 | // just attenutating. The former option allows for infinite sustain strings, for example, while | ||
| 48 | // The latter option allows for decaying strings, which can never exceed | ||
| 49 | // a specific level. | ||
| 50 | |||
| 51 | typedef struct _tFeedbackLeveler { | ||
| 52 | float targetLevel; // target power level | ||
| 53 | float strength; // how strongly level difference affects the VCA | ||
| 54 | int mode; // 0 for upwards limiting only, 1 for biderctional limiting | ||
| 55 | float curr; | ||
| 56 | tPowerFollower pwrFlw; // internal power follower needed for level tracking | ||
| 57 | |||
| 58 | } tFeedbackLeveler; | ||
| 59 | |||
| 60 | void tFeedbackLeveler_init (tFeedbackLeveler* const, float targetLevel, float factor, float strength, int mode); | ||
| 61 | void tFeedbackLeveler_free (tFeedbackLeveler* const); | ||
| 62 | |||
| 63 | float tFeedbackLeveler_tick (tFeedbackLeveler* const, float input); | ||
| 64 | float tFeedbackLeveler_sample (tFeedbackLeveler* const); | ||
| 65 | void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const, float TargetLevel); | ||
| 66 | void tFeedbackLeveler_setFactor (tFeedbackLeveler* const, float factor); | ||
| 67 | void tFeedbackLeveler_setMode (tFeedbackLeveler* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting | ||
| 68 | void tFeedbackLeveler_setStrength (tFeedbackLeveler* const, float strength); | ||
| 69 | |||
| 70 | |||
| 71 | //============================================================================== | ||
| 72 | |||
| 73 | #ifdef __cplusplus | ||
| 74 | } | ||
| 75 | #endif | ||
| 76 | |||
| 77 | #endif // LEAF_DYNAMICS_H_INCLUDED | ||
| 78 | |||
| 79 | //============================================================================== | ||
| @@ -0,0 +1,251 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-effects.h | ||
| 4 | Created: 20 Jan 2017 12:01:54pm | ||
| 5 | Author: Michael R Mulshine | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_EFFECTS_H_INCLUDED | ||
| 10 | #define LEAF_EFFECTS_H_INCLUDED | ||
| 11 | |||
| 12 | #ifdef __cplusplus | ||
| 13 | extern "C" { | ||
| 14 | #endif | ||
| 15 | |||
| 16 | //============================================================================== | ||
| 17 | |||
| 18 | #include "leaf-global.h" | ||
| 19 | #include "leaf-math.h" | ||
| 20 | #include "leaf-analysis.h" | ||
| 21 | |||
| 22 | //============================================================================== | ||
| 23 | |||
| 24 | /* tTalkbox */ | ||
| 25 | #define NUM_TALKBOX_PARAM 4 | ||
| 26 | |||
| 27 | typedef struct _tTalkbox | ||
| 28 | { | ||
| 29 | float param[NUM_TALKBOX_PARAM]; | ||
| 30 | |||
| 31 | int bufsize; | ||
| 32 | float* car0; | ||
| 33 | float* car1; | ||
| 34 | float* window; | ||
| 35 | float* buf0; | ||
| 36 | float* buf1; | ||
| 37 | |||
| 38 | float emphasis; | ||
| 39 | int32_t K, N, O, pos; | ||
| 40 | float wet, dry, FX; | ||
| 41 | float d0, d1, d2, d3, d4; | ||
| 42 | float u0, u1, u2, u3, u4; | ||
| 43 | |||
| 44 | } tTalkbox; | ||
| 45 | |||
| 46 | void tTalkbox_init (tTalkbox* const, int bufsize); | ||
| 47 | void tTalkbox_free (tTalkbox* const); | ||
| 48 | float tTalkbox_tick (tTalkbox* const, float synth, float voice); | ||
| 49 | void tTalkbox_update (tTalkbox* const); | ||
| 50 | void tTalkbox_suspend (tTalkbox* const); | ||
| 51 | void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g); | ||
| 52 | void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o); | ||
| 53 | void tTalkbox_setQuality (tTalkbox* const, float quality); | ||
| 54 | |||
| 55 | //============================================================================== | ||
| 56 | |||
| 57 | /* tVocoder */ | ||
| 58 | #define NUM_VOCODER_PARAM 8 | ||
| 59 | #define NBANDS 16 | ||
| 60 | |||
| 61 | typedef struct _tVocoder | ||
| 62 | { | ||
| 63 | float param[NUM_VOCODER_PARAM]; | ||
| 64 | |||
| 65 | float gain; //output level | ||
| 66 | float thru, high; //hf thru | ||
| 67 | float kout; //downsampled output | ||
| 68 | int32_t kval; //downsample counter | ||
| 69 | int32_t nbnd; //number of bands | ||
| 70 | |||
| 71 | //filter coeffs and buffers - seems it's faster to leave this global than make local copy | ||
| 72 | float f[NBANDS][13]; //[0-8][0 1 2 | 0 1 2 3 | 0 1 2 3 | val rate] | ||
| 73 | |||
| 74 | } tVocoder; | ||
| 75 | |||
| 76 | void tVocoder_init (tVocoder* const); | ||
| 77 | void tVocoder_free (tVocoder* const); | ||
| 78 | float tVocoder_tick (tVocoder* const, float synth, float voice); | ||
| 79 | void tVocoder_update (tVocoder* const); | ||
| 80 | void tVocoder_suspend (tVocoder* const); | ||
| 81 | |||
| 82 | //============================================================================== | ||
| 83 | |||
| 84 | |||
| 85 | //============================================================================== | ||
| 86 | |||
| 87 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 88 | |||
| 89 | /* tSOLAD : pitch shifting algorithm that underlies tPitchShifter etc */ | ||
| 90 | #define LOOPSIZE (2048*2) // (4096*2) // loop size must be power of two | ||
| 91 | #define LOOPMASK (LOOPSIZE - 1) | ||
| 92 | #define PITCHFACTORDEFAULT 1.0f | ||
| 93 | #define INITPERIOD 64.0f | ||
| 94 | #define MAXPERIOD (float)((LOOPSIZE - w->blocksize) * 0.8f) | ||
| 95 | #define MINPERIOD 8.0f | ||
| 96 | |||
| 97 | typedef struct _tSOLAD | ||
| 98 | { | ||
| 99 | uint16_t timeindex; // current reference time, write index | ||
| 100 | uint16_t blocksize; // signal input / output block size | ||
| 101 | float pitchfactor; // pitch factor between 0.25 and 4 | ||
| 102 | float readlag; // read pointer's lag behind write pointer | ||
| 103 | float period; // period length in input signal | ||
| 104 | float jump; // read pointer jump length and direction | ||
| 105 | float xfadelength; // crossfade length expressed at input sample rate | ||
| 106 | float xfadevalue; // crossfade phase and value | ||
| 107 | |||
| 108 | float* delaybuf; | ||
| 109 | |||
| 110 | } tSOLAD; | ||
| 111 | |||
| 112 | void tSOLAD_init (tSOLAD* const); | ||
| 113 | void tSOLAD_free (tSOLAD* const); | ||
| 114 | |||
| 115 | // send one block of input samples, receive one block of output samples | ||
| 116 | void tSOLAD_ioSamples (tSOLAD *w, float* in, float* out, int blocksize); | ||
| 117 | |||
| 118 | // set periodicity analysis data | ||
| 119 | void tSOLAD_setPeriod (tSOLAD *w, float period); | ||
| 120 | |||
| 121 | // set pitch factor between 0.25 and 4 | ||
| 122 | void tSOLAD_setPitchFactor (tSOLAD *w, float pitchfactor); | ||
| 123 | |||
| 124 | // force readpointer lag | ||
| 125 | void tSOLAD_setReadLag (tSOLAD *w, float readlag); | ||
| 126 | |||
| 127 | // reset state variables | ||
| 128 | void tSOLAD_resetState (tSOLAD *w); | ||
| 129 | |||
| 130 | // Pitch shifter | ||
| 131 | typedef struct _tPitchShifter | ||
| 132 | { | ||
| 133 | tEnvPD env; | ||
| 134 | tSNAC snac; | ||
| 135 | tSOLAD sola; | ||
| 136 | tHighpass hp; | ||
| 137 | |||
| 138 | float* inBuffer; | ||
| 139 | float* outBuffer; | ||
| 140 | int frameSize; | ||
| 141 | int bufSize; | ||
| 142 | int framesPerBuffer; | ||
| 143 | int curBlock; | ||
| 144 | int lastBlock; | ||
| 145 | int index; | ||
| 146 | |||
| 147 | uint16_t hopSize; | ||
| 148 | uint16_t windowSize; | ||
| 149 | uint8_t fba; | ||
| 150 | |||
| 151 | float pitchFactor; | ||
| 152 | float timeConstant; | ||
| 153 | float radius; | ||
| 154 | float max; | ||
| 155 | float lastmax; | ||
| 156 | float deltamax; | ||
| 157 | |||
| 158 | } tPitchShifter; | ||
| 159 | |||
| 160 | void tPitchShifter_init (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize); | ||
| 161 | void tPitchShifter_free (tPitchShifter* const); | ||
| 162 | |||
| 163 | float tPitchShifter_tick (tPitchShifter* const, float sample); | ||
| 164 | float tPitchShifterToFreq_tick (tPitchShifter* const, float sample, float freq); | ||
| 165 | float tPitchShifterToFunc_tick (tPitchShifter* const, float sample, float (*fun)(float)); | ||
| 166 | void tPitchShifter_ioSamples_toFreq (tPitchShifter* const, float* in, float* out, int size, float toFreq); | ||
| 167 | void tPitchShifter_ioSamples_toPeriod(tPitchShifter* const, float* in, float* out, int size, float toPeriod); | ||
| 168 | void tPitchShifter_ioSamples_toFunc (tPitchShifter* const, float* in, float* out, int size, float (*fun)(float)); | ||
| 169 | void tPitchShifter_setPitchFactor (tPitchShifter* const, float pf); | ||
| 170 | void tPitchShifter_setTimeConstant (tPitchShifter* const, float tc); | ||
| 171 | void tPitchShifter_setHopSize (tPitchShifter* const, int hs); | ||
| 172 | void tPitchShifter_setWindowSize (tPitchShifter* const, int ws); | ||
| 173 | float tPitchShifter_getPeriod (tPitchShifter* const); | ||
| 174 | |||
| 175 | //============================================================================== | ||
| 176 | |||
| 177 | // Pitch shift | ||
| 178 | typedef struct _tPitchShift | ||
| 179 | { | ||
| 180 | tSOLAD sola; | ||
| 181 | tHighpass hp; | ||
| 182 | tPeriodDetection* p; | ||
| 183 | |||
| 184 | float* outBuffer; | ||
| 185 | int frameSize; | ||
| 186 | int bufSize; | ||
| 187 | |||
| 188 | int framesPerBuffer; | ||
| 189 | int curBlock; | ||
| 190 | int lastBlock; | ||
| 191 | int index; | ||
| 192 | |||
| 193 | float pitchFactor; | ||
| 194 | float timeConstant; | ||
| 195 | float radius; | ||
| 196 | } tPitchShift; | ||
| 197 | |||
| 198 | void tPitchShift_init (tPitchShift* const,tPeriodDetection* const, float* out, int bufSize); | ||
| 199 | void tPitchShift_free (tPitchShift* const); | ||
| 200 | |||
| 201 | float tPitchShift_shift (tPitchShift* const); | ||
| 202 | float tPitchShift_shiftToFunc (tPitchShift* const, float (*fun)(float)); | ||
| 203 | float tPitchShift_shiftToFreq (tPitchShift* const, float freq); | ||
| 204 | void tPitchShift_setPitchFactor (tPitchShift* const, float pf); | ||
| 205 | |||
| 206 | //============================================================================== | ||
| 207 | |||
| 208 | #define FORD 7 | ||
| 209 | #define FORMANT_BUFFER_SIZE 2048 | ||
| 210 | |||
| 211 | typedef struct _tFormantShifter | ||
| 212 | { | ||
| 213 | int ford; | ||
| 214 | int bufsize; | ||
| 215 | float falph; | ||
| 216 | float flamb; | ||
| 217 | float* fk; | ||
| 218 | float* fb; | ||
| 219 | float* fc; | ||
| 220 | float* frb; | ||
| 221 | float* frc; | ||
| 222 | float* fsig; | ||
| 223 | float* fsmooth; | ||
| 224 | float fhp; | ||
| 225 | float flp; | ||
| 226 | float flpa; | ||
| 227 | float** fbuff; | ||
| 228 | float* ftvec; | ||
| 229 | float fmute; | ||
| 230 | float fmutealph; | ||
| 231 | unsigned int cbi; | ||
| 232 | |||
| 233 | } tFormantShifter; | ||
| 234 | |||
| 235 | void tFormantShifter_init (tFormantShifter* const, int bufsize, int order); | ||
| 236 | void tFormantShifter_free (tFormantShifter* const); | ||
| 237 | |||
| 238 | float tFormantShifter_tick (tFormantShifter* const, float input, float fwarp); | ||
| 239 | float tFormantShifter_remove (tFormantShifter* const, float input); | ||
| 240 | float tFormantShifter_add (tFormantShifter* const, float input, float fwarp); | ||
| 241 | void tFormantShifter_ioSamples (tFormantShifter* const, float* in, float* out, int size, float fwarp); | ||
| 242 | |||
| 243 | //============================================================================== | ||
| 244 | |||
| 245 | #ifdef __cplusplus | ||
| 246 | } | ||
| 247 | #endif | ||
| 248 | |||
| 249 | #endif // LEAF_EFFECTS_H_INCLUDED | ||
| 250 | |||
| 251 | //============================================================================== | ||
| @@ -1,12 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * leaf-WDF.h | 2 | * leaf-electrical.h |
| 3 | * | 3 | * |
| 4 | * Created on: Sep 25, 2019 | 4 | * Created on: Sep 25, 2019 |
| 5 | * Author: jeffsnyder | 5 | * Author: jeffsnyder |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #ifndef LEAF_INC_LEAF_WDF_H_ | 8 | #ifndef LEAF_INC_LEAF_ELECTRICAL_H_ |
| 9 | #define LEAF_INC_LEAF_WDF_H_ | 9 | #define LEAF_INC_LEAF_ELECTRICAL_H_ |
| 10 | 10 | ||
| 11 | #ifdef __cplusplus | 11 | #ifdef __cplusplus |
| 12 | extern "C" { | 12 | extern "C" { |
| @@ -86,4 +86,4 @@ float tWDF_getCurrent(tWDF* const r); · 73 unmodified lines | |||
| 86 | } | 86 | } |
| 87 | #endif | 87 | #endif |
| 88 | 88 | ||
| 89 | #endif /* LEAF_INC_LEAF_WDF_H_ */ | 89 | #endif /* LEAF_INC_LEAF_ELECTRICAL_H_ */ |
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | leaf-envelopes.h | ||
| 5 | Created: 20 Jan 2017 12:02:17pm | ||
| 6 | Author: Michael R Mulshine | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef LEAF_ENVELOPES_H_INCLUDED | ||
| 12 | #define LEAF_ENVELOPES_H_INCLUDED | ||
| 13 | |||
| 14 | #ifdef __cplusplus | ||
| 15 | extern "C" { | ||
| 16 | #endif | ||
| 17 | |||
| 18 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 19 | |||
| 20 | #include "leaf-math.h" | ||
| 21 | #include "leaf-filters.h" | ||
| 22 | #include "leaf-delay.h" | ||
| 23 | |||
| 24 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 25 | |||
| 26 | /* Attack-Decay envelope */ | ||
| 27 | typedef struct _tEnvelope { | ||
| 28 | |||
| 29 | const float *exp_buff; | ||
| 30 | const float *inc_buff; | ||
| 31 | uint32_t buff_size; | ||
| 32 | |||
| 33 | float next; | ||
| 34 | |||
| 35 | float attackInc, decayInc, rampInc; | ||
| 36 | |||
| 37 | oBool inAttack, inDecay, inRamp; | ||
| 38 | |||
| 39 | oBool loop; | ||
| 40 | |||
| 41 | float gain, rampPeak; | ||
| 42 | |||
| 43 | float attackPhase, decayPhase, rampPhase; | ||
| 44 | |||
| 45 | } tEnvelope; | ||
| 46 | |||
| 47 | void tEnvelope_init (tEnvelope* const, float attack, float decay, oBool loop); | ||
| 48 | void tEnvelope_free (tEnvelope* const); | ||
| 49 | |||
| 50 | float tEnvelope_tick (tEnvelope* const); | ||
| 51 | int tEnvelope_setAttack (tEnvelope* const, float attack); | ||
| 52 | int tEnvelope_setDecay (tEnvelope* const, float decay); | ||
| 53 | int tEnvelope_loop (tEnvelope* const, oBool loop); | ||
| 54 | int tEnvelope_on (tEnvelope* const, float velocity); | ||
| 55 | |||
| 56 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 57 | |||
| 58 | /* ADSR */ | ||
| 59 | typedef struct _tADSR | ||
| 60 | { | ||
| 61 | const float *exp_buff; | ||
| 62 | const float *inc_buff; | ||
| 63 | uint32_t buff_size; | ||
| 64 | |||
| 65 | float next; | ||
| 66 | |||
| 67 | float attackInc, decayInc, releaseInc, rampInc; | ||
| 68 | |||
| 69 | oBool inAttack, inDecay, inSustain, inRelease, inRamp; | ||
| 70 | |||
| 71 | float sustain, gain, rampPeak, releasePeak; | ||
| 72 | |||
| 73 | float attackPhase, decayPhase, releasePhase, rampPhase; | ||
| 74 | |||
| 75 | } tADSR; | ||
| 76 | |||
| 77 | void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release); | ||
| 78 | void tADSR_free (tADSR* const); | ||
| 79 | |||
| 80 | float tADSR_tick (tADSR* const); | ||
| 81 | int tADSR_setAttack (tADSR* const, float attack); | ||
| 82 | int tADSR_setDecay (tADSR* const, float decay); | ||
| 83 | int tADSR_setSustain(tADSR* const, float sustain); | ||
| 84 | int tADSR_setRelease(tADSR* const, float release); | ||
| 85 | int tADSR_on (tADSR* const, float velocity); | ||
| 86 | int tADSR_off (tADSR* const); | ||
| 87 | |||
| 88 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 89 | |||
| 90 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 91 | |||
| 92 | /* Ramp */ | ||
| 93 | typedef struct _tRamp { | ||
| 94 | float inc; | ||
| 95 | float inv_sr_ms; | ||
| 96 | float minimum_time; | ||
| 97 | float curr,dest; | ||
| 98 | float time; | ||
| 99 | int samples_per_tick; | ||
| 100 | |||
| 101 | } tRamp; | ||
| 102 | |||
| 103 | void tRamp_init (tRamp* const, float time, int samplesPerTick); | ||
| 104 | void tRamp_free (tRamp* const); | ||
| 105 | |||
| 106 | float tRamp_tick (tRamp* const); | ||
| 107 | float tRamp_sample (tRamp* const); | ||
| 108 | int tRamp_setTime (tRamp* const, float time); | ||
| 109 | int tRamp_setDest (tRamp* const, float dest); | ||
| 110 | int tRamp_setVal (tRamp* const, float val); | ||
| 111 | |||
| 112 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 113 | |||
| 114 | /* Exponential Smoother */ | ||
| 115 | typedef struct _tExpSmooth { | ||
| 116 | float factor, oneminusfactor; | ||
| 117 | float curr,dest; | ||
| 118 | |||
| 119 | } tExpSmooth; | ||
| 120 | |||
| 121 | void tExpSmooth_init (tExpSmooth* const, float val, float factor); | ||
| 122 | void tExpSmooth_free (tExpSmooth* const); | ||
| 123 | |||
| 124 | float tExpSmooth_tick (tExpSmooth* const); | ||
| 125 | float tExpSmooth_sample (tExpSmooth* const); | ||
| 126 | int tExpSmooth_setFactor (tExpSmooth* const, float factor); | ||
| 127 | int tExpSmooth_setDest (tExpSmooth* const, float dest); | ||
| 128 | int tExpSmooth_setVal (tExpSmooth* const, float val); | ||
| 129 | |||
| 130 | #ifdef __cplusplus | ||
| 131 | } | ||
| 132 | #endif | ||
| 133 | |||
| 134 | #endif // LEAF_ENVELOPES_H_INCLUDED | ||
| 135 | |||
| 136 | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /*============================================================================== | 1 | /*============================================================================== |
| 2 | 2 | ||
| 3 | leaf-filter.h | 3 | leaf-filters.h |
| 4 | Created: 20 Jan 2017 12:01:10pm | 4 | Created: 20 Jan 2017 12:01:10pm |
| 5 | Author: Michael R Mulshine | 5 | Author: Michael R Mulshine |
| 6 | 6 | ||
| 7 | ==============================================================================*/ | 7 | ==============================================================================*/ |
| 8 | 8 | ||
| 9 | #ifndef LEAF_FILTER_H_INCLUDED | 9 | #ifndef LEAF_FILTERS_H_INCLUDED |
| 10 | #define LEAF_FILTER_H_INCLUDED | 10 | #define LEAF_FILTERS_H_INCLUDED |
| 11 | 11 | ||
| 12 | #ifdef __cplusplus | 12 | #ifdef __cplusplus |
| 13 | extern "C" { | 13 | extern "C" { |
| @@ -26,7 +26,7 @@ typedef struct _tAllpass · 12 unmodified lines | |||
| 26 | { | 26 | { |
| 27 | float gain; | 27 | float gain; |
| 28 | 28 | ||
| 29 | tDelayL delay; | 29 | tLinearDelay delay; |
| 30 | 30 | ||
| 31 | float lastOut; | 31 | float lastOut; |
| 32 | 32 | ||
| @@ -227,21 +227,21 @@ int tSVF_setQ (tSVF* const, float Q); · 194 unmodified lines | |||
| 227 | //============================================================================== | 227 | //============================================================================== |
| 228 | 228 | ||
| 229 | /* Efficient State Variable Filter for 14-bit control input, [0, 4096). */ | 229 | /* Efficient State Variable Filter for 14-bit control input, [0, 4096). */ |
| 230 | typedef struct _tSVFE | 230 | typedef struct _tEfficientSVF |
| 231 | { | 231 | { |
| 232 | SVFType type; | 232 | SVFType type; |
| 233 | float cutoff, Q; | 233 | float cutoff, Q; |
| 234 | float ic1eq,ic2eq; | 234 | float ic1eq,ic2eq; |
| 235 | float g,k,a1,a2,a3; | 235 | float g,k,a1,a2,a3; |
| 236 | 236 | ||
| 237 | } tSVFE; | 237 | } tEfficientSVF; |
| 238 | 238 | ||
| 239 | void tSVFE_init (tSVFE* const, SVFType type, uint16_t controlFreq, float Q); | 239 | void tEfficientSVF_init (tEfficientSVF* const, SVFType type, uint16_t controlFreq, float Q); |
| 240 | void tSVFE_free (tSVFE* const); | 240 | void tEfficientSVF_free (tEfficientSVF* const); |
| 241 | 241 | ||
| 242 | float tSVFE_tick (tSVFE* const, float v0); | 242 | float tEfficientSVF_tick (tEfficientSVF* const, float v0); |
| 243 | int tSVFE_setFreq (tSVFE* const, uint16_t controlFreq); | 243 | int tEfficientSVF_setFreq (tEfficientSVF* const, uint16_t controlFreq); |
| 244 | int tSVFE_setQ (tSVFE* const, float Q); | 244 | int tEfficientSVF_setQ (tEfficientSVF* const, float Q); |
| 245 | 245 | ||
| 246 | //============================================================================== | 246 | //============================================================================== |
| 247 | 247 | ||
| @@ -307,6 +307,6 @@ void tFIR_coeffs (tFIR* const, float in); · 59 unmodified lines | |||
| 307 | } | 307 | } |
| 308 | #endif | 308 | #endif |
| 309 | 309 | ||
| 310 | #endif // LEAF_FILTER_H_INCLUDED | 310 | #endif // LEAF_FILTERS_H_INCLUDED |
| 311 | 311 | ||
| 312 | //============================================================================== | 312 | //============================================================================== |
| @@ -1,68 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-formant.h | ||
| 4 | Created: 30 Nov 2018 11:03:37am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_FORMANT_H_INCLUDED | ||
| 10 | #define LEAF_FORMANT_H_INCLUDED | ||
| 11 | |||
| 12 | #ifdef __cplusplus | ||
| 13 | extern "C" { | ||
| 14 | #endif | ||
| 15 | |||
| 16 | //============================================================================== | ||
| 17 | |||
| 18 | #include "leaf-global.h" | ||
| 19 | #include "leaf-mempool.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | |||
| 22 | //============================================================================== | ||
| 23 | |||
| 24 | #define FORD 7 | ||
| 25 | #define FORMANT_BUFFER_SIZE 2048 | ||
| 26 | |||
| 27 | typedef struct _tFormantShifter | ||
| 28 | { | ||
| 29 | int ford; | ||
| 30 | int bufsize; | ||
| 31 | float falph; | ||
| 32 | float flamb; | ||
| 33 | float* fk; | ||
| 34 | float* fb; | ||
| 35 | float* fc; | ||
| 36 | float* frb; | ||
| 37 | float* frc; | ||
| 38 | float* fsig; | ||
| 39 | float* fsmooth; | ||
| 40 | float fhp; | ||
| 41 | float flp; | ||
| 42 | float flpa; | ||
| 43 | float** fbuff; | ||
| 44 | float* ftvec; | ||
| 45 | float fmute; | ||
| 46 | float fmutealph; | ||
| 47 | unsigned int cbi; | ||
| 48 | |||
| 49 | } tFormantShifter; | ||
| 50 | |||
| 51 | void tFormantShifter_init (tFormantShifter* const, int bufsize, int order); | ||
| 52 | void tFormantShifter_free (tFormantShifter* const); | ||
| 53 | |||
| 54 | float tFormantShifter_tick (tFormantShifter* const, float input, float fwarp); | ||
| 55 | float tFormantShifter_remove (tFormantShifter* const, float input); | ||
| 56 | float tFormantShifter_add (tFormantShifter* const, float input, float fwarp); | ||
| 57 | void tFormantShifter_ioSamples (tFormantShifter* const, float* in, float* out, int size, float fwarp); | ||
| 58 | |||
| 59 | //============================================================================== | ||
| 60 | |||
| 61 | #ifdef __cplusplus | ||
| 62 | } | ||
| 63 | #endif | ||
| 64 | |||
| 65 | #endif // LEAF_FORMANT_H_INCLUDED | ||
| 66 | |||
| 67 | //============================================================================== | ||
| 68 | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /*============================================================================== | 1 | /*============================================================================== |
| 2 | 2 | ||
| 3 | leaf-808.h | 3 | leaf-instruments.h |
| 4 | Created: 30 Nov 2018 10:24:44am | 4 | Created: 30 Nov 2018 10:24:44am |
| 5 | Author: airship | 5 | Author: airship |
| 6 | 6 | ||
| 7 | ==============================================================================*/ | 7 | ==============================================================================*/ |
| 8 | 8 | ||
| 9 | #ifndef LEAF_808_H_INCLUDED | 9 | #ifndef LEAF_INSTRUMENTS_H_INCLUDED |
| 10 | #define LEAF_808_H_INCLUDED | 10 | #define LEAF_INSTRUMENTS_H_INCLUDED |
| 11 | 11 | ||
| 12 | #ifdef __cplusplus | 12 | #ifdef __cplusplus |
| 13 | extern "C" { | 13 | extern "C" { |
| @@ -16,9 +16,9 @@ extern "C" { · 2 unmodified lines | |||
| 16 | //============================================================================== | 16 | //============================================================================== |
| 17 | 17 | ||
| 18 | #include "leaf-math.h" | 18 | #include "leaf-math.h" |
| 19 | #include "leaf-oscillator.h" | 19 | #include "leaf-oscillators.h" |
| 20 | #include "leaf-utilities.h" | 20 | #include "leaf-filters.h" |
| 21 | #include "leaf-filter.h" | 21 | #include "leaf-envelopes.h" |
| 22 | 22 | ||
| 23 | //============================================================================== | 23 | //============================================================================== |
| 24 | 24 | ||
| @@ -177,7 +177,7 @@ void t808Kick_setNoiseFilterQ (t808Kick* const, float noiseFilterQ) · 152 unmodified lines | |||
| 177 | } | 177 | } |
| 178 | #endif | 178 | #endif |
| 179 | 179 | ||
| 180 | #endif // LEAF_808_H_INCLUDED | 180 | #endif // LEAF_INSTRUMENTS_H_INCLUDED |
| 181 | 181 | ||
| 182 | //============================================================================== | 182 | //============================================================================== |
| 183 | 183 | ||
| @@ -18,10 +18,38 @@ extern "C" { · 17 unmodified lines | |||
| 18 | #include "leaf-global.h" | 18 | #include "leaf-global.h" |
| 19 | #include "leaf-mempool.h" | 19 | #include "leaf-mempool.h" |
| 20 | #include "leaf-math.h" | 20 | #include "leaf-math.h" |
| 21 | #include "leaf-utilities.h" | 21 | #include "leaf-envelopes.h" |
| 22 | 22 | ||
| 23 | //============================================================================== | 23 | //============================================================================== |
| 24 | 24 | ||
| 25 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 26 | |||
| 27 | // STACK implementation (fixed size) | ||
| 28 | #define STACK_SIZE 128 | ||
| 29 | typedef struct _tStack | ||
| 30 | { | ||
| 31 | int data[STACK_SIZE]; | ||
| 32 | uint16_t pos; | ||
| 33 | uint16_t size; | ||
| 34 | uint16_t capacity; | ||
| 35 | oBool ordered; | ||
| 36 | |||
| 37 | } tStack; | ||
| 38 | |||
| 39 | void tStack_init (tStack* const); | ||
| 40 | void tStack_free (tStack* const); | ||
| 41 | |||
| 42 | void tStack_setCapacity (tStack* const, uint16_t cap); | ||
| 43 | int tStack_addIfNotAlreadyThere (tStack* const, uint16_t item); | ||
| 44 | void tStack_add (tStack* const, uint16_t item); | ||
| 45 | int tStack_remove (tStack* const, uint16_t item); | ||
| 46 | void tStack_clear (tStack* const); | ||
| 47 | int tStack_first (tStack* const); | ||
| 48 | int tStack_getSize (tStack* const); | ||
| 49 | int tStack_contains (tStack* const, uint16_t item); | ||
| 50 | int tStack_next (tStack* const); | ||
| 51 | int tStack_get (tStack* const, int which); | ||
| 52 | |||
| 25 | /* tPoly */ | 53 | /* tPoly */ |
| 26 | typedef struct _tPoly | 54 | typedef struct _tPoly |
| 27 | { | 55 | { |
| @@ -1,13 +1,13 @@ | |||
| 1 | /*============================================================================== | 1 | /*============================================================================== |
| 2 | 2 | ||
| 3 | leaf-oscillator.h | 3 | leaf-oscillators.h |
| 4 | Created: 20 Jan 2017 12:00:58pm | 4 | Created: 20 Jan 2017 12:00:58pm |
| 5 | Author: Michael R Mulshine | 5 | Author: Michael R Mulshine |
| 6 | 6 | ||
| 7 | ==============================================================================*/ | 7 | ==============================================================================*/ |
| 8 | 8 | ||
| 9 | #ifndef LEAF_OSCILLATOR_H_INCLUDED | 9 | #ifndef LEAF_OSCILLATORS_H_INCLUDED |
| 10 | #define LEAF_OSCILLATOR_H_INCLUDED | 10 | #define LEAF_OSCILLATORS_H_INCLUDED |
| 11 | 11 | ||
| 12 | #ifdef __cplusplus | 12 | #ifdef __cplusplus |
| 13 | extern "C" { | 13 | extern "C" { |
| @@ -16,68 +16,7 @@ extern "C" { · 2 unmodified lines | |||
| 16 | //============================================================================== | 16 | //============================================================================== |
| 17 | 17 | ||
| 18 | #include "leaf-math.h" | 18 | #include "leaf-math.h" |
| 19 | 19 | #include "leaf-filters.h" | |
| 20 | #include "leaf-filter.h" | ||
| 21 | |||
| 22 | //============================================================================== | ||
| 23 | |||
| 24 | /* tNeuron */ | ||
| 25 | typedef enum NeuronMode | ||
| 26 | { | ||
| 27 | NeuronNormal = 0, | ||
| 28 | NeuronTanh, | ||
| 29 | NeuronAaltoShaper, | ||
| 30 | NeuronModeNil | ||
| 31 | } NeuronMode; | ||
| 32 | |||
| 33 | typedef struct _tNeuron | ||
| 34 | { | ||
| 35 | tPoleZero f; | ||
| 36 | |||
| 37 | NeuronMode mode; | ||
| 38 | |||
| 39 | float voltage, current; | ||
| 40 | float timeStep; | ||
| 41 | |||
| 42 | float alpha[3]; | ||
| 43 | float beta[3]; | ||
| 44 | float rate[3]; | ||
| 45 | float V[3]; | ||
| 46 | float P[3]; | ||
| 47 | float gK, gN, gL, C; | ||
| 48 | } tNeuron; | ||
| 49 | |||
| 50 | void tNeuron_init (tNeuron* const); | ||
| 51 | void tNeuron_free (tNeuron* const); | ||
| 52 | |||
| 53 | void tNeuron_reset (tNeuron* const); | ||
| 54 | float tNeuron_Tick (tNeuron* const); | ||
| 55 | void tNeuron_setMode (tNeuron* const, NeuronMode mode); | ||
| 56 | void tNeuron_setCurrent (tNeuron* const, float current); | ||
| 57 | void tNeuron_setK (tNeuron* const, float K); | ||
| 58 | void tNeuron_setL (tNeuron* const, float L); | ||
| 59 | void tNeuron_setN (tNeuron* const, float N); | ||
| 60 | void tNeuron_setC (tNeuron* const, float C); | ||
| 61 | void tNeuron_setV1 (tNeuron* const, float V1); | ||
| 62 | void tNeuron_setV2 (tNeuron* const, float V2); | ||
| 63 | void tNeuron_setV3 (tNeuron* const, float V3); | ||
| 64 | void tNeuron_setTimeStep (tNeuron* const, float timestep); | ||
| 65 | |||
| 66 | //============================================================================== | ||
| 67 | |||
| 68 | /* tPhasor: Aliasing phasor [0.0, 1.0) */ | ||
| 69 | typedef struct _tPhasor | ||
| 70 | { | ||
| 71 | float phase; | ||
| 72 | float inc,freq; | ||
| 73 | |||
| 74 | } tPhasor; | ||
| 75 | |||
| 76 | void tPhasor_init (tPhasor* const); | ||
| 77 | void tPhasor_free (tPhasor* const); | ||
| 78 | |||
| 79 | float tPhasor_tick (tPhasor* const); | ||
| 80 | int tPhasor_setFreq (tPhasor* const, float freq); | ||
| 81 | 20 | ||
| 82 | //============================================================================== | 21 | //============================================================================== |
| 83 | 22 | ||
| @@ -98,23 +37,6 @@ int tCycle_setFreq (tCycle* const, float freq); · 14 unmodified lines | |||
| 98 | 37 | ||
| 99 | //============================================================================== | 38 | //============================================================================== |
| 100 | 39 | ||
| 101 | /* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */ | ||
| 102 | typedef struct _tSawtooth | ||
| 103 | { | ||
| 104 | // Underlying phasor | ||
| 105 | float phase; | ||
| 106 | float inc,freq; | ||
| 107 | |||
| 108 | } tSawtooth; | ||
| 109 | |||
| 110 | void tSawtooth_init (tSawtooth* const); | ||
| 111 | void tSawtooth_free (tSawtooth* const); | ||
| 112 | |||
| 113 | float tSawtooth_tick (tSawtooth* const); | ||
| 114 | int tSawtooth_setFreq (tSawtooth* const, float freq); | ||
| 115 | |||
| 116 | //============================================================================== | ||
| 117 | |||
| 118 | /* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */ | 40 | /* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */ |
| 119 | typedef struct _tTriangle | 41 | typedef struct _tTriangle |
| 120 | { | 42 | { |
| @@ -146,6 +68,39 @@ void tSquare_free (tSquare* const); · 25 unmodified lines | |||
| 146 | 68 | ||
| 147 | float tSquare_tick (tSquare* const); | 69 | float tSquare_tick (tSquare* const); |
| 148 | int tSquare_setFreq (tSquare* const, float freq); | 70 | int tSquare_setFreq (tSquare* const, float freq); |
| 71 | |||
| 72 | //============================================================================== | ||
| 73 | |||
| 74 | /* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */ | ||
| 75 | typedef struct _tSawtooth | ||
| 76 | { | ||
| 77 | // Underlying phasor | ||
| 78 | float phase; | ||
| 79 | float inc,freq; | ||
| 80 | |||
| 81 | } tSawtooth; | ||
| 82 | |||
| 83 | void tSawtooth_init (tSawtooth* const); | ||
| 84 | void tSawtooth_free (tSawtooth* const); | ||
| 85 | |||
| 86 | float tSawtooth_tick (tSawtooth* const); | ||
| 87 | int tSawtooth_setFreq (tSawtooth* const, float freq); | ||
| 88 | |||
| 89 | //============================================================================== | ||
| 90 | |||
| 91 | /* tPhasor: Aliasing phasor [0.0, 1.0) */ | ||
| 92 | typedef struct _tPhasor | ||
| 93 | { | ||
| 94 | float phase; | ||
| 95 | float inc,freq; | ||
| 96 | |||
| 97 | } tPhasor; | ||
| 98 | |||
| 99 | void tPhasor_init (tPhasor* const); | ||
| 100 | void tPhasor_free (tPhasor* const); | ||
| 101 | |||
| 102 | float tPhasor_tick (tPhasor* const); | ||
| 103 | int tPhasor_setFreq (tPhasor* const, float freq); | ||
| 149 | 104 | ||
| 150 | //============================================================================== | 105 | //============================================================================== |
| 151 | 106 | ||
| @@ -161,7 +116,7 @@ typedef struct _tNoise · 9 unmodified lines | |||
| 161 | { | 116 | { |
| 162 | NoiseType type; | 117 | NoiseType type; |
| 163 | float pinkb0, pinkb1, pinkb2; | 118 | float pinkb0, pinkb1, pinkb2; |
| 164 | float(*rand)(); | 119 | float(*rand)(void); |
| 165 | 120 | ||
| 166 | } tNoise; | 121 | } tNoise; |
| 167 | 122 | ||
| @@ -169,6 +124,50 @@ void tNoise_init (tNoise* const, NoiseType type); · 1 unmodified line | |||
| 169 | void tNoise_free (tNoise* const); | 124 | void tNoise_free (tNoise* const); |
| 170 | 125 | ||
| 171 | float tNoise_tick (tNoise* const); | 126 | float tNoise_tick (tNoise* const); |
| 127 | |||
| 128 | //============================================================================== | ||
| 129 | |||
| 130 | /* tNeuron */ | ||
| 131 | typedef enum NeuronMode | ||
| 132 | { | ||
| 133 | NeuronNormal = 0, | ||
| 134 | NeuronTanh, | ||
| 135 | NeuronAaltoShaper, | ||
| 136 | NeuronModeNil | ||
| 137 | } NeuronMode; | ||
| 138 | |||
| 139 | typedef struct _tNeuron | ||
| 140 | { | ||
| 141 | tPoleZero f; | ||
| 142 | |||
| 143 | NeuronMode mode; | ||
| 144 | |||
| 145 | float voltage, current; | ||
| 146 | float timeStep; | ||
| 147 | |||
| 148 | float alpha[3]; | ||
| 149 | float beta[3]; | ||
| 150 | float rate[3]; | ||
| 151 | float V[3]; | ||
| 152 | float P[3]; | ||
| 153 | float gK, gN, gL, C; | ||
| 154 | } tNeuron; | ||
| 155 | |||
| 156 | void tNeuron_init (tNeuron* const); | ||
| 157 | void tNeuron_free (tNeuron* const); | ||
| 158 | |||
| 159 | void tNeuron_reset (tNeuron* const); | ||
| 160 | float tNeuron_Tick (tNeuron* const); | ||
| 161 | void tNeuron_setMode (tNeuron* const, NeuronMode mode); | ||
| 162 | void tNeuron_setCurrent (tNeuron* const, float current); | ||
| 163 | void tNeuron_setK (tNeuron* const, float K); | ||
| 164 | void tNeuron_setL (tNeuron* const, float L); | ||
| 165 | void tNeuron_setN (tNeuron* const, float N); | ||
| 166 | void tNeuron_setC (tNeuron* const, float C); | ||
| 167 | void tNeuron_setV1 (tNeuron* const, float V1); | ||
| 168 | void tNeuron_setV2 (tNeuron* const, float V2); | ||
| 169 | void tNeuron_setV3 (tNeuron* const, float V3); | ||
| 170 | void tNeuron_setTimeStep (tNeuron* const, float timestep); | ||
| 172 | 171 | ||
| 173 | //============================================================================== | 172 | //============================================================================== |
| 174 | 173 | ||
| @@ -176,6 +175,6 @@ float tNoise_tick (tNoise* const); · 1 unmodified line | |||
| 176 | } | 175 | } |
| 177 | #endif | 176 | #endif |
| 178 | 177 | ||
| 179 | #endif // LEAF_OSCILLATOR_H_INCLUDED | 178 | #endif // LEAF_OSCILLATORS_H_INCLUDED |
| 180 | 179 | ||
| 181 | //============================================================================== | 180 | //============================================================================== |
| @@ -1,51 +0,0 @@ | |||
| 1 | // | ||
| 2 | // leaf-oversampler.h | ||
| 3 | // LEAF | ||
| 4 | // | ||
| 5 | // Created by Matthew Wang and Joshua Becker on 2/28/19. | ||
| 6 | // Copyright © 2019 Princeton University. All rights reserved. | ||
| 7 | // | ||
| 8 | //============================================================================== | ||
| 9 | |||
| 10 | #ifndef LEAF_OVERSAMPLER_H_INCLUDED | ||
| 11 | #define LEAF_OVERSAMPLER_H_INCLUDED | ||
| 12 | |||
| 13 | #ifdef __cplusplus | ||
| 14 | extern "C" { | ||
| 15 | #endif | ||
| 16 | |||
| 17 | //============================================================================== | ||
| 18 | |||
| 19 | #include "leaf-global.h" | ||
| 20 | #include "leaf-mempool.h" | ||
| 21 | #include "leaf-math.h" | ||
| 22 | #include "leaf-filter.h" | ||
| 23 | |||
| 24 | //============================================================================== | ||
| 25 | |||
| 26 | typedef struct _tOversampler | ||
| 27 | { | ||
| 28 | int ratio; | ||
| 29 | float* pCoeffs; | ||
| 30 | float* upState; | ||
| 31 | float* downState; | ||
| 32 | int numTaps; | ||
| 33 | int phaseLength; | ||
| 34 | } tOversampler; | ||
| 35 | |||
| 36 | void tOversampler_init(tOversampler* const, int order, oBool extraQuality); | ||
| 37 | void tOversampler_free(tOversampler* const); | ||
| 38 | void tOversampler_upsample(tOversampler* const, float input, float* output); | ||
| 39 | float tOversampler_downsample(tOversampler *const os, float* input); | ||
| 40 | float tOversampler_tick(tOversampler* const, float input, float (*effectTick)(float)); | ||
| 41 | int tOversampler_getLatency(tOversampler* const os); | ||
| 42 | |||
| 43 | //============================================================================== | ||
| 44 | |||
| 45 | #ifdef __cplusplus | ||
| 46 | } | ||
| 47 | #endif | ||
| 48 | |||
| 49 | #endif // LEAF_OVERSAMPLER_H_INCLUDED | ||
| 50 | |||
| 51 | //============================================================================== | ||
| @@ -0,0 +1,221 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | leaf-physical.h | ||
| 5 | Created: 30 Nov 2018 10:41:55am | ||
| 6 | Author: airship | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef LEAF_PHYSICAL_H_INCLUDED | ||
| 12 | #define LEAF_PHYSICAL_H_INCLUDED | ||
| 13 | |||
| 14 | #ifdef __cplusplus | ||
| 15 | extern "C" { | ||
| 16 | #endif | ||
| 17 | |||
| 18 | //============================================================================== | ||
| 19 | |||
| 20 | #include "leaf-global.h" | ||
| 21 | #include "leaf-math.h" | ||
| 22 | #include "leaf-delay.h" | ||
| 23 | #include "leaf-filters.h" | ||
| 24 | #include "leaf-oscillators.h" | ||
| 25 | #include "leaf-envelopes.h" | ||
| 26 | #include "leaf-dynamics.h" | ||
| 27 | |||
| 28 | //============================================================================== | ||
| 29 | |||
| 30 | /* Karplus Strong model */ | ||
| 31 | typedef struct _tPluck | ||
| 32 | { | ||
| 33 | tAllpassDelay delayLine; // Allpass or Linear?? big difference... | ||
| 34 | tOneZero loopFilter; | ||
| 35 | tOnePole pickFilter; | ||
| 36 | tNoise noise; | ||
| 37 | |||
| 38 | float lastOut; | ||
| 39 | float loopGain; | ||
| 40 | float lastFreq; | ||
| 41 | |||
| 42 | float sr; | ||
| 43 | |||
| 44 | } tPluck; | ||
| 45 | |||
| 46 | void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]); | ||
| 47 | void tPluck_free (tPluck* const); | ||
| 48 | |||
| 49 | float tPluck_tick (tPluck* const); | ||
| 50 | |||
| 51 | // Pluck the string. | ||
| 52 | void tPluck_pluck (tPluck* const, float amplitude); | ||
| 53 | |||
| 54 | // Start a note with the given frequency and amplitude.; | ||
| 55 | void tPluck_noteOn (tPluck* const, float frequency, float amplitude ); | ||
| 56 | |||
| 57 | // Stop a note with the given amplitude (speed of decay). | ||
| 58 | void tPluck_noteOff (tPluck* const, float amplitude ); | ||
| 59 | |||
| 60 | // Set instrument parameters for a particular frequency. | ||
| 61 | void tPluck_setFrequency (tPluck* const, float frequency ); | ||
| 62 | |||
| 63 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 64 | void tPluck_controlChange (tPluck* const, int number, float value); | ||
| 65 | |||
| 66 | // tPluck Utilities. | ||
| 67 | float tPluck_getLastOut (tPluck* const); | ||
| 68 | |||
| 69 | //============================================================================== | ||
| 70 | |||
| 71 | /* Stif Karplus Strong model */ | ||
| 72 | typedef struct _tKarplusStrong | ||
| 73 | { | ||
| 74 | tAllpassDelay delayLine; | ||
| 75 | tLinearDelay combDelay; | ||
| 76 | tOneZero filter; | ||
| 77 | tNoise noise; | ||
| 78 | tBiQuad biquad[4]; | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | uint32_t length; | ||
| 83 | float loopGain; | ||
| 84 | float baseLoopGain; | ||
| 85 | float lastFrequency; | ||
| 86 | float lastLength; | ||
| 87 | float stretching; | ||
| 88 | float pluckAmplitude; | ||
| 89 | float pickupPosition; | ||
| 90 | |||
| 91 | float lastOut; | ||
| 92 | |||
| 93 | } tKarplusStrong; | ||
| 94 | |||
| 95 | typedef enum SKControlType | ||
| 96 | { | ||
| 97 | SKPickPosition = 0, | ||
| 98 | SKStringDamping, | ||
| 99 | SKDetune, | ||
| 100 | SKControlTypeNil | ||
| 101 | } SKControlType; | ||
| 102 | |||
| 103 | void tKarplusStrong_init (tKarplusStrong* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]); | ||
| 104 | void tKarplusStrong_free (tKarplusStrong* const); | ||
| 105 | |||
| 106 | float tKarplusStrong_tick (tKarplusStrong* const); | ||
| 107 | |||
| 108 | // Pluck the string. | ||
| 109 | void tKarplusStrong_pluck (tKarplusStrong* const, float amplitude); | ||
| 110 | |||
| 111 | // Start a note with the given frequency and amplitude.; | ||
| 112 | void tKarplusStrong_noteOn (tKarplusStrong* const, float frequency, float amplitude ); | ||
| 113 | |||
| 114 | // Stop a note with the given amplitude (speed of decay). | ||
| 115 | void tKarplusStrong_noteOff (tKarplusStrong* const, float amplitude ); | ||
| 116 | |||
| 117 | // Set instrument parameters for a particular frequency. | ||
| 118 | void tKarplusStrong_setFrequency (tKarplusStrong* const, float frequency ); | ||
| 119 | |||
| 120 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 121 | // Use SKPickPosition, SKStringDamping, or SKDetune for type. | ||
| 122 | void tKarplusStrong_controlChange (tKarplusStrong* const, SKControlType type, float value); | ||
| 123 | |||
| 124 | // Set the stretch "factor" of the string (0.0 - 1.0). | ||
| 125 | void tKarplusStrong_setStretch (tKarplusStrong* const, float stretch ); | ||
| 126 | |||
| 127 | // Set the pluck or "excitation" position along the string (0.0 - 1.0). | ||
| 128 | void tKarplusStrong_setPickupPosition (tKarplusStrong* const, float position ); | ||
| 129 | |||
| 130 | // Set the base loop gain. | ||
| 131 | void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const, float aGain ); | ||
| 132 | |||
| 133 | // tKarplusStrong utilities. | ||
| 134 | float tKarplusStrong_getLastOut (tKarplusStrong* const); | ||
| 135 | |||
| 136 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 137 | |||
| 138 | /* Simple Living String */ | ||
| 139 | typedef struct _tSimpleLivingString { | ||
| 140 | float freq, waveLengthInSamples; // the frequency of the string, determining delay length | ||
| 141 | float dampFreq; // frequency for the bridge LP filter, in Hz | ||
| 142 | float decay; // amplitude damping factor for the string (only active in mode 0) | ||
| 143 | float levMode; | ||
| 144 | float curr; | ||
| 145 | tLinearDelay delayLine; | ||
| 146 | tOnePole bridgeFilter; | ||
| 147 | tHighpass DCblocker; | ||
| 148 | tFeedbackLeveler fbLev; | ||
| 149 | tExpSmooth wlSmooth; | ||
| 150 | } tSimpleLivingString; | ||
| 151 | |||
| 152 | void tSimpleLivingString_init (tSimpleLivingString* const, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode); | ||
| 153 | void tSimpleLivingString_free (tSimpleLivingString* const); | ||
| 154 | float tSimpleLivingString_tick (tSimpleLivingString* const, float input); | ||
| 155 | float tSimpleLivingString_sample (tSimpleLivingString* const); | ||
| 156 | int tSimpleLivingString_setFreq (tSimpleLivingString* const, float freq); | ||
| 157 | int tSimpleLivingString_setWaveLength (tSimpleLivingString* const, float waveLength); // in samples | ||
| 158 | int tSimpleLivingString_setDampFreq (tSimpleLivingString* const, float dampFreq); | ||
| 159 | int tSimpleLivingString_setDecay (tSimpleLivingString* const, float decay); // should be near 1.0 | ||
| 160 | int tSimpleLivingString_setTargetLev (tSimpleLivingString* const, float targetLev); | ||
| 161 | int tSimpleLivingString_setLevSmoothFactor (tSimpleLivingString* const, float levSmoothFactor); | ||
| 162 | int tSimpleLivingString_setLevStrength (tSimpleLivingString* const, float levStrength); | ||
| 163 | int tSimpleLivingString_setLevMode (tSimpleLivingString* const, int levMode); | ||
| 164 | |||
| 165 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 166 | |||
| 167 | /* Living String */ | ||
| 168 | typedef struct _tLivingString { | ||
| 169 | float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length | ||
| 170 | float pickPos; // the pick position, dividing the string in two, in ratio | ||
| 171 | float prepIndex; // the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj) | ||
| 172 | float dampFreq; // frequency for the bridge LP filter, in Hz | ||
| 173 | float decay; // amplitude damping factor for the string (only active in mode 0) | ||
| 174 | float levMode; | ||
| 175 | float curr; | ||
| 176 | tLinearDelay delLF,delUF,delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model | ||
| 177 | tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL; | ||
| 178 | tHighpass DCblockerL, DCblockerU; | ||
| 179 | tFeedbackLeveler fbLevU, fbLevL; | ||
| 180 | tExpSmooth wlSmooth, ppSmooth; | ||
| 181 | } tLivingString; | ||
| 182 | |||
| 183 | void tLivingString_init (tLivingString* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay, | ||
| 184 | float targetLev, float levSmoothFactor, float levStrength, int levMode); | ||
| 185 | void tLivingString_free (tLivingString* const); | ||
| 186 | float tLivingString_tick (tLivingString* const, float input); | ||
| 187 | float tLivingString_sample (tLivingString* const); | ||
| 188 | int tLivingString_setFreq (tLivingString* const, float freq); | ||
| 189 | int tLivingString_setWaveLength (tLivingString* const, float waveLength); // in samples | ||
| 190 | int tLivingString_setPickPos (tLivingString* const, float pickPos); | ||
| 191 | int tLivingString_setPrepIndex (tLivingString* const, float prepIndex); | ||
| 192 | int tLivingString_setDampFreq (tLivingString* const, float dampFreq); | ||
| 193 | int tLivingString_setDecay (tLivingString* const, float decay); // should be near 1.0 | ||
| 194 | int tLivingString_setTargetLev (tLivingString* const, float targetLev); | ||
| 195 | int tLivingString_setLevSmoothFactor (tLivingString* const, float levSmoothFactor); | ||
| 196 | int tLivingString_setLevStrength (tLivingString* const, float levStrength); | ||
| 197 | int tLivingString_setLevMode (tLivingString* const, int levMode); | ||
| 198 | |||
| 199 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 200 | |||
| 201 | //Reed Table - borrowed from STK | ||
| 202 | typedef struct _tReedTable { | ||
| 203 | float offset, slope; | ||
| 204 | } tReedTable; | ||
| 205 | |||
| 206 | void tReedTable_init (tReedTable* const, float offset, float slope); | ||
| 207 | void tReedTable_free (tReedTable* const); | ||
| 208 | float tReedTable_tick (tReedTable* const, float input); | ||
| 209 | float tReedTable_tanh_tick (tReedTable* const p, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code | ||
| 210 | void tReedTable_setOffset (tReedTable* const, float offset); | ||
| 211 | void tReedTable_setSlope (tReedTable* const, float slope); | ||
| 212 | |||
| 213 | //============================================================================== | ||
| 214 | |||
| 215 | #ifdef __cplusplus | ||
| 216 | } | ||
| 217 | #endif | ||
| 218 | |||
| 219 | #endif // LEAF_PHYSICAL_H_INCLUDED | ||
| 220 | |||
| 221 | //============================================================================== | ||
| @@ -1,161 +0,0 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | leaf-pitch.h | ||
| 5 | Created: 30 Nov 2018 11:03:13am | ||
| 6 | Author: airship | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef LEAF_PITCH_H_INCLUDED | ||
| 12 | #define LEAF_PITCH_H_INCLUDED | ||
| 13 | |||
| 14 | #ifdef __cplusplus | ||
| 15 | extern "C" { | ||
| 16 | #endif | ||
| 17 | |||
| 18 | //============================================================================== | ||
| 19 | |||
| 20 | #include "leaf-global.h" | ||
| 21 | #include "leaf-math.h" | ||
| 22 | |||
| 23 | #include "leaf-filter.h" | ||
| 24 | #include "leaf-utilities.h" | ||
| 25 | |||
| 26 | //============================================================================== | ||
| 27 | |||
| 28 | #define DEFPITCHRATIO 2.0f | ||
| 29 | #define DEFTIMECONSTANT 100.0f | ||
| 30 | #define DEFHOPSIZE 64 | ||
| 31 | #define DEFWINDOWSIZE 64 | ||
| 32 | #define FBA 20 | ||
| 33 | #define HPFREQ 40.0f | ||
| 34 | |||
| 35 | |||
| 36 | //============================================================================== | ||
| 37 | |||
| 38 | // Pitch shifter | ||
| 39 | typedef struct _tPitchShifter | ||
| 40 | { | ||
| 41 | tEnv env; | ||
| 42 | tSNAC snac; | ||
| 43 | tSOLAD sola; | ||
| 44 | tHighpass hp; | ||
| 45 | |||
| 46 | float* inBuffer; | ||
| 47 | float* outBuffer; | ||
| 48 | int frameSize; | ||
| 49 | int bufSize; | ||
| 50 | int framesPerBuffer; | ||
| 51 | int curBlock; | ||
| 52 | int lastBlock; | ||
| 53 | int index; | ||
| 54 | |||
| 55 | uint16_t hopSize; | ||
| 56 | uint16_t windowSize; | ||
| 57 | uint8_t fba; | ||
| 58 | |||
| 59 | float pitchFactor; | ||
| 60 | float timeConstant; | ||
| 61 | float radius; | ||
| 62 | float max; | ||
| 63 | float lastmax; | ||
| 64 | float deltamax; | ||
| 65 | |||
| 66 | } tPitchShifter; | ||
| 67 | |||
| 68 | void tPitchShifter_init (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize); | ||
| 69 | void tPitchShifter_free (tPitchShifter* const); | ||
| 70 | |||
| 71 | float tPitchShifter_tick (tPitchShifter* const, float sample); | ||
| 72 | float tPitchShifterToFreq_tick (tPitchShifter* const, float sample, float freq); | ||
| 73 | float tPitchShifterToFunc_tick (tPitchShifter* const, float sample, float (*fun)(float)); | ||
| 74 | void tPitchShifter_ioSamples_toFreq (tPitchShifter* const, float* in, float* out, int size, float toFreq); | ||
| 75 | void tPitchShifter_ioSamples_toPeriod(tPitchShifter* const, float* in, float* out, int size, float toPeriod); | ||
| 76 | void tPitchShifter_ioSamples_toFunc (tPitchShifter* const, float* in, float* out, int size, float (*fun)(float)); | ||
| 77 | void tPitchShifter_setPitchFactor (tPitchShifter* const, float pf); | ||
| 78 | void tPitchShifter_setTimeConstant (tPitchShifter* const, float tc); | ||
| 79 | void tPitchShifter_setHopSize (tPitchShifter* const, int hs); | ||
| 80 | void tPitchShifter_setWindowSize (tPitchShifter* const, int ws); | ||
| 81 | float tPitchShifter_getPeriod (tPitchShifter* const); | ||
| 82 | |||
| 83 | //============================================================================== | ||
| 84 | |||
| 85 | // Period detection | ||
| 86 | typedef struct _tPeriod | ||
| 87 | { | ||
| 88 | tEnv env; | ||
| 89 | tSNAC snac; | ||
| 90 | float* inBuffer; | ||
| 91 | float* outBuffer; | ||
| 92 | int frameSize; | ||
| 93 | int bufSize; | ||
| 94 | int framesPerBuffer; | ||
| 95 | int curBlock; | ||
| 96 | int lastBlock; | ||
| 97 | int i; | ||
| 98 | int indexstore; | ||
| 99 | int iLast; | ||
| 100 | int index; | ||
| 101 | float period; | ||
| 102 | |||
| 103 | uint16_t hopSize; | ||
| 104 | uint16_t windowSize; | ||
| 105 | uint8_t fba; | ||
| 106 | |||
| 107 | float timeConstant; | ||
| 108 | float radius; | ||
| 109 | float max; | ||
| 110 | float lastmax; | ||
| 111 | float deltamax; | ||
| 112 | |||
| 113 | }tPeriod; | ||
| 114 | |||
| 115 | void tPeriod_init (tPeriod* const, float* in, float* out, int bufSize, int frameSize); | ||
| 116 | void tPeriod_free (tPeriod* const); | ||
| 117 | |||
| 118 | float tPeriod_findPeriod (tPeriod* const, float sample); | ||
| 119 | void tPeriod_setHopSize (tPeriod* p, int hs); | ||
| 120 | void tPeriod_setWindowSize (tPeriod* p, int ws); | ||
| 121 | |||
| 122 | //============================================================================== | ||
| 123 | |||
| 124 | // Pitch shift | ||
| 125 | typedef struct _tPitchShift | ||
| 126 | { | ||
| 127 | tSOLAD sola; | ||
| 128 | tHighpass hp; | ||
| 129 | tPeriod* p; | ||
| 130 | |||
| 131 | float* outBuffer; | ||
| 132 | int frameSize; | ||
| 133 | int bufSize; | ||
| 134 | |||
| 135 | int framesPerBuffer; | ||
| 136 | int curBlock; | ||
| 137 | int lastBlock; | ||
| 138 | int index; | ||
| 139 | |||
| 140 | float pitchFactor; | ||
| 141 | float timeConstant; | ||
| 142 | float radius; | ||
| 143 | } tPitchShift; | ||
| 144 | |||
| 145 | void tPitchShift_init (tPitchShift* const, tPeriod* const, float* out, int bufSize); | ||
| 146 | void tPitchShift_free (tPitchShift* const); | ||
| 147 | |||
| 148 | float tPitchShift_shift (tPitchShift* const); | ||
| 149 | float tPitchShift_shiftToFunc (tPitchShift* const, float (*fun)(float)); | ||
| 150 | float tPitchShift_shiftToFreq (tPitchShift* const, float freq); | ||
| 151 | void tPitchShift_setPitchFactor (tPitchShift* const, float pf); | ||
| 152 | |||
| 153 | //============================================================================== | ||
| 154 | |||
| 155 | #ifdef __cplusplus | ||
| 156 | } | ||
| 157 | #endif | ||
| 158 | |||
| 159 | #endif // LEAF_PITCH_H_INCLUDED | ||
| 160 | |||
| 161 | //============================================================================== | ||
| @@ -17,15 +17,14 @@ extern "C" { · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | #include "leaf-global.h" | 18 | #include "leaf-global.h" |
| 19 | #include "leaf-math.h" | 19 | #include "leaf-math.h" |
| 20 | |||
| 21 | #include "leaf-delay.h" | 20 | #include "leaf-delay.h" |
| 22 | #include "leaf-filter.h" | 21 | #include "leaf-filters.h" |
| 23 | #include "leaf-oscillator.h" | 22 | #include "leaf-oscillators.h" |
| 24 | 23 | ||
| 25 | //============================================================================== | 24 | //============================================================================== |
| 26 | 25 | ||
| 27 | /* PRCRev: Reverb, reimplemented from STK (Cook and Scavone). */ | 26 | /* PRCReverb: Reverb, reimplemented from STK (Cook and Scavone). */ |
| 28 | typedef struct _tPRCRev | 27 | typedef struct _tPRCReverb |
| 29 | { | 28 | { |
| 30 | float mix, t60; | 29 | float mix, t60; |
| 31 | 30 | ||
| @@ -38,23 +37,23 @@ typedef struct _tPRCRev · 6 unmodified lines | |||
| 38 | 37 | ||
| 39 | float lastIn, lastOut; | 38 | float lastIn, lastOut; |
| 40 | 39 | ||
| 41 | } tPRCRev; | 40 | } tPRCReverb; |
| 42 | 41 | ||
| 43 | void tPRCRev_init (tPRCRev* const, float t60); | 42 | void tPRCReverb_init (tPRCReverb* const, float t60); |
| 44 | void tPRCRev_free (tPRCRev* const); | 43 | void tPRCReverb_free (tPRCReverb* const); |
| 45 | 44 | ||
| 46 | float tPRCRev_tick (tPRCRev* const, float input); | 45 | float tPRCReverb_tick (tPRCReverb* const, float input); |
| 47 | 46 | ||
| 48 | // Set reverb time in seconds. | 47 | // Set reverb time in seconds. |
| 49 | void tPRCRev_setT60 (tPRCRev* const, float t60); | 48 | void tPRCReverb_setT60 (tPRCReverb* const, float t60); |
| 50 | 49 | ||
| 51 | // Set mix between dry input and wet output signal. | 50 | // Set mix between dry input and wet output signal. |
| 52 | void tPRCRev_setMix (tPRCRev* const, float mix); | 51 | void tPRCReverb_setMix (tPRCReverb* const, float mix); |
| 53 | 52 | ||
| 54 | //============================================================================== | 53 | //============================================================================== |
| 55 | 54 | ||
| 56 | /* NRev: Reverb, reimplemented from STK (Cook and Scavone). */ | 55 | /* NReverb: Reverb, reimplemented from STK (Cook and Scavone). */ |
| 57 | typedef struct _tNRev | 56 | typedef struct _tNReverb |
| 58 | { | 57 | { |
| 59 | float mix, t60; | 58 | float mix, t60; |
| 60 | 59 | ||
| @@ -68,22 +67,22 @@ typedef struct _tNRev · 7 unmodified lines | |||
| 68 | 67 | ||
| 69 | float lastIn, lastOut; | 68 | float lastIn, lastOut; |
| 70 | 69 | ||
| 71 | } tNRev; | 70 | } tNReverb; |
| 72 | 71 | ||
| 73 | void tNRev_init (tNRev* const, float t60); | 72 | void tNReverb_init (tNReverb* const, float t60); |
| 74 | void tNRev_free (tNRev* const); | 73 | void tNReverb_free (tNReverb* const); |
| 75 | 74 | ||
| 76 | float tNRev_tick (tNRev* const, float input); | 75 | float tNReverb_tick (tNReverb* const, float input); |
| 77 | 76 | ||
| 78 | // Set reverb time in seconds. | 77 | // Set reverb time in seconds. |
| 79 | void tNRev_setT60 (tNRev* const, float t60); | 78 | void tNReverb_setT60 (tNReverb* const, float t60); |
| 80 | 79 | ||
| 81 | // Set mix between dry input and wet output signal. | 80 | // Set mix between dry input and wet output signal. |
| 82 | void tNRev_setMix (tNRev* const, float mix); | 81 | void tNReverb_setMix (tNReverb* const, float mix); |
| 83 | 82 | ||
| 84 | //============================================================================== | 83 | //============================================================================== |
| 85 | 84 | ||
| 86 | typedef struct _tDattorro | 85 | typedef struct _tDattorroReverb |
| 87 | { | 86 | { |
| 88 | float predelay; | 87 | float predelay; |
| 89 | float input_filter; | 88 | float input_filter; |
| @@ -125,19 +124,19 @@ typedef struct _tDattorro · 35 unmodified lines | |||
| 125 | 124 | ||
| 126 | tCycle f2_lfo; | 125 | tCycle f2_lfo; |
| 127 | 126 | ||
| 128 | } tDattorro; | 127 | } tDattorroReverb; |
| 129 | 128 | ||
| 130 | void tDattorro_init (tDattorro* const); | 129 | void tDattorroReverb_init (tDattorroReverb* const); |
| 131 | void tDattorro_free (tDattorro* const); | 130 | void tDattorroReverb_free (tDattorroReverb* const); |
| 132 | 131 | ||
| 133 | float tDattorro_tick (tDattorro* const, float input); | 132 | float tDattorroReverb_tick (tDattorroReverb* const, float input); |
| 134 | 133 | ||
| 135 | void tDattorro_setMix (tDattorro* const, float mix); | 134 | void tDattorroReverb_setMix (tDattorroReverb* const, float mix); |
| 136 | void tDattorro_setSize (tDattorro* const, float size); | 135 | void tDattorroReverb_setSize (tDattorroReverb* const, float size); |
| 137 | void tDattorro_setInputDelay (tDattorro* const, float preDelay); | 136 | void tDattorroReverb_setInputDelay (tDattorroReverb* const, float preDelay); |
| 138 | void tDattorro_setInputFilter (tDattorro* const, float freq); | 137 | void tDattorroReverb_setInputFilter (tDattorroReverb* const, float freq); |
| 139 | void tDattorro_setFeedbackFilter (tDattorro* const, float freq); | 138 | void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const, float freq); |
| 140 | void tDattorro_setFeedbackGain (tDattorro* const, float gain); | 139 | void tDattorroReverb_setFeedbackGain (tDattorroReverb* const, float gain); |
| 141 | 140 | ||
| 142 | #ifdef __cplusplus | 141 | #ifdef __cplusplus |
| 143 | } | 142 | } |
| @@ -1,125 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-sample.h | ||
| 4 | Created: 23 Jan 2019 11:22:09am | ||
| 5 | Author: Mike Mulshine | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | |||
| 10 | #ifndef LEAF_SAMPLE_H_INCLUDED | ||
| 11 | #define LEAF_SAMPLE_H_INCLUDED | ||
| 12 | |||
| 13 | #ifdef __cplusplus | ||
| 14 | extern "C" { | ||
| 15 | #endif | ||
| 16 | |||
| 17 | //============================================================================== | ||
| 18 | |||
| 19 | #include "leaf-global.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | |||
| 22 | #include "leaf-utilities.h" | ||
| 23 | |||
| 24 | //============================================================================== | ||
| 25 | |||
| 26 | typedef enum RecordMode | ||
| 27 | { | ||
| 28 | RecordOneShot = 0, | ||
| 29 | RecordLoop, | ||
| 30 | RecordModeNil | ||
| 31 | } RecordMode; | ||
| 32 | |||
| 33 | typedef struct _tBuffer | ||
| 34 | { | ||
| 35 | float* buff; | ||
| 36 | |||
| 37 | uint32_t idx; | ||
| 38 | uint32_t length; | ||
| 39 | |||
| 40 | RecordMode mode; | ||
| 41 | |||
| 42 | int active; | ||
| 43 | |||
| 44 | } tBuffer; | ||
| 45 | |||
| 46 | void tBuffer_init (tBuffer* const, uint32_t length); | ||
| 47 | void tBuffer_free (tBuffer* const); | ||
| 48 | |||
| 49 | void tBuffer_tick (tBuffer* const, float sample); | ||
| 50 | |||
| 51 | void tBuffer_read(tBuffer* const, float* buff, uint32_t len); | ||
| 52 | |||
| 53 | float tBuffer_get (tBuffer* const, int idx); | ||
| 54 | |||
| 55 | void tBuffer_record (tBuffer* const); | ||
| 56 | void tBuffer_stop (tBuffer* const); | ||
| 57 | |||
| 58 | void tBuffer_setRecordMode (tBuffer* const, RecordMode mode); | ||
| 59 | |||
| 60 | void tBuffer_clear (tBuffer* const); | ||
| 61 | |||
| 62 | //============================================================================== | ||
| 63 | |||
| 64 | typedef enum PlayMode | ||
| 65 | { | ||
| 66 | PlayNormal, | ||
| 67 | PlayLoop, | ||
| 68 | PlayBackAndForth, | ||
| 69 | PlayModeNil | ||
| 70 | } PlayMode; | ||
| 71 | |||
| 72 | typedef struct _tSampler | ||
| 73 | { | ||
| 74 | tBuffer* samp; | ||
| 75 | |||
| 76 | tRamp gain; | ||
| 77 | |||
| 78 | float idx; | ||
| 79 | float inc; | ||
| 80 | float last; | ||
| 81 | float iinc; | ||
| 82 | int8_t dir; | ||
| 83 | int8_t flip; | ||
| 84 | int8_t bnf; | ||
| 85 | |||
| 86 | int32_t start; | ||
| 87 | int32_t end; | ||
| 88 | uint32_t len; | ||
| 89 | uint32_t cfxlen; | ||
| 90 | |||
| 91 | PlayMode mode; | ||
| 92 | int retrigger; | ||
| 93 | |||
| 94 | int active; | ||
| 95 | |||
| 96 | } tSampler; | ||
| 97 | |||
| 98 | void tSampler_init (tSampler* const, tBuffer* const); | ||
| 99 | void tSampler_free (tSampler* const); | ||
| 100 | |||
| 101 | float tSampler_tick (tSampler* const); | ||
| 102 | |||
| 103 | void tSampler_setSample (tSampler* const, tBuffer* s); | ||
| 104 | |||
| 105 | void tSampler_setMode (tSampler* const, PlayMode mode); | ||
| 106 | |||
| 107 | void tSampler_play (tSampler* const); | ||
| 108 | void tSampler_stop (tSampler* const); | ||
| 109 | |||
| 110 | void tSampler_setStart (tSampler* const, int32_t start); | ||
| 111 | void tSampler_setEnd (tSampler* const, int32_t end); | ||
| 112 | |||
| 113 | void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length); | ||
| 114 | |||
| 115 | void tSampler_setRate (tSampler* const, float rate); | ||
| 116 | |||
| 117 | //============================================================================== | ||
| 118 | |||
| 119 | #ifdef __cplusplus | ||
| 120 | } | ||
| 121 | #endif | ||
| 122 | |||
| 123 | #endif // LEAF_SAMPLE_H_INCLUDED | ||
| 124 | |||
| 125 | //============================================================================== | ||
| @@ -0,0 +1,124 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-sampling.h | ||
| 4 | Created: 23 Jan 2019 11:22:09am | ||
| 5 | Author: Mike Mulshine | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | |||
| 10 | #ifndef LEAF_SAMPLING_H_INCLUDED | ||
| 11 | #define LEAF_SAMPLING_H_INCLUDED | ||
| 12 | |||
| 13 | #ifdef __cplusplus | ||
| 14 | extern "C" { | ||
| 15 | #endif | ||
| 16 | |||
| 17 | //============================================================================== | ||
| 18 | |||
| 19 | #include "leaf-global.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | #include "leaf-envelopes.h" | ||
| 22 | |||
| 23 | //============================================================================== | ||
| 24 | |||
| 25 | typedef enum RecordMode | ||
| 26 | { | ||
| 27 | RecordOneShot = 0, | ||
| 28 | RecordLoop, | ||
| 29 | RecordModeNil | ||
| 30 | } RecordMode; | ||
| 31 | |||
| 32 | typedef struct _tBuffer | ||
| 33 | { | ||
| 34 | float* buff; | ||
| 35 | |||
| 36 | uint32_t idx; | ||
| 37 | uint32_t length; | ||
| 38 | |||
| 39 | RecordMode mode; | ||
| 40 | |||
| 41 | int active; | ||
| 42 | |||
| 43 | } tBuffer; | ||
| 44 | |||
| 45 | void tBuffer_init (tBuffer* const, uint32_t length); | ||
| 46 | void tBuffer_free (tBuffer* const); | ||
| 47 | |||
| 48 | void tBuffer_tick (tBuffer* const, float sample); | ||
| 49 | |||
| 50 | void tBuffer_read(tBuffer* const, float* buff, uint32_t len); | ||
| 51 | |||
| 52 | float tBuffer_get (tBuffer* const, int idx); | ||
| 53 | |||
| 54 | void tBuffer_record (tBuffer* const); | ||
| 55 | void tBuffer_stop (tBuffer* const); | ||
| 56 | |||
| 57 | void tBuffer_setRecordMode (tBuffer* const, RecordMode mode); | ||
| 58 | |||
| 59 | void tBuffer_clear (tBuffer* const); | ||
| 60 | |||
| 61 | //============================================================================== | ||
| 62 | |||
| 63 | typedef enum PlayMode | ||
| 64 | { | ||
| 65 | PlayNormal, | ||
| 66 | PlayLoop, | ||
| 67 | PlayBackAndForth, | ||
| 68 | PlayModeNil | ||
| 69 | } PlayMode; | ||
| 70 | |||
| 71 | typedef struct _tSampler | ||
| 72 | { | ||
| 73 | tBuffer* samp; | ||
| 74 | |||
| 75 | tRamp gain; | ||
| 76 | |||
| 77 | float idx; | ||
| 78 | float inc; | ||
| 79 | float last; | ||
| 80 | float iinc; | ||
| 81 | int8_t dir; | ||
| 82 | int8_t flip; | ||
| 83 | int8_t bnf; | ||
| 84 | |||
| 85 | int32_t start; | ||
| 86 | int32_t end; | ||
| 87 | uint32_t len; | ||
| 88 | uint32_t cfxlen; | ||
| 89 | |||
| 90 | PlayMode mode; | ||
| 91 | int retrigger; | ||
| 92 | |||
| 93 | int active; | ||
| 94 | |||
| 95 | } tSampler; | ||
| 96 | |||
| 97 | void tSampler_init (tSampler* const, tBuffer* const); | ||
| 98 | void tSampler_free (tSampler* const); | ||
| 99 | |||
| 100 | float tSampler_tick (tSampler* const); | ||
| 101 | |||
| 102 | void tSampler_setSample (tSampler* const, tBuffer* s); | ||
| 103 | |||
| 104 | void tSampler_setMode (tSampler* const, PlayMode mode); | ||
| 105 | |||
| 106 | void tSampler_play (tSampler* const); | ||
| 107 | void tSampler_stop (tSampler* const); | ||
| 108 | |||
| 109 | void tSampler_setStart (tSampler* const, int32_t start); | ||
| 110 | void tSampler_setEnd (tSampler* const, int32_t end); | ||
| 111 | |||
| 112 | void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length); | ||
| 113 | |||
| 114 | void tSampler_setRate (tSampler* const, float rate); | ||
| 115 | |||
| 116 | //============================================================================== | ||
| 117 | |||
| 118 | #ifdef __cplusplus | ||
| 119 | } | ||
| 120 | #endif | ||
| 121 | |||
| 122 | #endif // LEAF_SAMPLING_H_INCLUDED | ||
| 123 | |||
| 124 | //============================================================================== | ||
| @@ -1,143 +0,0 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | leaf-string.h | ||
| 5 | Created: 30 Nov 2018 10:41:55am | ||
| 6 | Author: airship | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef LEAF_STRING_H_INCLUDED | ||
| 12 | #define LEAF_STRING_H_INCLUDED | ||
| 13 | |||
| 14 | #ifdef __cplusplus | ||
| 15 | extern "C" { | ||
| 16 | #endif | ||
| 17 | |||
| 18 | //============================================================================== | ||
| 19 | |||
| 20 | #include "leaf-global.h" | ||
| 21 | #include "leaf-math.h" | ||
| 22 | |||
| 23 | #include "leaf-delay.h" | ||
| 24 | #include "leaf-filter.h" | ||
| 25 | #include "leaf-oscillator.h" | ||
| 26 | |||
| 27 | //============================================================================== | ||
| 28 | |||
| 29 | /* Karplus Strong model */ | ||
| 30 | typedef struct _tPluck | ||
| 31 | { | ||
| 32 | tDelayA delayLine; // Allpass or Linear?? big difference... | ||
| 33 | tOneZero loopFilter; | ||
| 34 | tOnePole pickFilter; | ||
| 35 | tNoise noise; | ||
| 36 | |||
| 37 | float lastOut; | ||
| 38 | float loopGain; | ||
| 39 | float lastFreq; | ||
| 40 | |||
| 41 | float sr; | ||
| 42 | |||
| 43 | } tPluck; | ||
| 44 | |||
| 45 | void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]); | ||
| 46 | void tPluck_free (tPluck* const); | ||
| 47 | |||
| 48 | float tPluck_tick (tPluck* const); | ||
| 49 | |||
| 50 | // Pluck the string. | ||
| 51 | void tPluck_pluck (tPluck* const, float amplitude); | ||
| 52 | |||
| 53 | // Start a note with the given frequency and amplitude.; | ||
| 54 | void tPluck_noteOn (tPluck* const, float frequency, float amplitude ); | ||
| 55 | |||
| 56 | // Stop a note with the given amplitude (speed of decay). | ||
| 57 | void tPluck_noteOff (tPluck* const, float amplitude ); | ||
| 58 | |||
| 59 | // Set instrument parameters for a particular frequency. | ||
| 60 | void tPluck_setFrequency (tPluck* const, float frequency ); | ||
| 61 | |||
| 62 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 63 | void tPluck_controlChange (tPluck* const, int number, float value); | ||
| 64 | |||
| 65 | // tPluck Utilities. | ||
| 66 | float tPluck_getLastOut (tPluck* const); | ||
| 67 | |||
| 68 | //============================================================================== | ||
| 69 | |||
| 70 | /* Stif Karplus Strong model */ | ||
| 71 | typedef struct _tStifKarp | ||
| 72 | { | ||
| 73 | tDelayA delayLine; | ||
| 74 | tDelayL combDelay; | ||
| 75 | tOneZero filter; | ||
| 76 | tNoise noise; | ||
| 77 | tBiQuad biquad[4]; | ||
| 78 | |||
| 79 | |||
| 80 | |||
| 81 | uint32_t length; | ||
| 82 | float loopGain; | ||
| 83 | float baseLoopGain; | ||
| 84 | float lastFrequency; | ||
| 85 | float lastLength; | ||
| 86 | float stretching; | ||
| 87 | float pluckAmplitude; | ||
| 88 | float pickupPosition; | ||
| 89 | |||
| 90 | float lastOut; | ||
| 91 | |||
| 92 | } tStifKarp; | ||
| 93 | |||
| 94 | typedef enum SKControlType | ||
| 95 | { | ||
| 96 | SKPickPosition = 0, | ||
| 97 | SKStringDamping, | ||
| 98 | SKDetune, | ||
| 99 | SKControlTypeNil | ||
| 100 | } SKControlType; | ||
| 101 | |||
| 102 | void tStifKarp_init (tStifKarp* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]); | ||
| 103 | void tStifKarp_free (tStifKarp* const); | ||
| 104 | |||
| 105 | float tStifKarp_tick (tStifKarp* const); | ||
| 106 | |||
| 107 | // Pluck the string. | ||
| 108 | void tStifKarp_pluck (tStifKarp* const, float amplitude); | ||
| 109 | |||
| 110 | // Start a note with the given frequency and amplitude.; | ||
| 111 | void tStifKarp_noteOn (tStifKarp* const, float frequency, float amplitude ); | ||
| 112 | |||
| 113 | // Stop a note with the given amplitude (speed of decay). | ||
| 114 | void tStifKarp_noteOff (tStifKarp* const, float amplitude ); | ||
| 115 | |||
| 116 | // Set instrument parameters for a particular frequency. | ||
| 117 | void tStifKarp_setFrequency (tStifKarp* const, float frequency ); | ||
| 118 | |||
| 119 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 120 | // Use SKPickPosition, SKStringDamping, or SKDetune for type. | ||
| 121 | void tStifKarp_controlChange (tStifKarp* const, SKControlType type, float value); | ||
| 122 | |||
| 123 | // Set the stretch "factor" of the string (0.0 - 1.0). | ||
| 124 | void tStifKarp_setStretch (tStifKarp* const, float stretch ); | ||
| 125 | |||
| 126 | // Set the pluck or "excitation" position along the string (0.0 - 1.0). | ||
| 127 | void tStifKarp_setPickupPosition (tStifKarp* const, float position ); | ||
| 128 | |||
| 129 | // Set the base loop gain. | ||
| 130 | void tStifKarp_setBaseLoopGain (tStifKarp* const, float aGain ); | ||
| 131 | |||
| 132 | // tStifKarp utilities. | ||
| 133 | float tStifKarp_getLastOut (tStifKarp* const); | ||
| 134 | |||
| 135 | //============================================================================== | ||
| 136 | |||
| 137 | #ifdef __cplusplus | ||
| 138 | } | ||
| 139 | #endif | ||
| 140 | |||
| 141 | #endif // LEAF_STRING_H_INCLUDED | ||
| 142 | |||
| 143 | //============================================================================== | ||
| @@ -6,8 +6,8 @@ · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | ==============================================================================*/ | 7 | ==============================================================================*/ |
| 8 | 8 | ||
| 9 | #ifndef LEAF_WAVETABLES_H_INCLUDED | 9 | #ifndef LEAF_TABLES_H_INCLUDED |
| 10 | #define LEAF_WAVETABLES_H_INCLUDED | 10 | #define LEAF_TABLES_H_INCLUDED |
| 11 | 11 | ||
| 12 | #ifdef __cplusplus | 12 | #ifdef __cplusplus |
| 13 | extern "C" { | 13 | extern "C" { |
| @@ -95,6 +95,6 @@ extern const float squarewave[11][SQR_TABLE_SIZE]; · 81 unmodified lines | |||
| 95 | } | 95 | } |
| 96 | #endif | 96 | #endif |
| 97 | 97 | ||
| 98 | #endif // LEAF_WAVETABLES_H_INCLUDED | 98 | #endif // LEAF_TABLES_H_INCLUDED |
| 99 | 99 | ||
| 100 | //============================================================================== | 100 | //============================================================================== |
| @@ -1,483 +0,0 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | LEAFUtilities.h | ||
| 5 | Created: 20 Jan 2017 12:02:17pm | ||
| 6 | Author: Michael R Mulshine | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef LEAFUTILITIES_H_INCLUDED | ||
| 12 | #define LEAFUTILITIES_H_INCLUDED | ||
| 13 | |||
| 14 | #ifdef __cplusplus | ||
| 15 | extern "C" { | ||
| 16 | #endif | ||
| 17 | |||
| 18 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 19 | |||
| 20 | #include "leaf-math.h" | ||
| 21 | #include "leaf-filter.h" | ||
| 22 | #include "leaf-delay.h" | ||
| 23 | |||
| 24 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 25 | |||
| 26 | // STACK implementation (fixed size) | ||
| 27 | #define STACK_SIZE 128 | ||
| 28 | typedef struct _tStack | ||
| 29 | { | ||
| 30 | int data[STACK_SIZE]; | ||
| 31 | uint16_t pos; | ||
| 32 | uint16_t size; | ||
| 33 | uint16_t capacity; | ||
| 34 | oBool ordered; | ||
| 35 | |||
| 36 | } tStack; | ||
| 37 | |||
| 38 | void tStack_init (tStack* const); | ||
| 39 | void tStack_free (tStack* const); | ||
| 40 | |||
| 41 | void tStack_setCapacity (tStack* const, uint16_t cap); | ||
| 42 | int tStack_addIfNotAlreadyThere (tStack* const, uint16_t item); | ||
| 43 | void tStack_add (tStack* const, uint16_t item); | ||
| 44 | int tStack_remove (tStack* const, uint16_t item); | ||
| 45 | void tStack_clear (tStack* const); | ||
| 46 | int tStack_first (tStack* const); | ||
| 47 | int tStack_getSize (tStack* const); | ||
| 48 | int tStack_contains (tStack* const, uint16_t item); | ||
| 49 | int tStack_next (tStack* const); | ||
| 50 | int tStack_get (tStack* const, int which); | ||
| 51 | |||
| 52 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 53 | |||
| 54 | /* Ramp */ | ||
| 55 | typedef struct _tRamp { | ||
| 56 | float inc; | ||
| 57 | float inv_sr_ms; | ||
| 58 | float minimum_time; | ||
| 59 | float curr,dest; | ||
| 60 | float time; | ||
| 61 | int samples_per_tick; | ||
| 62 | |||
| 63 | } tRamp; | ||
| 64 | |||
| 65 | void tRamp_init (tRamp* const, float time, int samplesPerTick); | ||
| 66 | void tRamp_free (tRamp* const); | ||
| 67 | |||
| 68 | float tRamp_tick (tRamp* const); | ||
| 69 | float tRamp_sample (tRamp* const); | ||
| 70 | int tRamp_setTime (tRamp* const, float time); | ||
| 71 | int tRamp_setDest (tRamp* const, float dest); | ||
| 72 | int tRamp_setVal (tRamp* const, float val); | ||
| 73 | |||
| 74 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 75 | |||
| 76 | /* Exponential Smoother */ | ||
| 77 | typedef struct _tExpSmooth { | ||
| 78 | float factor, oneminusfactor; | ||
| 79 | float curr,dest; | ||
| 80 | |||
| 81 | } tExpSmooth; | ||
| 82 | |||
| 83 | void tExpSmooth_init (tExpSmooth* const, float val, float factor); | ||
| 84 | void tExpSmooth_free (tExpSmooth* const); | ||
| 85 | |||
| 86 | float tExpSmooth_tick (tExpSmooth* const); | ||
| 87 | float tExpSmooth_sample (tExpSmooth* const); | ||
| 88 | int tExpSmooth_setFactor (tExpSmooth* const, float factor); | ||
| 89 | int tExpSmooth_setDest (tExpSmooth* const, float dest); | ||
| 90 | int tExpSmooth_setVal (tExpSmooth* const, float val); | ||
| 91 | |||
| 92 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 93 | |||
| 94 | /* PowerEnvelopeFollower */ | ||
| 95 | typedef struct _tPwrFollow { | ||
| 96 | float factor, oneminusfactor; | ||
| 97 | float curr; | ||
| 98 | |||
| 99 | } tPwrFollow; | ||
| 100 | |||
| 101 | void tPwrFollow_init (tPwrFollow* const, float factor); | ||
| 102 | void tPwrFollow_free (tPwrFollow* const); | ||
| 103 | float tPwrFollow_tick (tPwrFollow* const, float input); | ||
| 104 | float tPwrFollow_sample (tPwrFollow* const); | ||
| 105 | int tPwrFollow_setFactor (tPwrFollow* const, float factor); | ||
| 106 | |||
| 107 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 108 | |||
| 109 | //Reed Table - borrowed from STK | ||
| 110 | typedef struct _tReedTable { | ||
| 111 | float offset, slope; | ||
| 112 | } tReedTable; | ||
| 113 | |||
| 114 | void tReedTable_init (tReedTable* const, float offset, float slope); | ||
| 115 | void tReedTable_free (tReedTable* const); | ||
| 116 | float tReedTable_tick (tReedTable* const, float input); | ||
| 117 | float tReedTable_tanh_tick (tReedTable* const p, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code | ||
| 118 | void tReedTable_setOffset (tReedTable* const, float offset); | ||
| 119 | void tReedTable_setSlope (tReedTable* const, float slope); | ||
| 120 | |||
| 121 | |||
| 122 | |||
| 123 | /// | ||
| 124 | /* Feedback leveller */ | ||
| 125 | // An auto VCA that you put into a feedback circuit to make it stay at the same level. | ||
| 126 | // It can enforce level bidirectionally (amplifying and attenuating as needed) or | ||
| 127 | // just attenutating. The former option allows for infinite sustain strings, for example, while | ||
| 128 | // The latter option allows for decaying strings, which can never exceed | ||
| 129 | // a specific level. | ||
| 130 | |||
| 131 | typedef struct _tFBleveller { | ||
| 132 | float targetLevel; // target power level | ||
| 133 | float strength; // how strongly level difference affects the VCA | ||
| 134 | int mode; // 0 for upwards limiting only, 1 for biderctional limiting | ||
| 135 | float curr; | ||
| 136 | tPwrFollow pwrFlw; // internal power follower needed for level tracking | ||
| 137 | |||
| 138 | } tFBleveller; | ||
| 139 | |||
| 140 | void tFBleveller_init (tFBleveller* const, float targetLevel, float factor, float strength, int mode); | ||
| 141 | void tFBleveller_free (tFBleveller* const); | ||
| 142 | |||
| 143 | float tFBleveller_tick (tFBleveller* const, float input); | ||
| 144 | float tFBleveller_sample (tFBleveller* const); | ||
| 145 | int tFBleveller_setTargetLevel (tFBleveller* const, float TargetLevel); | ||
| 146 | int tFBleveller_setFactor (tFBleveller* const, float factor); | ||
| 147 | int tFBleveller_setMode (tFBleveller* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting | ||
| 148 | int tFBleveller_setStrength (tFBleveller* const, float strength); | ||
| 149 | |||
| 150 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 151 | |||
| 152 | /* Simple Living String */ | ||
| 153 | typedef struct _tSimpleLivingString { | ||
| 154 | float freq, waveLengthInSamples; // the frequency of the string, determining delay length | ||
| 155 | float dampFreq; // frequency for the bridge LP filter, in Hz | ||
| 156 | float decay; // amplitude damping factor for the string (only active in mode 0) | ||
| 157 | float levMode; | ||
| 158 | float curr; | ||
| 159 | tDelayL delayLine; | ||
| 160 | tOnePole bridgeFilter; | ||
| 161 | tHighpass DCblocker; | ||
| 162 | tFBleveller fbLev; | ||
| 163 | tExpSmooth wlSmooth; | ||
| 164 | } tSimpleLivingString; | ||
| 165 | |||
| 166 | void tSimpleLivingString_init (tSimpleLivingString* const, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode); | ||
| 167 | void tSimpleLivingString_free (tSimpleLivingString* const); | ||
| 168 | float tSimpleLivingString_tick (tSimpleLivingString* const, float input); | ||
| 169 | float tSimpleLivingString_sample (tSimpleLivingString* const); | ||
| 170 | int tSimpleLivingString_setFreq (tSimpleLivingString* const, float freq); | ||
| 171 | int tSimpleLivingString_setWaveLength (tSimpleLivingString* const, float waveLength); // in samples | ||
| 172 | int tSimpleLivingString_setDampFreq (tSimpleLivingString* const, float dampFreq); | ||
| 173 | int tSimpleLivingString_setDecay (tSimpleLivingString* const, float decay); // should be near 1.0 | ||
| 174 | int tSimpleLivingString_setTargetLev (tSimpleLivingString* const, float targetLev); | ||
| 175 | int tSimpleLivingString_setLevSmoothFactor (tSimpleLivingString* const, float levSmoothFactor); | ||
| 176 | int tSimpleLivingString_setLevStrength (tSimpleLivingString* const, float levStrength); | ||
| 177 | int tSimpleLivingString_setLevMode (tSimpleLivingString* const, int levMode); | ||
| 178 | |||
| 179 | |||
| 180 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 181 | |||
| 182 | /* Living String */ | ||
| 183 | typedef struct _tLivingString { | ||
| 184 | float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length | ||
| 185 | float pickPos; // the pick position, dividing the string in two, in ratio | ||
| 186 | float prepIndex; // the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj) | ||
| 187 | float dampFreq; // frequency for the bridge LP filter, in Hz | ||
| 188 | float decay; // amplitude damping factor for the string (only active in mode 0) | ||
| 189 | float levMode; | ||
| 190 | float curr; | ||
| 191 | tDelayL delLF,delUF,delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model | ||
| 192 | tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL; | ||
| 193 | tHighpass DCblockerL, DCblockerU; | ||
| 194 | tFBleveller fbLevU, fbLevL; | ||
| 195 | tExpSmooth wlSmooth, ppSmooth; | ||
| 196 | } tLivingString; | ||
| 197 | |||
| 198 | void tLivingString_init (tLivingString* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay, | ||
| 199 | float targetLev, float levSmoothFactor, float levStrength, int levMode); | ||
| 200 | void tLivingString_free (tLivingString* const); | ||
| 201 | float tLivingString_tick (tLivingString* const, float input); | ||
| 202 | float tLivingString_sample (tLivingString* const); | ||
| 203 | int tLivingString_setFreq (tLivingString* const, float freq); | ||
| 204 | int tLivingString_setWaveLength (tLivingString* const, float waveLength); // in samples | ||
| 205 | int tLivingString_setPickPos (tLivingString* const, float pickPos); | ||
| 206 | int tLivingString_setPrepIndex (tLivingString* const, float prepIndex); | ||
| 207 | int tLivingString_setDampFreq (tLivingString* const, float dampFreq); | ||
| 208 | int tLivingString_setDecay (tLivingString* const, float decay); // should be near 1.0 | ||
| 209 | int tLivingString_setTargetLev (tLivingString* const, float targetLev); | ||
| 210 | int tLivingString_setLevSmoothFactor (tLivingString* const, float levSmoothFactor); | ||
| 211 | int tLivingString_setLevStrength (tLivingString* const, float levStrength); | ||
| 212 | int tLivingString_setLevMode (tLivingString* const, int levMode); | ||
| 213 | |||
| 214 | |||
| 215 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 216 | |||
| 217 | /* Compressor */ | ||
| 218 | typedef struct _tCompressor | ||
| 219 | { | ||
| 220 | float tauAttack, tauRelease; | ||
| 221 | float T, R, W, M; // Threshold, compression Ratio, decibel Width of knee transition, decibel Make-up gain | ||
| 222 | |||
| 223 | float x_G[2], y_G[2], x_T[2], y_T[2]; | ||
| 224 | |||
| 225 | oBool isActive; | ||
| 226 | |||
| 227 | }tCompressor; | ||
| 228 | |||
| 229 | void tCompressor_init (tCompressor* const); | ||
| 230 | void tCompressor_free (tCompressor* const); | ||
| 231 | float tCompressor_tick (tCompressor* const, float input); | ||
| 232 | |||
| 233 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 234 | |||
| 235 | /* Attack-Decay envelope */ | ||
| 236 | typedef struct _tEnvelope { | ||
| 237 | |||
| 238 | const float *exp_buff; | ||
| 239 | const float *inc_buff; | ||
| 240 | uint32_t buff_size; | ||
| 241 | |||
| 242 | float next; | ||
| 243 | |||
| 244 | float attackInc, decayInc, rampInc; | ||
| 245 | |||
| 246 | oBool inAttack, inDecay, inRamp; | ||
| 247 | |||
| 248 | oBool loop; | ||
| 249 | |||
| 250 | float gain, rampPeak; | ||
| 251 | |||
| 252 | float attackPhase, decayPhase, rampPhase; | ||
| 253 | |||
| 254 | } tEnvelope; | ||
| 255 | |||
| 256 | void tEnvelope_init (tEnvelope* const, float attack, float decay, oBool loop); | ||
| 257 | void tEnvelope_free (tEnvelope* const); | ||
| 258 | |||
| 259 | float tEnvelope_tick (tEnvelope* const); | ||
| 260 | int tEnvelope_setAttack (tEnvelope* const, float attack); | ||
| 261 | int tEnvelope_setDecay (tEnvelope* const, float decay); | ||
| 262 | int tEnvelope_loop (tEnvelope* const, oBool loop); | ||
| 263 | int tEnvelope_on (tEnvelope* const, float velocity); | ||
| 264 | |||
| 265 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 266 | |||
| 267 | /* ADSR */ | ||
| 268 | typedef struct _tADSR | ||
| 269 | { | ||
| 270 | const float *exp_buff; | ||
| 271 | const float *inc_buff; | ||
| 272 | uint32_t buff_size; | ||
| 273 | |||
| 274 | float next; | ||
| 275 | |||
| 276 | float attackInc, decayInc, releaseInc, rampInc; | ||
| 277 | |||
| 278 | oBool inAttack, inDecay, inSustain, inRelease, inRamp; | ||
| 279 | |||
| 280 | float sustain, gain, rampPeak, releasePeak; | ||
| 281 | |||
| 282 | float attackPhase, decayPhase, releasePhase, rampPhase; | ||
| 283 | |||
| 284 | } tADSR; | ||
| 285 | |||
| 286 | void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release); | ||
| 287 | void tADSR_free (tADSR* const); | ||
| 288 | |||
| 289 | float tADSR_tick (tADSR* const); | ||
| 290 | int tADSR_setAttack (tADSR* const, float attack); | ||
| 291 | int tADSR_setDecay (tADSR* const, float decay); | ||
| 292 | int tADSR_setSustain(tADSR* const, float sustain); | ||
| 293 | int tADSR_setRelease(tADSR* const, float release); | ||
| 294 | int tADSR_on (tADSR* const, float velocity); | ||
| 295 | int tADSR_off (tADSR* const); | ||
| 296 | |||
| 297 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 298 | |||
| 299 | /* Envelope Follower */ | ||
| 300 | typedef struct _tEnvelopeFollower | ||
| 301 | { | ||
| 302 | float y; | ||
| 303 | float a_thresh; | ||
| 304 | float d_coeff; | ||
| 305 | |||
| 306 | } tEnvelopeFollower; | ||
| 307 | |||
| 308 | void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff); | ||
| 309 | void tEnvelopeFollower_free (tEnvelopeFollower* const); | ||
| 310 | |||
| 311 | float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x); | ||
| 312 | int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff); | ||
| 313 | int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh); | ||
| 314 | |||
| 315 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 316 | |||
| 317 | /* tAtkDtk */ | ||
| 318 | #define DEFBLOCKSIZE 1024 | ||
| 319 | #define DEFTHRESHOLD 6 | ||
| 320 | #define DEFATTACK 10 | ||
| 321 | #define DEFRELEASE 10 | ||
| 322 | |||
| 323 | typedef struct _tAtkDtk | ||
| 324 | { | ||
| 325 | float env; | ||
| 326 | |||
| 327 | //Attack & Release times in msec | ||
| 328 | int atk; | ||
| 329 | int rel; | ||
| 330 | |||
| 331 | //Attack & Release coefficients based on times | ||
| 332 | float atk_coeff; | ||
| 333 | float rel_coeff; | ||
| 334 | |||
| 335 | int blocksize; | ||
| 336 | int samplerate; | ||
| 337 | |||
| 338 | //RMS amplitude of previous block - used to decide if attack is present | ||
| 339 | float prevAmp; | ||
| 340 | |||
| 341 | float threshold; | ||
| 342 | } tAtkDtk; | ||
| 343 | |||
| 344 | void tAtkDtk_init (tAtkDtk* const, int blocksize); | ||
| 345 | void tAtkDtk_init_expanded (tAtkDtk* const, int blocksize, int atk, int rel); | ||
| 346 | void tAtkDtk_free (tAtkDtk* const); | ||
| 347 | |||
| 348 | // set expected input blocksize | ||
| 349 | void tAtkDtk_setBlocksize (tAtkDtk* const, int size); | ||
| 350 | |||
| 351 | // change atkDetector sample rate | ||
| 352 | void tAtkDtk_setSamplerate (tAtkDtk* const, int inRate); | ||
| 353 | |||
| 354 | // set attack time and coeff | ||
| 355 | void tAtkDtk_setAtk (tAtkDtk* const, int inAtk); | ||
| 356 | |||
| 357 | // set release time and coeff | ||
| 358 | void tAtkDtk_setRel (tAtkDtk* const, int inRel); | ||
| 359 | |||
| 360 | // set level above which values are identified as attacks | ||
| 361 | void tAtkDtk_setThreshold (tAtkDtk* const, float thres); | ||
| 362 | |||
| 363 | // find largest transient in input block, return index of attack | ||
| 364 | int tAtkDtk_detect (tAtkDtk* const, float *in); | ||
| 365 | |||
| 366 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 367 | |||
| 368 | // ENV~ from PD, modified for LEAF | ||
| 369 | #define MAXOVERLAP 32 | ||
| 370 | #define INITVSTAKEN 64 | ||
| 371 | #define ENV_WINDOW_SIZE 1024 | ||
| 372 | #define ENV_HOP_SIZE 256 | ||
| 373 | |||
| 374 | typedef struct _tEnv | ||
| 375 | { | ||
| 376 | float buf[ENV_WINDOW_SIZE + INITVSTAKEN]; | ||
| 377 | uint16_t x_phase; /* number of points since last output */ | ||
| 378 | uint16_t x_period; /* requested period of output */ | ||
| 379 | uint16_t x_realperiod; /* period rounded up to vecsize multiple */ | ||
| 380 | uint16_t x_npoints; /* analysis window size in samples */ | ||
| 381 | float x_result; /* result to output */ | ||
| 382 | float x_sumbuf[MAXOVERLAP]; /* summing buffer */ | ||
| 383 | float x_f; | ||
| 384 | uint16_t windowSize, hopSize, blockSize; | ||
| 385 | uint16_t x_allocforvs; /* extra buffer for DSP vector size */ | ||
| 386 | } tEnv; | ||
| 387 | |||
| 388 | void tEnv_init (tEnv* const, int windowSize, int hopSize, int blockSize); | ||
| 389 | void tEnv_free (tEnv* const); | ||
| 390 | float tEnv_tick (tEnv* const); | ||
| 391 | void tEnv_processBlock (tEnv* const, float* in); | ||
| 392 | |||
| 393 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 394 | |||
| 395 | /* tSOLAD : pitch shifting algorithm that underlies tPitchShifter etc */ | ||
| 396 | #define LOOPSIZE (2048*2) // (4096*2) // loop size must be power of two | ||
| 397 | #define LOOPMASK (LOOPSIZE - 1) | ||
| 398 | #define PITCHFACTORDEFAULT 1.0f | ||
| 399 | #define INITPERIOD 64.0f | ||
| 400 | #define MAXPERIOD (float)((LOOPSIZE - w->blocksize) * 0.8f) | ||
| 401 | #define MINPERIOD 8.0f | ||
| 402 | |||
| 403 | typedef struct _tSOLAD | ||
| 404 | { | ||
| 405 | uint16_t timeindex; // current reference time, write index | ||
| 406 | uint16_t blocksize; // signal input / output block size | ||
| 407 | float pitchfactor; // pitch factor between 0.25 and 4 | ||
| 408 | float readlag; // read pointer's lag behind write pointer | ||
| 409 | float period; // period length in input signal | ||
| 410 | float jump; // read pointer jump length and direction | ||
| 411 | float xfadelength; // crossfade length expressed at input sample rate | ||
| 412 | float xfadevalue; // crossfade phase and value | ||
| 413 | |||
| 414 | float* delaybuf; | ||
| 415 | |||
| 416 | } tSOLAD; | ||
| 417 | |||
| 418 | void tSOLAD_init (tSOLAD* const); | ||
| 419 | void tSOLAD_free (tSOLAD* const); | ||
| 420 | |||
| 421 | // send one block of input samples, receive one block of output samples | ||
| 422 | void tSOLAD_ioSamples (tSOLAD *w, float* in, float* out, int blocksize); | ||
| 423 | |||
| 424 | // set periodicity analysis data | ||
| 425 | void tSOLAD_setPeriod (tSOLAD *w, float period); | ||
| 426 | |||
| 427 | // set pitch factor between 0.25 and 4 | ||
| 428 | void tSOLAD_setPitchFactor (tSOLAD *w, float pitchfactor); | ||
| 429 | |||
| 430 | // force readpointer lag | ||
| 431 | void tSOLAD_setReadLag (tSOLAD *w, float readlag); | ||
| 432 | |||
| 433 | // reset state variables | ||
| 434 | void tSOLAD_resetState (tSOLAD *w); | ||
| 435 | |||
| 436 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 437 | |||
| 438 | // tSNAC: period detector | ||
| 439 | #define SNAC_FRAME_SIZE 1024 // default analysis framesize // should be the same as (or smaller than?) PS_FRAME_SIZE | ||
| 440 | #define DEFOVERLAP 1 // default overlap | ||
| 441 | #define DEFBIAS 0.2f // default bias | ||
| 442 | #define DEFMINRMS 0.003f // default minimum RMS | ||
| 443 | #define SEEK 0.85f // seek-length as ratio of framesize | ||
| 444 | |||
| 445 | typedef struct _tSNAC | ||
| 446 | { | ||
| 447 | float* inputbuf; | ||
| 448 | float* processbuf; | ||
| 449 | float* spectrumbuf; | ||
| 450 | float* biasbuf; | ||
| 451 | uint16_t timeindex; | ||
| 452 | uint16_t framesize; | ||
| 453 | uint16_t overlap; | ||
| 454 | uint16_t periodindex; | ||
| 455 | |||
| 456 | float periodlength; | ||
| 457 | float fidelity; | ||
| 458 | float biasfactor; | ||
| 459 | float minrms; | ||
| 460 | |||
| 461 | } tSNAC; | ||
| 462 | |||
| 463 | void tSNAC_init (tSNAC* const, int overlaparg); // constructor | ||
| 464 | void tSNAC_free (tSNAC* const); // destructor | ||
| 465 | |||
| 466 | void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size); | ||
| 467 | void tSNAC_setOverlap (tSNAC *s, int lap); | ||
| 468 | void tSNAC_setBias (tSNAC *s, float bias); | ||
| 469 | void tSNAC_setMinRMS (tSNAC *s, float rms); | ||
| 470 | |||
| 471 | /*To get freq, perform SAMPLE_RATE/snac_getperiod() */ | ||
| 472 | float tSNAC_getPeriod (tSNAC *s); | ||
| 473 | float tSNAC_getfidelity (tSNAC *s); | ||
| 474 | |||
| 475 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 476 | |||
| 477 | #ifdef __cplusplus | ||
| 478 | } | ||
| 479 | #endif | ||
| 480 | |||
| 481 | #endif // LEAFUTILITIES_H_INCLUDED | ||
| 482 | |||
| 483 | |||
| @@ -1,89 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-vocoder.h | ||
| 4 | Created: 20 Jan 2017 12:01:54pm | ||
| 5 | Author: Michael R Mulshine | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_VOCODER_H_INCLUDED | ||
| 10 | #define LEAF_VOCODER_H_INCLUDED | ||
| 11 | |||
| 12 | #ifdef __cplusplus | ||
| 13 | extern "C" { | ||
| 14 | #endif | ||
| 15 | |||
| 16 | //============================================================================== | ||
| 17 | |||
| 18 | #include "leaf-global.h" | ||
| 19 | #include "leaf-math.h" | ||
| 20 | |||
| 21 | //============================================================================== | ||
| 22 | |||
| 23 | /* tTalkbox */ | ||
| 24 | #define NUM_TALKBOX_PARAM 4 | ||
| 25 | |||
| 26 | typedef struct _tTalkbox | ||
| 27 | { | ||
| 28 | float param[NUM_TALKBOX_PARAM]; | ||
| 29 | |||
| 30 | int bufsize; | ||
| 31 | float* car0; | ||
| 32 | float* car1; | ||
| 33 | float* window; | ||
| 34 | float* buf0; | ||
| 35 | float* buf1; | ||
| 36 | |||
| 37 | float emphasis; | ||
| 38 | int32_t K, N, O, pos; | ||
| 39 | float wet, dry, FX; | ||
| 40 | float d0, d1, d2, d3, d4; | ||
| 41 | float u0, u1, u2, u3, u4; | ||
| 42 | |||
| 43 | } tTalkbox; | ||
| 44 | |||
| 45 | void tTalkbox_init (tTalkbox* const, int bufsize); | ||
| 46 | void tTalkbox_free (tTalkbox* const); | ||
| 47 | float tTalkbox_tick (tTalkbox* const, float synth, float voice); | ||
| 48 | void tTalkbox_update (tTalkbox* const); | ||
| 49 | void tTalkbox_suspend (tTalkbox* const); | ||
| 50 | void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g); | ||
| 51 | void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o); | ||
| 52 | void tTalkbox_setQuality (tTalkbox* const, float quality); | ||
| 53 | |||
| 54 | //============================================================================== | ||
| 55 | |||
| 56 | /* tVocoder */ | ||
| 57 | #define NUM_VOCODER_PARAM 8 | ||
| 58 | #define NBANDS 16 | ||
| 59 | |||
| 60 | typedef struct _tVocoder | ||
| 61 | { | ||
| 62 | float param[NUM_VOCODER_PARAM]; | ||
| 63 | |||
| 64 | float gain; //output level | ||
| 65 | float thru, high; //hf thru | ||
| 66 | float kout; //downsampled output | ||
| 67 | int32_t kval; //downsample counter | ||
| 68 | int32_t nbnd; //number of bands | ||
| 69 | |||
| 70 | //filter coeffs and buffers - seems it's faster to leave this global than make local copy | ||
| 71 | float f[NBANDS][13]; //[0-8][0 1 2 | 0 1 2 3 | 0 1 2 3 | val rate] | ||
| 72 | |||
| 73 | } tVocoder; | ||
| 74 | |||
| 75 | void tVocoder_init (tVocoder* const); | ||
| 76 | void tVocoder_free (tVocoder* const); | ||
| 77 | float tVocoder_tick (tVocoder* const, float synth, float voice); | ||
| 78 | void tVocoder_update (tVocoder* const); | ||
| 79 | void tVocoder_suspend (tVocoder* const); | ||
| 80 | |||
| 81 | //============================================================================== | ||
| 82 | |||
| 83 | #ifdef __cplusplus | ||
| 84 | } | ||
| 85 | #endif | ||
| 86 | |||
| 87 | #endif // LEAF_VOCODER_H_INCLUDED | ||
| 88 | |||
| 89 | //============================================================================== | ||
| @@ -1,48 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-wavefolder.h | ||
| 4 | Created: 30 Nov 2018 11:57:05am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #ifndef LEAF_WAVEFOLDER_H_INCLUDED | ||
| 10 | #define LEAF_WAVEFOLDER_H_INCLUDED | ||
| 11 | |||
| 12 | |||
| 13 | #ifdef __cplusplus | ||
| 14 | extern "C" { | ||
| 15 | #endif | ||
| 16 | |||
| 17 | //============================================================================== | ||
| 18 | |||
| 19 | #include "leaf-global.h" | ||
| 20 | #include "leaf-math.h" | ||
| 21 | |||
| 22 | //============================================================================== | ||
| 23 | |||
| 24 | /* tLockhartWavefolder */ | ||
| 25 | |||
| 26 | typedef struct _tLockhartWavefolder | ||
| 27 | { | ||
| 28 | double Ln1; | ||
| 29 | double Fn1; | ||
| 30 | float xn1; | ||
| 31 | |||
| 32 | } tLockhartWavefolder; | ||
| 33 | |||
| 34 | void tLockhartWavefolder_init (tLockhartWavefolder* const); | ||
| 35 | void tLockhartWavefolder_free (tLockhartWavefolder* const); | ||
| 36 | |||
| 37 | float tLockhartWavefolder_tick (tLockhartWavefolder* const, float samp); | ||
| 38 | |||
| 39 | |||
| 40 | //============================================================================== | ||
| 41 | |||
| 42 | #ifdef __cplusplus | ||
| 43 | } | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #endif // LEAF_WAVEFOLDER_H_INCLUDED | ||
| 47 | |||
| 48 | //============================================================================== | ||
| @@ -0,0 +1,733 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-analysis.c | ||
| 4 | Created: 30 Nov 2018 11:56:49am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-analysis.h" | ||
| 12 | #include "..\Externals\d_fft_mayer.h" | ||
| 13 | |||
| 14 | #else | ||
| 15 | |||
| 16 | #include "../Inc/leaf-analysis.h" | ||
| 17 | #include "../Externals/d_fft_mayer.h" | ||
| 18 | |||
| 19 | #endif | ||
| 20 | |||
| 21 | //=========================================================================== | ||
| 22 | /* Envelope Follower */ | ||
| 23 | //=========================================================================== | ||
| 24 | |||
| 25 | void tEnvelopeFollower_init(tEnvelopeFollower* const e, float attackThreshold, float decayCoeff) | ||
| 26 | { | ||
| 27 | e->y = 0.0f; | ||
| 28 | e->a_thresh = attackThreshold; | ||
| 29 | e->d_coeff = decayCoeff; | ||
| 30 | } | ||
| 31 | |||
| 32 | void tEnvelopeFollower_free(tEnvelopeFollower* const e) | ||
| 33 | { | ||
| 34 | |||
| 35 | } | ||
| 36 | |||
| 37 | float tEnvelopeFollower_tick(tEnvelopeFollower* const ef, float x) | ||
| 38 | { | ||
| 39 | if (x < 0.0f ) x = -x; /* Absolute value. */ | ||
| 40 | |||
| 41 | if ((x >= ef->y) && (x > ef->a_thresh)) ef->y = x; /* If we hit a peak, ride the peak to the top. */ | ||
| 42 | else ef->y = ef->y * ef->d_coeff; /* Else, exponential decay of output. */ | ||
| 43 | |||
| 44 | //ef->y = envelope_pow[(uint16_t)(ef->y * (float)UINT16_MAX)] * ef->d_coeff; //not quite the right behavior - too much loss of precision? | ||
| 45 | //ef->y = powf(ef->y, 1.000009f) * ef->d_coeff; // too expensive | ||
| 46 | |||
| 47 | if( ef->y < VSF) ef->y = 0.0f; | ||
| 48 | |||
| 49 | return ef->y; | ||
| 50 | } | ||
| 51 | |||
| 52 | int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff) | ||
| 53 | { | ||
| 54 | return ef->d_coeff = decayCoeff; | ||
| 55 | } | ||
| 56 | |||
| 57 | int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attackThresh) | ||
| 58 | { | ||
| 59 | return ef->a_thresh = attackThresh; | ||
| 60 | } | ||
| 61 | |||
| 62 | |||
| 63 | |||
| 64 | |||
| 65 | |||
| 66 | //=========================================================================== | ||
| 67 | /* Power Follower */ | ||
| 68 | //=========================================================================== | ||
| 69 | void tPowerFollower_init(tPowerFollower* const p, float factor) | ||
| 70 | { | ||
| 71 | p->curr=0.0f; | ||
| 72 | p->factor=factor; | ||
| 73 | p->oneminusfactor=1.0f-factor; | ||
| 74 | } | ||
| 75 | |||
| 76 | void tPowerFollower_free(tPowerFollower* const p) | ||
| 77 | { | ||
| 78 | |||
| 79 | } | ||
| 80 | |||
| 81 | int tPowerFollower_setFactor(tPowerFollower* const p, float factor) | ||
| 82 | { | ||
| 83 | if (factor<0) factor=0; | ||
| 84 | if (factor>1) factor=1; | ||
| 85 | p->factor=factor; | ||
| 86 | p->oneminusfactor=1.0f-factor; | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | float tPowerFollower_tick(tPowerFollower* const p, float input) | ||
| 91 | { | ||
| 92 | p->curr = p->factor*input*input+p->oneminusfactor*p->curr; | ||
| 93 | return p->curr; | ||
| 94 | } | ||
| 95 | |||
| 96 | float tPowerFollower_sample(tPowerFollower* const p) | ||
| 97 | { | ||
| 98 | return p->curr; | ||
| 99 | } | ||
| 100 | |||
| 101 | |||
| 102 | |||
| 103 | |||
| 104 | //=========================================================================== | ||
| 105 | /* ---------------- env~ - simple envelope follower. ----------------- */ | ||
| 106 | //=========================================================================== | ||
| 107 | |||
| 108 | void tEnvPD_init(tEnvPD* const x, int ws, int hs, int bs) | ||
| 109 | { | ||
| 110 | int period = hs, npoints = ws; | ||
| 111 | |||
| 112 | int i; | ||
| 113 | |||
| 114 | if (npoints < 1) npoints = 1024; | ||
| 115 | if (period < 1) period = npoints/2; | ||
| 116 | if (period < npoints / MAXOVERLAP + 1) | ||
| 117 | period = npoints / MAXOVERLAP + 1; | ||
| 118 | |||
| 119 | x->x_npoints = npoints; | ||
| 120 | x->x_phase = 0; | ||
| 121 | x->x_period = period; | ||
| 122 | |||
| 123 | x->windowSize = npoints; | ||
| 124 | x->hopSize = period; | ||
| 125 | x->blockSize = bs; | ||
| 126 | |||
| 127 | for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0; | ||
| 128 | for (i = 0; i < npoints; i++) | ||
| 129 | x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints; | ||
| 130 | for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0; | ||
| 131 | |||
| 132 | x->x_f = 0; | ||
| 133 | |||
| 134 | x->x_allocforvs = INITVSTAKEN; | ||
| 135 | |||
| 136 | // ~ ~ ~ dsp ~ ~ ~ | ||
| 137 | if (x->x_period % x->blockSize) | ||
| 138 | { | ||
| 139 | x->x_realperiod = x->x_period + x->blockSize - (x->x_period % x->blockSize); | ||
| 140 | } | ||
| 141 | else | ||
| 142 | { | ||
| 143 | x->x_realperiod = x->x_period; | ||
| 144 | } | ||
| 145 | // ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 146 | } | ||
| 147 | |||
| 148 | void tEnvPD_free (tEnvPD* const x) | ||
| 149 | { | ||
| 150 | |||
| 151 | } | ||
| 152 | |||
| 153 | float tEnvPD_tick (tEnvPD* const x) | ||
| 154 | { | ||
| 155 | return powtodb(x->x_result); | ||
| 156 | } | ||
| 157 | |||
| 158 | void tEnvPD_processBlock(tEnvPD* const x, float* in) | ||
| 159 | { | ||
| 160 | int n = x->blockSize; | ||
| 161 | |||
| 162 | int count; | ||
| 163 | t_sample *sump; | ||
| 164 | in += n; | ||
| 165 | for (count = x->x_phase, sump = x->x_sumbuf; | ||
| 166 | count < x->x_npoints; count += x->x_realperiod, sump++) | ||
| 167 | { | ||
| 168 | t_sample *hp = x->buf + count; | ||
| 169 | t_sample *fp = in; | ||
| 170 | t_sample sum = *sump; | ||
| 171 | int i; | ||
| 172 | |||
| 173 | for (i = 0; i < n; i++) | ||
| 174 | { | ||
| 175 | fp--; | ||
| 176 | sum += *hp++ * (*fp * *fp); | ||
| 177 | } | ||
| 178 | *sump = sum; | ||
| 179 | } | ||
| 180 | sump[0] = 0; | ||
| 181 | x->x_phase -= n; | ||
| 182 | if (x->x_phase < 0) | ||
| 183 | { | ||
| 184 | x->x_result = x->x_sumbuf[0]; | ||
| 185 | for (count = x->x_realperiod, sump = x->x_sumbuf; | ||
| 186 | count < x->x_npoints; count += x->x_realperiod, sump++) | ||
| 187 | sump[0] = sump[1]; | ||
| 188 | sump[0] = 0; | ||
| 189 | x->x_phase = x->x_realperiod - n; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | //=========================================================================== | ||
| 194 | // ATTACKDETECTION | ||
| 195 | //=========================================================================== | ||
| 196 | /********Private function prototypes**********/ | ||
| 197 | static void atkdtk_init(tAttackDetection* const a, int blocksize, int atk, int rel); | ||
| 198 | static void atkdtk_envelope(tAttackDetection* const a, float *in); | ||
| 199 | |||
| 200 | /********Constructor/Destructor***************/ | ||
| 201 | |||
| 202 | void tAttackDetection_init(tAttackDetection* const a, int blocksize) | ||
| 203 | { | ||
| 204 | atkdtk_init(a, blocksize, DEFATTACK, DEFRELEASE); | ||
| 205 | } | ||
| 206 | |||
| 207 | void tAttackDetection_init_expanded(tAttackDetection* const a, int blocksize, int atk, int rel) | ||
| 208 | { | ||
| 209 | atkdtk_init(a, blocksize, atk, rel); | ||
| 210 | } | ||
| 211 | |||
| 212 | void tAttackDetection_free(tAttackDetection *a) | ||
| 213 | { | ||
| 214 | |||
| 215 | } | ||
| 216 | |||
| 217 | /*******Public Functions***********/ | ||
| 218 | |||
| 219 | |||
| 220 | void tAttackDetection_setBlocksize(tAttackDetection* const a, int size) | ||
| 221 | { | ||
| 222 | |||
| 223 | if(!((size==64)|(size==128)|(size==256)|(size==512)|(size==1024)|(size==2048))) | ||
| 224 | size = DEFBLOCKSIZE; | ||
| 225 | a->blocksize = size; | ||
| 226 | |||
| 227 | return; | ||
| 228 | |||
| 229 | } | ||
| 230 | |||
| 231 | void tAttackDetection_setSamplerate(tAttackDetection* const a, int inRate) | ||
| 232 | { | ||
| 233 | a->samplerate = inRate; | ||
| 234 | |||
| 235 | //Reset atk and rel to recalculate coeff | ||
| 236 | tAttackDetection_setAtk(a, a->atk); | ||
| 237 | tAttackDetection_setRel(a, a->rel); | ||
| 238 | |||
| 239 | return; | ||
| 240 | } | ||
| 241 | |||
| 242 | void tAttackDetection_setThreshold(tAttackDetection* const a, float thres) | ||
| 243 | { | ||
| 244 | a->threshold = thres; | ||
| 245 | return; | ||
| 246 | } | ||
| 247 | |||
| 248 | void tAttackDetection_setAtk(tAttackDetection* const a, int inAtk) | ||
| 249 | { | ||
| 250 | a->atk = inAtk; | ||
| 251 | a->atk_coeff = pow(0.01, 1.0/(a->atk * a->samplerate * 0.001)); | ||
| 252 | |||
| 253 | return; | ||
| 254 | } | ||
| 255 | |||
| 256 | void tAttackDetection_setRel(tAttackDetection* const a, int inRel) | ||
| 257 | { | ||
| 258 | a->rel = inRel; | ||
| 259 | a->rel_coeff = pow(0.01, 1.0/(a->rel * a->samplerate * 0.001)); | ||
| 260 | |||
| 261 | return; | ||
| 262 | } | ||
| 263 | |||
| 264 | |||
| 265 | int tAttackDetection_detect(tAttackDetection* const a, float *in) | ||
| 266 | { | ||
| 267 | int result; | ||
| 268 | |||
| 269 | atkdtk_envelope(a, in); | ||
| 270 | |||
| 271 | if(a->env >= a->prevAmp*2) //2 times greater = 6dB increase | ||
| 272 | result = 1; | ||
| 273 | else | ||
| 274 | result = 0; | ||
| 275 | |||
| 276 | a->prevAmp = a->env; | ||
| 277 | |||
| 278 | return result; | ||
| 279 | |||
| 280 | } | ||
| 281 | |||
| 282 | /*******Private Functions**********/ | ||
| 283 | |||
| 284 | static void atkdtk_init(tAttackDetection* const a, int blocksize, int atk, int rel) | ||
| 285 | { | ||
| 286 | a->env = 0; | ||
| 287 | a->blocksize = blocksize; | ||
| 288 | a->threshold = DEFTHRESHOLD; | ||
| 289 | a->samplerate = leaf.sampleRate; | ||
| 290 | a->prevAmp = 0; | ||
| 291 | |||
| 292 | a->env = 0; | ||
| 293 | |||
| 294 | tAttackDetection_setAtk(a, atk); | ||
| 295 | tAttackDetection_setRel(a, rel); | ||
| 296 | } | ||
| 297 | |||
| 298 | static void atkdtk_envelope(tAttackDetection* const a, float *in) | ||
| 299 | { | ||
| 300 | int i = 0; | ||
| 301 | float tmp; | ||
| 302 | for(i = 0; i < a->blocksize; ++i){ | ||
| 303 | tmp = fastabs(in[i]); | ||
| 304 | |||
| 305 | if(tmp > a->env) | ||
| 306 | a->env = a->atk_coeff * (a->env - tmp) + tmp; | ||
| 307 | else | ||
| 308 | a->env = a->rel_coeff * (a->env - tmp) + tmp; | ||
| 309 | } | ||
| 310 | |||
| 311 | } | ||
| 312 | |||
| 313 | //=========================================================================== | ||
| 314 | // PERIODDETECTION | ||
| 315 | //=========================================================================== | ||
| 316 | void tPeriodDetection_init (tPeriodDetection* const p, float* in, float* out, int bufSize, int frameSize) | ||
| 317 | { | ||
| 318 | p->inBuffer = in; | ||
| 319 | p->outBuffer = out; | ||
| 320 | p->bufSize = bufSize; | ||
| 321 | p->frameSize = frameSize; | ||
| 322 | p->framesPerBuffer = p->bufSize / p->frameSize; | ||
| 323 | p->curBlock = 1; | ||
| 324 | p->lastBlock = 0; | ||
| 325 | p->index = 0; | ||
| 326 | |||
| 327 | p->hopSize = DEFHOPSIZE; | ||
| 328 | p->windowSize = DEFWINDOWSIZE; | ||
| 329 | p->fba = FBA; | ||
| 330 | |||
| 331 | tEnvPD_init(&p->env, p->windowSize, p->hopSize, p->frameSize); | ||
| 332 | |||
| 333 | tSNAC_init(&p->snac, DEFOVERLAP); | ||
| 334 | |||
| 335 | p->timeConstant = DEFTIMECONSTANT; | ||
| 336 | p->radius = expf(-1000.0f * p->hopSize * leaf.invSampleRate / p->timeConstant); | ||
| 337 | } | ||
| 338 | |||
| 339 | void tPeriodDetection_free (tPeriodDetection* const p) | ||
| 340 | { | ||
| 341 | tEnvPD_free(&p->env); | ||
| 342 | tSNAC_free(&p->snac); | ||
| 343 | } | ||
| 344 | |||
| 345 | float tPeriodDetection_findPeriod (tPeriodDetection* p, float sample) | ||
| 346 | { | ||
| 347 | int i, iLast; | ||
| 348 | |||
| 349 | i = (p->curBlock*p->frameSize); | ||
| 350 | iLast = (p->lastBlock*p->frameSize)+p->index; | ||
| 351 | |||
| 352 | p->i = i; | ||
| 353 | p->iLast = iLast; | ||
| 354 | |||
| 355 | p->inBuffer[i+p->index] = sample; | ||
| 356 | |||
| 357 | p->index++; | ||
| 358 | p->indexstore = p->index; | ||
| 359 | if (p->index >= p->frameSize) | ||
| 360 | { | ||
| 361 | p->index = 0; | ||
| 362 | |||
| 363 | tEnvPD_processBlock(&p->env, &(p->inBuffer[i])); | ||
| 364 | |||
| 365 | tSNAC_ioSamples(&p->snac, &(p->inBuffer[i]), &(p->outBuffer[i]), p->frameSize); | ||
| 366 | p->period = tSNAC_getPeriod(&p->snac); | ||
| 367 | |||
| 368 | p->curBlock++; | ||
| 369 | if (p->curBlock >= p->framesPerBuffer) p->curBlock = 0; | ||
| 370 | p->lastBlock++; | ||
| 371 | if (p->lastBlock >= p->framesPerBuffer) p->lastBlock = 0; | ||
| 372 | } | ||
| 373 | |||
| 374 | // changed from period to p->period | ||
| 375 | return p->period; | ||
| 376 | } | ||
| 377 | |||
| 378 | void tPeriodDetection_setHopSize(tPeriodDetection* p, int hs) | ||
| 379 | { | ||
| 380 | p->hopSize = hs; | ||
| 381 | } | ||
| 382 | |||
| 383 | void tPeriodDetection_setWindowSize(tPeriodDetection* p, int ws) | ||
| 384 | { | ||
| 385 | p->windowSize = ws; | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | |||
| 390 | |||
| 391 | |||
| 392 | |||
| 393 | |||
| 394 | |||
| 395 | |||
| 396 | //=========================================================================== | ||
| 397 | // SNAC | ||
| 398 | //=========================================================================== | ||
| 399 | /******************************************************************************/ | ||
| 400 | /***************************** private procedures *****************************/ | ||
| 401 | /******************************************************************************/ | ||
| 402 | |||
| 403 | #define REALFFT mayer_realfft | ||
| 404 | #define REALIFFT mayer_realifft | ||
| 405 | |||
| 406 | static void snac_analyzeframe(tSNAC* const s); | ||
| 407 | static void snac_autocorrelation(tSNAC* const s); | ||
| 408 | static void snac_normalize(tSNAC* const s); | ||
| 409 | static void snac_pickpeak(tSNAC* const s); | ||
| 410 | static void snac_periodandfidelity(tSNAC* const s); | ||
| 411 | static void snac_biasbuf(tSNAC* const s); | ||
| 412 | static float snac_spectralpeak(tSNAC* const s, float periodlength); | ||
| 413 | |||
| 414 | |||
| 415 | /******************************************************************************/ | ||
| 416 | /******************************** constructor, destructor *********************/ | ||
| 417 | /******************************************************************************/ | ||
| 418 | |||
| 419 | |||
| 420 | void tSNAC_init(tSNAC* const s, int overlaparg) | ||
| 421 | { | ||
| 422 | s->biasfactor = DEFBIAS; | ||
| 423 | s->timeindex = 0; | ||
| 424 | s->periodindex = 0; | ||
| 425 | s->periodlength = 0.; | ||
| 426 | s->fidelity = 0.; | ||
| 427 | s->minrms = DEFMINRMS; | ||
| 428 | s->framesize = SNAC_FRAME_SIZE; | ||
| 429 | |||
| 430 | s->inputbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE); | ||
| 431 | s->processbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE * 2)); | ||
| 432 | s->spectrumbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE / 2)); | ||
| 433 | s->biasbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE); | ||
| 434 | |||
| 435 | snac_biasbuf(s); | ||
| 436 | tSNAC_setOverlap(s, overlaparg); | ||
| 437 | } | ||
| 438 | |||
| 439 | void tSNAC_free(tSNAC* const s) | ||
| 440 | { | ||
| 441 | leaf_free(s->inputbuf); | ||
| 442 | leaf_free(s->processbuf); | ||
| 443 | leaf_free(s->spectrumbuf); | ||
| 444 | leaf_free(s->biasbuf); | ||
| 445 | } | ||
| 446 | /******************************************************************************/ | ||
| 447 | /************************** public access functions****************************/ | ||
| 448 | /******************************************************************************/ | ||
| 449 | |||
| 450 | |||
| 451 | void tSNAC_ioSamples(tSNAC* const s, float *in, float *out, int size) | ||
| 452 | { | ||
| 453 | int timeindex = s->timeindex; | ||
| 454 | int mask = s->framesize - 1; | ||
| 455 | int outindex = 0; | ||
| 456 | float *inputbuf = s->inputbuf; | ||
| 457 | float *processbuf = s->processbuf; | ||
| 458 | |||
| 459 | // call analysis function when it is time | ||
| 460 | if(!(timeindex & (s->framesize / s->overlap - 1))) snac_analyzeframe(s); | ||
| 461 | |||
| 462 | while(size--) | ||
| 463 | { | ||
| 464 | inputbuf[timeindex] = *in++; | ||
| 465 | out[outindex++] = processbuf[timeindex++]; | ||
| 466 | timeindex &= mask; | ||
| 467 | } | ||
| 468 | s->timeindex = timeindex; | ||
| 469 | } | ||
| 470 | |||
| 471 | void tSNAC_setOverlap(tSNAC* const s, int lap) | ||
| 472 | { | ||
| 473 | if(!((lap==1)|(lap==2)|(lap==4)|(lap==8))) lap = DEFOVERLAP; | ||
| 474 | s->overlap = lap; | ||
| 475 | } | ||
| 476 | |||
| 477 | |||
| 478 | void tSNAC_setBias(tSNAC* const s, float bias) | ||
| 479 | { | ||
| 480 | if(bias > 1.) bias = 1.; | ||
| 481 | if(bias < 0.) bias = 0.; | ||
| 482 | s->biasfactor = bias; | ||
| 483 | snac_biasbuf(s); | ||
| 484 | return; | ||
| 485 | } | ||
| 486 | |||
| 487 | |||
| 488 | void tSNAC_setMinRMS(tSNAC* const s, float rms) | ||
| 489 | { | ||
| 490 | if(rms > 1.) rms = 1.; | ||
| 491 | if(rms < 0.) rms = 0.; | ||
| 492 | s->minrms = rms; | ||
| 493 | return; | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | float tSNAC_getPeriod(tSNAC* const s) | ||
| 498 | { | ||
| 499 | return(s->periodlength); | ||
| 500 | } | ||
| 501 | |||
| 502 | |||
| 503 | float tSNAC_getFidelity(tSNAC* const s) | ||
| 504 | { | ||
| 505 | return(s->fidelity); | ||
| 506 | } | ||
| 507 | |||
| 508 | |||
| 509 | /******************************************************************************/ | ||
| 510 | /***************************** private procedures *****************************/ | ||
| 511 | /******************************************************************************/ | ||
| 512 | |||
| 513 | |||
| 514 | // main analysis function | ||
| 515 | static void snac_analyzeframe(tSNAC* const s) | ||
| 516 | { | ||
| 517 | int n, tindex = s->timeindex; | ||
| 518 | int framesize = s->framesize; | ||
| 519 | int mask = framesize - 1; | ||
| 520 | float norm = 1. / sqrt((float)(framesize * 2)); | ||
| 521 | |||
| 522 | float *inputbuf = s->inputbuf; | ||
| 523 | float *processbuf = s->processbuf; | ||
| 524 | |||
| 525 | // copy input to processing buffers | ||
| 526 | for(n=0; n<framesize; n++) | ||
| 527 | { | ||
| 528 | processbuf[n] = inputbuf[tindex] * norm; | ||
| 529 | tindex++; | ||
| 530 | tindex &= mask; | ||
| 531 | } | ||
| 532 | |||
| 533 | // zeropadding | ||
| 534 | for(n=framesize; n<(framesize<<1); n++) processbuf[n] = 0.; | ||
| 535 | |||
| 536 | // call analysis procedures | ||
| 537 | snac_autocorrelation(s); | ||
| 538 | snac_normalize(s); | ||
| 539 | snac_pickpeak(s); | ||
| 540 | snac_periodandfidelity(s); | ||
| 541 | } | ||
| 542 | |||
| 543 | |||
| 544 | static void snac_autocorrelation(tSNAC* const s) | ||
| 545 | { | ||
| 546 | int n, m; | ||
| 547 | int framesize = s->framesize; | ||
| 548 | int fftsize = framesize * 2; | ||
| 549 | float *processbuf = s->processbuf; | ||
| 550 | float *spectrumbuf = s->spectrumbuf; | ||
| 551 | |||
| 552 | REALFFT(fftsize, processbuf); | ||
| 553 | |||
| 554 | // compute power spectrum | ||
| 555 | processbuf[0] *= processbuf[0]; // DC | ||
| 556 | processbuf[framesize] *= processbuf[framesize]; // Nyquist | ||
| 557 | |||
| 558 | for(n=1; n<framesize; n++) | ||
| 559 | { | ||
| 560 | processbuf[n] = processbuf[n] * processbuf[n] | ||
| 561 | + processbuf[fftsize-n] * processbuf[fftsize-n]; // imag coefficients appear reversed | ||
| 562 | processbuf[fftsize-n] = 0.; | ||
| 563 | } | ||
| 564 | |||
| 565 | // store power spectrum up to SR/4 for possible later use | ||
| 566 | for(m=0; m<(framesize>>1); m++) | ||
| 567 | { | ||
| 568 | spectrumbuf[m] = processbuf[m]; | ||
| 569 | } | ||
| 570 | |||
| 571 | // transform power spectrum to autocorrelation function | ||
| 572 | REALIFFT(fftsize, processbuf); | ||
| 573 | return; | ||
| 574 | } | ||
| 575 | |||
| 576 | |||
| 577 | static void snac_normalize(tSNAC* const s) | ||
| 578 | { | ||
| 579 | int framesize = s->framesize; | ||
| 580 | int framesizeplustimeindex = s->framesize + s->timeindex; | ||
| 581 | int timeindexminusone = s->timeindex - 1; | ||
| 582 | int n, m; | ||
| 583 | int mask = framesize - 1; | ||
| 584 | int seek = framesize * SEEK; | ||
| 585 | float *inputbuf = s->inputbuf; | ||
| 586 | float *processbuf= s->processbuf; | ||
| 587 | float signal1, signal2; | ||
| 588 | |||
| 589 | // minimum RMS implemented as minimum autocorrelation at index 0 | ||
| 590 | // functionally equivalent to white noise floor | ||
| 591 | float rms = s->minrms / sqrt(1.0f / (float)framesize); | ||
| 592 | float minrzero = rms * rms; | ||
| 593 | float rzero = processbuf[0]; | ||
| 594 | if(rzero < minrzero) rzero = minrzero; | ||
| 595 | double normintegral = (double)rzero * 2.; | ||
| 596 | |||
| 597 | // normalize biased autocorrelation function | ||
| 598 | // inputbuf is circular buffer: timeindex may be non-zero when overlap > 1 | ||
| 599 | processbuf[0] = 1; | ||
| 600 | for(n=1, m=s->timeindex+1; n<seek; n++, m++) | ||
| 601 | { | ||
| 602 | signal1 = inputbuf[(n + timeindexminusone)&mask]; | ||
| 603 | signal2 = inputbuf[(framesizeplustimeindex - n)&mask]; | ||
| 604 | normintegral -= (double)(signal1 * signal1 + signal2 * signal2); | ||
| 605 | processbuf[n] /= (float)normintegral * 0.5f; | ||
| 606 | } | ||
| 607 | |||
| 608 | // flush instable function tail | ||
| 609 | for(n = seek; n<framesize; n++) processbuf[n] = 0.; | ||
| 610 | return; | ||
| 611 | } | ||
| 612 | |||
| 613 | |||
| 614 | static void snac_periodandfidelity(tSNAC* const s) | ||
| 615 | { | ||
| 616 | float periodlength; | ||
| 617 | |||
| 618 | if(s->periodindex) | ||
| 619 | { | ||
| 620 | periodlength = (float)s->periodindex + | ||
| 621 | interpolate3phase(s->processbuf, s->periodindex); | ||
| 622 | if(periodlength < 8) periodlength = snac_spectralpeak(s, periodlength); | ||
| 623 | s->periodlength = periodlength; | ||
| 624 | s->fidelity = interpolate3max(s->processbuf, s->periodindex); | ||
| 625 | } | ||
| 626 | return; | ||
| 627 | } | ||
| 628 | |||
| 629 | // select the peak which most probably represents period length | ||
| 630 | static void snac_pickpeak(tSNAC* const s) | ||
| 631 | { | ||
| 632 | int n, peakindex=0; | ||
| 633 | int seek = s->framesize * SEEK; | ||
| 634 | float *processbuf= s->processbuf; | ||
| 635 | float maxvalue = 0.; | ||
| 636 | float biasedpeak; | ||
| 637 | float *biasbuf = s->biasbuf; | ||
| 638 | |||
| 639 | // skip main lobe | ||
| 640 | for(n=1; n<seek; n++) | ||
| 641 | { | ||
| 642 | if(processbuf[n] < 0.) break; | ||
| 643 | } | ||
| 644 | |||
| 645 | // find interpolated / biased maximum in SNAC function | ||
| 646 | // interpolation finds the 'real maximum' | ||
| 647 | // biasing favours the first candidate | ||
| 648 | for(; n<seek-1; n++) | ||
| 649 | { | ||
| 650 | if(processbuf[n] >= processbuf[n-1]) | ||
| 651 | { | ||
| 652 | if(processbuf[n] > processbuf[n+1]) // we have a local peak | ||
| 653 | { | ||
| 654 | biasedpeak = interpolate3max(processbuf, n) * biasbuf[n]; | ||
| 655 | |||
| 656 | if(biasedpeak > maxvalue) | ||
| 657 | { | ||
| 658 | maxvalue = biasedpeak; | ||
| 659 | peakindex = n; | ||
| 660 | } | ||
| 661 | } | ||
| 662 | } | ||
| 663 | } | ||
| 664 | s->periodindex = peakindex; | ||
| 665 | return; | ||
| 666 | } | ||
| 667 | |||
| 668 | |||
| 669 | // verify period length via frequency domain (up till SR/4) | ||
| 670 | // frequency domain is more precise than lag domain for period lengths < 8 | ||
| 671 | // argument 'periodlength' is initial estimation from autocorrelation | ||
| 672 | static float snac_spectralpeak(tSNAC* const s, float periodlength) | ||
| 673 | { | ||
| 674 | if(periodlength < 4.) return periodlength; | ||
| 675 | |||
| 676 | float max = 0.; | ||
| 677 | int n, startbin, stopbin, peakbin = 0; | ||
| 678 | int spectrumsize = s->framesize>>1; | ||
| 679 | float *spectrumbuf = s->spectrumbuf; | ||
| 680 | float peaklocation = (float)(s->framesize * 2.) / periodlength; | ||
| 681 | |||
| 682 | startbin = (int)(peaklocation * 0.8 + 0.5); | ||
| 683 | if(startbin < 1) startbin = 1; | ||
| 684 | stopbin = (int)(peaklocation * 1.25 + 0.5); | ||
| 685 | if(stopbin >= spectrumsize - 1) stopbin = spectrumsize - 1; | ||
| 686 | |||
| 687 | for(n=startbin; n<stopbin; n++) | ||
| 688 | { | ||
| 689 | if(spectrumbuf[n] >= spectrumbuf[n-1]) | ||
| 690 | { | ||
| 691 | if(spectrumbuf[n] > spectrumbuf[n+1]) | ||
| 692 | { | ||
| 693 | if(spectrumbuf[n] > max) | ||
| 694 | { | ||
| 695 | max = spectrumbuf[n]; | ||
| 696 | peakbin = n; | ||
| 697 | } | ||
| 698 | } | ||
| 699 | } | ||
| 700 | } | ||
| 701 | |||
| 702 | // calculate amplitudes in peak region | ||
| 703 | for(n=(peakbin-1); n<(peakbin+2); n++) | ||
| 704 | { | ||
| 705 | spectrumbuf[n] = sqrt(spectrumbuf[n]); | ||
| 706 | } | ||
| 707 | |||
| 708 | peaklocation = (float)peakbin + interpolate3phase(spectrumbuf, peakbin); | ||
| 709 | periodlength = (float)(s->framesize * 2.0f) / peaklocation; | ||
| 710 | |||
| 711 | return periodlength; | ||
| 712 | } | ||
| 713 | |||
| 714 | |||
| 715 | // modified logarithmic bias function | ||
| 716 | static void snac_biasbuf(tSNAC* const s) | ||
| 717 | { | ||
| 718 | int n; | ||
| 719 | int maxperiod = (int)(s->framesize * (float)SEEK); | ||
| 720 | float bias = s->biasfactor / log((float)(maxperiod - 4)); | ||
| 721 | float *biasbuf = s->biasbuf; | ||
| 722 | |||
| 723 | for(n=0; n<5; n++) // periods < 5 samples can't be tracked | ||
| 724 | { | ||
| 725 | biasbuf[n] = 0.; | ||
| 726 | } | ||
| 727 | |||
| 728 | for(n=5; n<maxperiod; n++) | ||
| 729 | { | ||
| 730 | biasbuf[n] = 1.0f - (float)log(n - 4) * bias; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| @@ -1,84 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-crusher.c | ||
| 4 | Created: 30 Nov 2018 11:56:49am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-crusher.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include "../Inc/leaf-crusher.h" | ||
| 16 | |||
| 17 | #endif | ||
| 18 | |||
| 19 | //============================================================================== | ||
| 20 | |||
| 21 | #define SCALAR 5000.f | ||
| 22 | |||
| 23 | void tCrusher_init (tCrusher* const c) | ||
| 24 | { | ||
| 25 | c->op = 4; | ||
| 26 | c->div = SCALAR; | ||
| 27 | c->rnd = 0.25f; | ||
| 28 | c->srr = 0.25f; | ||
| 29 | |||
| 30 | c->gain = (c->div / SCALAR) * 0.7f + 0.3f; | ||
| 31 | } | ||
| 32 | |||
| 33 | void tCrusher_free (tCrusher* const c) | ||
| 34 | { | ||
| 35 | |||
| 36 | } | ||
| 37 | |||
| 38 | float tCrusher_tick (tCrusher* const c, float input) | ||
| 39 | { | ||
| 40 | float sample = input; | ||
| 41 | |||
| 42 | sample *= SCALAR; // SCALAR is 5000 by default | ||
| 43 | |||
| 44 | sample = (int32_t) sample; | ||
| 45 | |||
| 46 | sample /= c->div; | ||
| 47 | |||
| 48 | sample = LEAF_bitwise_xor(sample, c->op << 23); | ||
| 49 | |||
| 50 | sample = LEAF_clip(-1.f, sample, 1.f); | ||
| 51 | |||
| 52 | sample = LEAF_round(sample, c->rnd); | ||
| 53 | |||
| 54 | sample = LEAF_reduct(sample, c->srr); | ||
| 55 | |||
| 56 | return sample * c->gain; | ||
| 57 | |||
| 58 | } | ||
| 59 | |||
| 60 | void tCrusher_setOperation (tCrusher* const c, float op) | ||
| 61 | { | ||
| 62 | c->op = (uint32_t) (op * 8.0f); | ||
| 63 | } | ||
| 64 | |||
| 65 | // 0.0 - 1.0 | ||
| 66 | void tCrusher_setQuality (tCrusher* const c, float val) | ||
| 67 | { | ||
| 68 | val = LEAF_clip(0.0f, val, 1.0f); | ||
| 69 | |||
| 70 | c->div = 0.01f + val * SCALAR; | ||
| 71 | |||
| 72 | c->gain = (c->div / SCALAR) * 0.7f + 0.3f; | ||
| 73 | } | ||
| 74 | |||
| 75 | // what decimal to round to | ||
| 76 | void tCrusher_setRound (tCrusher* const c, float rnd) | ||
| 77 | { | ||
| 78 | c->rnd = fabsf(rnd); | ||
| 79 | } | ||
| 80 | |||
| 81 | void tCrusher_setSamplingRatio (tCrusher* const c, float ratio) | ||
| 82 | { | ||
| 83 | c->srr = ratio; | ||
| 84 | } | ||
| @@ -127,8 +127,8 @@ float tDelay_getGain (tDelay* const d) · 126 unmodified lines | |||
| 127 | return d->gain; | 127 | return d->gain; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayL ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | 130 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ LinearDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // |
| 131 | void tDelayL_init (tDelayL* const d, float delay, uint32_t maxDelay) | 131 | void tLinearDelay_init (tLinearDelay* const d, float delay, uint32_t maxDelay) |
| 132 | { | 132 | { |
| 133 | d->maxDelay = maxDelay; | 133 | d->maxDelay = maxDelay; |
| 134 | 134 | ||
| @@ -146,15 +146,15 @@ void tDelayL_init (tDelayL* const d, float delay, uint32_t maxDelay) · 11 unmodified lines | |||
| 146 | d->inPoint = 0; | 146 | d->inPoint = 0; |
| 147 | d->outPoint = 0; | 147 | d->outPoint = 0; |
| 148 | 148 | ||
| 149 | tDelayL_setDelay(d, d->delay); | 149 | tLinearDelay_setDelay(d, d->delay); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | void tDelayL_free(tDelayL* const d) | 152 | void tLinearDelay_free(tLinearDelay* const d) |
| 153 | { | 153 | { |
| 154 | leaf_free(d->buff); | 154 | leaf_free(d->buff); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | float tDelayL_tick (tDelayL* const d, float input) | 157 | float tLinearDelay_tick (tLinearDelay* const d, float input) |
| 158 | { | 158 | { |
| 159 | d->buff[d->inPoint] = input * d->gain; | 159 | d->buff[d->inPoint] = input * d->gain; |
| 160 | 160 | ||
| @@ -176,7 +176,7 @@ float tDelayL_tick (tDelayL* const d, float input) · 15 unmodified lines | |||
| 176 | return d->lastOut; | 176 | return d->lastOut; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | void tDelayL_tickIn (tDelayL* const d, float input) | 179 | void tLinearDelay_tickIn (tLinearDelay* const d, float input) |
| 180 | { | 180 | { |
| 181 | d->buff[d->inPoint] = input * d->gain; | 181 | d->buff[d->inPoint] = input * d->gain; |
| 182 | 182 | ||
| @@ -184,7 +184,7 @@ void tDelayL_tickIn (tDelayL* const d, float input) · 1 unmodified line | |||
| 184 | if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0; | 184 | if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | float tDelayL_tickOut (tDelayL* const d) | 187 | float tLinearDelay_tickOut (tLinearDelay* const d) |
| 188 | { | 188 | { |
| 189 | uint32_t idx = (uint32_t) d->outPoint; | 189 | uint32_t idx = (uint32_t) d->outPoint; |
| 190 | 190 | ||
| @@ -200,7 +200,7 @@ float tDelayL_tickOut (tDelayL* const d) · 9 unmodified lines | |||
| 200 | return d->lastOut; | 200 | return d->lastOut; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | int tDelayL_setDelay (tDelayL* const d, float delay) | 203 | int tLinearDelay_setDelay (tLinearDelay* const d, float delay) |
| 204 | { | 204 | { |
| 205 | d->delay = LEAF_clip(0.0f, delay, d->maxDelay); | 205 | d->delay = LEAF_clip(0.0f, delay, d->maxDelay); |
| 206 | 206 | ||
| @@ -219,7 +219,7 @@ int tDelayL_setDelay (tDelayL* const d, float delay) · 12 unmodified lines | |||
| 219 | return 0; | 219 | return 0; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | float tDelayL_tapOut (tDelayL* const d, float tapDelay) | 222 | float tLinearDelay_tapOut (tLinearDelay* const d, float tapDelay) |
| 223 | { | 223 | { |
| 224 | float tap = (float) d->inPoint - tapDelay - 1.f; | 224 | float tap = (float) d->inPoint - tapDelay - 1.f; |
| 225 | 225 | ||
| @@ -244,7 +244,7 @@ float tDelayL_tapOut (tDelayL* const d, float tapDelay) · 18 unmodified lines | |||
| 244 | 244 | ||
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | void tDelayL_tapIn (tDelayL* const d, float value, uint32_t tapDelay) | 247 | void tLinearDelay_tapIn (tLinearDelay* const d, float value, uint32_t tapDelay) |
| 248 | { | 248 | { |
| 249 | int32_t tap = d->inPoint - tapDelay - 1; | 249 | int32_t tap = d->inPoint - tapDelay - 1; |
| 250 | 250 | ||
| @@ -254,7 +254,7 @@ void tDelayL_tapIn (tDelayL* const d, float value, uint32_t tapDelay) · 3 unmodified lines | |||
| 254 | d->buff[tap] = value; | 254 | d->buff[tap] = value; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | float tDelayL_addTo (tDelayL* const d, float value, uint32_t tapDelay) | 257 | float tLinearDelay_addTo (tLinearDelay* const d, float value, uint32_t tapDelay) |
| 258 | { | 258 | { |
| 259 | int32_t tap = d->inPoint - tapDelay - 1; | 259 | int32_t tap = d->inPoint - tapDelay - 1; |
| 260 | 260 | ||
| @@ -264,34 +264,34 @@ float tDelayL_addTo (tDelayL* const d, float value, uint32_t tapDelay) · 3 unmodified lines | |||
| 264 | return (d->buff[tap] += value); | 264 | return (d->buff[tap] += value); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | float tDelayL_getDelay (tDelayL *d) | 267 | float tLinearDelay_getDelay (tLinearDelay *d) |
| 268 | { | 268 | { |
| 269 | return d->delay; | 269 | return d->delay; |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | float tDelayL_getLastOut (tDelayL* const d) | 272 | float tLinearDelay_getLastOut (tLinearDelay* const d) |
| 273 | { | 273 | { |
| 274 | return d->lastOut; | 274 | return d->lastOut; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | float tDelayL_getLastIn (tDelayL* const d) | 277 | float tLinearDelay_getLastIn (tLinearDelay* const d) |
| 278 | { | 278 | { |
| 279 | return d->lastIn; | 279 | return d->lastIn; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | void tDelayL_setGain (tDelayL* const d, float gain) | 282 | void tLinearDelay_setGain (tLinearDelay* const d, float gain) |
| 283 | { | 283 | { |
| 284 | if (gain < 0.0f) d->gain = 0.0f; | 284 | if (gain < 0.0f) d->gain = 0.0f; |
| 285 | else d->gain = gain; | 285 | else d->gain = gain; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | float tDelayL_getGain (tDelayL* const d) | 288 | float tLinearDelay_getGain (tLinearDelay* const d) |
| 289 | { | 289 | { |
| 290 | return d->gain; | 290 | return d->gain; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayA ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | 293 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ AllpassDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // |
| 294 | void tDelayA_init (tDelayA* const d, float delay, uint32_t maxDelay) | 294 | void tAllpassDelay_init (tAllpassDelay* const d, float delay, uint32_t maxDelay) |
| 295 | { | 295 | { |
| 296 | d->maxDelay = maxDelay; | 296 | d->maxDelay = maxDelay; |
| 297 | 297 | ||
| @@ -309,17 +309,17 @@ void tDelayA_init (tDelayA* const d, float delay, uint32_t maxDelay) · 11 unmodified lines | |||
| 309 | d->inPoint = 0; | 309 | d->inPoint = 0; |
| 310 | d->outPoint = 0; | 310 | d->outPoint = 0; |
| 311 | 311 | ||
| 312 | tDelayA_setDelay(d, d->delay); | 312 | tAllpassDelay_setDelay(d, d->delay); |
| 313 | 313 | ||
| 314 | d->apInput = 0.0f; | 314 | d->apInput = 0.0f; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | void tDelayA_free(tDelayA* const d) | 317 | void tAllpassDelay_free(tAllpassDelay* const d) |
| 318 | { | 318 | { |
| 319 | leaf_free(d->buff); | 319 | leaf_free(d->buff); |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | float tDelayA_tick (tDelayA* const d, float input) | 322 | float tAllpassDelay_tick (tAllpassDelay* const d, float input) |
| 323 | { | 323 | { |
| 324 | d->buff[d->inPoint] = input * d->gain; | 324 | d->buff[d->inPoint] = input * d->gain; |
| 325 | 325 | ||
| @@ -340,7 +340,7 @@ float tDelayA_tick (tDelayA* const d, float input) · 14 unmodified lines | |||
| 340 | return d->lastOut; | 340 | return d->lastOut; |
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | int tDelayA_setDelay (tDelayA* const d, float delay) | 343 | int tAllpassDelay_setDelay (tAllpassDelay* const d, float delay) |
| 344 | { | 344 | { |
| 345 | d->delay = LEAF_clip(0.5f, delay, d->maxDelay); | 345 | d->delay = LEAF_clip(0.5f, delay, d->maxDelay); |
| 346 | 346 | ||
| @@ -373,7 +373,7 @@ int tDelayA_setDelay (tDelayA* const d, float delay) · 26 unmodified lines | |||
| 373 | return 0; | 373 | return 0; |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | float tDelayA_tapOut (tDelayA* const d, uint32_t tapDelay) | 376 | float tAllpassDelay_tapOut (tAllpassDelay* const d, uint32_t tapDelay) |
| 377 | { | 377 | { |
| 378 | int32_t tap = d->inPoint - tapDelay - 1; | 378 | int32_t tap = d->inPoint - tapDelay - 1; |
| 379 | 379 | ||
| @@ -384,7 +384,7 @@ float tDelayA_tapOut (tDelayA* const d, uint32_t tapDelay) · 4 unmodified lines | |||
| 384 | 384 | ||
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | void tDelayA_tapIn (tDelayA* const d, float value, uint32_t tapDelay) | 387 | void tAllpassDelay_tapIn (tAllpassDelay* const d, float value, uint32_t tapDelay) |
| 388 | { | 388 | { |
| 389 | int32_t tap = d->inPoint - tapDelay - 1; | 389 | int32_t tap = d->inPoint - tapDelay - 1; |
| 390 | 390 | ||
| @@ -394,7 +394,7 @@ void tDelayA_tapIn (tDelayA* const d, float value, uint32_t tapDelay) · 3 unmodified lines | |||
| 394 | d->buff[tap] = value; | 394 | d->buff[tap] = value; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | float tDelayA_addTo (tDelayA* const d, float value, uint32_t tapDelay) | 397 | float tAllpassDelay_addTo (tAllpassDelay* const d, float value, uint32_t tapDelay) |
| 398 | { | 398 | { |
| 399 | int32_t tap = d->inPoint - tapDelay - 1; | 399 | int32_t tap = d->inPoint - tapDelay - 1; |
| 400 | 400 | ||
| @@ -404,28 +404,28 @@ float tDelayA_addTo (tDelayA* const d, float value, uint32_t tapDelay) · 3 unmodified lines | |||
| 404 | return (d->buff[tap] += value); | 404 | return (d->buff[tap] += value); |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | float tDelayA_getDelay (tDelayA* const d) | 407 | float tAllpassDelay_getDelay (tAllpassDelay* const d) |
| 408 | { | 408 | { |
| 409 | return d->delay; | 409 | return d->delay; |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | float tDelayA_getLastOut (tDelayA* const d) | 412 | float tAllpassDelay_getLastOut (tAllpassDelay* const d) |
| 413 | { | 413 | { |
| 414 | return d->lastOut; | 414 | return d->lastOut; |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | float tDelayA_getLastIn (tDelayA* const d) | 417 | float tAllpassDelay_getLastIn (tAllpassDelay* const d) |
| 418 | { | 418 | { |
| 419 | return d->lastIn; | 419 | return d->lastIn; |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | void tDelayA_setGain (tDelayA* const d, float gain) | 422 | void tAllpassDelay_setGain (tAllpassDelay* const d, float gain) |
| 423 | { | 423 | { |
| 424 | if (gain < 0.0f) d->gain = 0.0f; | 424 | if (gain < 0.0f) d->gain = 0.0f; |
| 425 | else d->gain = gain; | 425 | else d->gain = gain; |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | float tDelayA_getGain (tDelayA* const d) | 428 | float tAllpassDelay_getGain (tAllpassDelay* const d) |
| 429 | { | 429 | { |
| 430 | return d->gain; | 430 | return d->gain; |
| 431 | } | 431 | } |
| @@ -8,17 +8,188 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #if _WIN32 || _WIN64 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | ||
| 11 | #include "..\Inc\leaf-oversampler.h" | 11 | #include "..\Inc\leaf-distortion.h" |
| 12 | #include "..\Inc\leaf-tables.h" | 12 | #include "..\Inc\leaf-tables.h" |
| 13 | #else | 13 | #else |
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | #include "../Inc/leaf-oversampler.h" | 16 | #include "../Inc/leaf-distortion.h" |
| 17 | #include "../Inc/leaf-tables.h" | 17 | #include "../Inc/leaf-tables.h" |
| 18 | 18 | ||
| 19 | #endif | 19 | #endif |
| 20 | 20 | ||
| 21 | //============================================================================================================ | ||
| 22 | // WAVEFOLDER | ||
| 23 | //============================================================================================================ | ||
| 24 | void tLockhartWavefolder_init(tLockhartWavefolder* const w) | ||
| 25 | { | ||
| 26 | w->Ln1 = 0.0; | ||
| 27 | w->Fn1 = 0.0; | ||
| 28 | w->xn1 = 0.0f; | ||
| 29 | } | ||
| 30 | |||
| 31 | void tLockhardWavefolder_free(tLockhartWavefolder* const w) | ||
| 32 | { | ||
| 33 | |||
| 34 | } | ||
| 35 | |||
| 36 | double tLockhartWavefolderLambert(double x, double ln) | ||
| 37 | { | ||
| 38 | double thresh, w, expw, p, r, s, err; | ||
| 39 | // Error threshold | ||
| 40 | thresh = 10e-6; | ||
| 41 | // Initial guess (use previous value) | ||
| 42 | w = ln; | ||
| 43 | |||
| 44 | // Haley's method (Sec. 4.2 of the paper) | ||
| 45 | for(int i=0; i<100; i+=1) { | ||
| 46 | |||
| 47 | expw = exp(w); | ||
| 48 | |||
| 49 | p = w*expw - x; | ||
| 50 | r = (w+1.0)*expw; | ||
| 51 | s = (w+2.0)/(2.0*(w+1.0)); err = (p/(r-(p*s))); | ||
| 52 | |||
| 53 | if (fabs(err)<thresh) { | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | if (isnan(err)) | ||
| 57 | { | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | |||
| 61 | w = w - err; | ||
| 62 | } | ||
| 63 | return w; | ||
| 64 | } | ||
| 65 | |||
| 66 | float tLockhartWavefolder_tick(tLockhartWavefolder* const w, float samp) | ||
| 67 | { | ||
| 68 | |||
| 69 | float out = 0.0f; | ||
| 70 | // Constants | ||
| 71 | double RL = 7.5e3; | ||
| 72 | double R = 15e3; | ||
| 73 | double VT = 26e-3; | ||
| 74 | double Is = 10e-16; | ||
| 75 | |||
| 76 | double a = 2.0*RL/R; | ||
| 77 | double b = (R+2.0*RL)/(VT*R); | ||
| 78 | double d = (RL*Is)/VT; | ||
| 79 | |||
| 80 | // Antialiasing error threshold | ||
| 81 | double thresh = 10e-10; | ||
| 82 | |||
| 83 | // Compute Antiderivative | ||
| 84 | int l = (samp > 0) - (samp < 0); | ||
| 85 | double u = d*exp(l*b*samp); | ||
| 86 | double Ln = tLockhartWavefolderLambert(u,w->Ln1); | ||
| 87 | double Fn = (0.5*VT/b)*(Ln*(Ln + 2.0)) - 0.5*a*samp*samp; | ||
| 88 | |||
| 89 | // Check for ill-conditioning | ||
| 90 | if (fabs(samp-w->xn1)<thresh) { | ||
| 91 | |||
| 92 | // Compute Averaged Wavefolder Output | ||
| 93 | double xn = 0.5*(samp+w->xn1); | ||
| 94 | u = d*exp(l*b*xn); | ||
| 95 | Ln = tLockhartWavefolderLambert(u,w->Ln1); | ||
| 96 | out = (float) (l*VT*Ln - a*xn); | ||
| 97 | if (isnan(out)) | ||
| 98 | { | ||
| 99 | ; | ||
| 100 | } | ||
| 101 | |||
| 102 | } | ||
| 103 | else { | ||
| 104 | |||
| 105 | // Apply AA Form | ||
| 106 | out = (float) ((Fn-w->Fn1)/(samp-w->xn1)); | ||
| 107 | if (isnan(out)) | ||
| 108 | { | ||
| 109 | ; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | // Update States | ||
| 114 | w->Ln1 = Ln; | ||
| 115 | w->Fn1 = Fn; | ||
| 116 | w->xn1 = samp; | ||
| 117 | |||
| 118 | return out; | ||
| 119 | } | ||
| 120 | |||
| 121 | //============================================================================================================ | ||
| 122 | // CRUSHER | ||
| 123 | //============================================================================================================ | ||
| 124 | #define SCALAR 5000.f | ||
| 125 | |||
| 126 | void tCrusher_init (tCrusher* const c) | ||
| 127 | { | ||
| 128 | c->op = 4; | ||
| 129 | c->div = SCALAR; | ||
| 130 | c->rnd = 0.25f; | ||
| 131 | c->srr = 0.25f; | ||
| 132 | |||
| 133 | c->gain = (c->div / SCALAR) * 0.7f + 0.3f; | ||
| 134 | } | ||
| 135 | |||
| 136 | void tCrusher_free (tCrusher* const c) | ||
| 137 | { | ||
| 138 | |||
| 139 | } | ||
| 140 | |||
| 141 | float tCrusher_tick (tCrusher* const c, float input) | ||
| 142 | { | ||
| 143 | float sample = input; | ||
| 144 | |||
| 145 | sample *= SCALAR; // SCALAR is 5000 by default | ||
| 146 | |||
| 147 | sample = (int32_t) sample; | ||
| 148 | |||
| 149 | sample /= c->div; | ||
| 150 | |||
| 151 | sample = LEAF_bitwise_xor(sample, c->op << 23); | ||
| 152 | |||
| 153 | sample = LEAF_clip(-1.f, sample, 1.f); | ||
| 154 | |||
| 155 | sample = LEAF_round(sample, c->rnd); | ||
| 156 | |||
| 157 | sample = LEAF_reduct(sample, c->srr); | ||
| 158 | |||
| 159 | return sample * c->gain; | ||
| 160 | |||
| 161 | } | ||
| 162 | |||
| 163 | void tCrusher_setOperation (tCrusher* const c, float op) | ||
| 164 | { | ||
| 165 | c->op = (uint32_t) (op * 8.0f); | ||
| 166 | } | ||
| 167 | |||
| 168 | // 0.0 - 1.0 | ||
| 169 | void tCrusher_setQuality (tCrusher* const c, float val) | ||
| 170 | { | ||
| 171 | val = LEAF_clip(0.0f, val, 1.0f); | ||
| 172 | |||
| 173 | c->div = 0.01f + val * SCALAR; | ||
| 174 | |||
| 175 | c->gain = (c->div / SCALAR) * 0.7f + 0.3f; | ||
| 176 | } | ||
| 177 | |||
| 178 | // what decimal to round to | ||
| 179 | void tCrusher_setRound (tCrusher* const c, float rnd) | ||
| 180 | { | ||
| 181 | c->rnd = fabsf(rnd); | ||
| 182 | } | ||
| 183 | |||
| 184 | void tCrusher_setSamplingRatio (tCrusher* const c, float ratio) | ||
| 185 | { | ||
| 186 | c->srr = ratio; | ||
| 187 | } | ||
| 188 | |||
| 189 | |||
| 190 | //============================================================================================================ | ||
| 21 | // Oversampler | 191 | // Oversampler |
| 192 | //============================================================================================================ | ||
| 22 | // Latency is equal to the phase length (numTaps / ratio) | 193 | // Latency is equal to the phase length (numTaps / ratio) |
| 23 | void tOversampler_init(tOversampler* const os, int ratio, oBool extraQuality) | 194 | void tOversampler_init(tOversampler* const os, int ratio, oBool extraQuality) |
| 24 | { | 195 | { |
| @@ -0,0 +1,172 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-dynamics.c | ||
| 4 | Created: 30 Nov 2018 11:56:49am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-dynamics.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include "../Inc/leaf-dynamics.h" | ||
| 16 | |||
| 17 | #endif | ||
| 18 | |||
| 19 | //============================================================================== | ||
| 20 | |||
| 21 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compressor ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | ||
| 22 | |||
| 23 | /* | ||
| 24 | tCompressor* tCompressorInit(int tauAttack, int tauRelease) | ||
| 25 | { | ||
| 26 | tCompressor* c = &leaf.tCompressorRegistry[leaf.registryIndex[T_COMPRESSOR]++]; | ||
| 27 | |||
| 28 | c->tauAttack = tauAttack; | ||
| 29 | c->tauRelease = tauRelease; | ||
| 30 | |||
| 31 | c->x_G[0] = 0.0f, c->x_G[1] = 0.0f, | ||
| 32 | c->y_G[0] = 0.0f, c->y_G[1] = 0.0f, | ||
| 33 | c->x_T[0] = 0.0f, c->x_T[1] = 0.0f, | ||
| 34 | c->y_T[0] = 0.0f, c->y_T[1] = 0.0f; | ||
| 35 | |||
| 36 | c->T = 0.0f; // Threshold | ||
| 37 | c->R = 1.0f; // compression Ratio | ||
| 38 | c->M = 0.0f; // decibel Make-up gain | ||
| 39 | c->W = 0.0f; // decibel Width of knee transition | ||
| 40 | |||
| 41 | return c; | ||
| 42 | } | ||
| 43 | */ | ||
| 44 | void tCompressor_init(tCompressor* const c) | ||
| 45 | { | ||
| 46 | c->tauAttack = 100; | ||
| 47 | c->tauRelease = 100; | ||
| 48 | |||
| 49 | c->isActive = OFALSE; | ||
| 50 | |||
| 51 | c->T = 0.0f; // Threshold | ||
| 52 | c->R = 0.5f; // compression Ratio | ||
| 53 | c->M = 3.0f; // decibel Width of knee transition | ||
| 54 | c->W = 1.0f; // decibel Make-up gain | ||
| 55 | } | ||
| 56 | |||
| 57 | void tCompressor_free(tCompressor* const c) | ||
| 58 | { | ||
| 59 | |||
| 60 | } | ||
| 61 | |||
| 62 | int ccount = 0; | ||
| 63 | float tCompressor_tick(tCompressor* const c, float in) | ||
| 64 | { | ||
| 65 | float slope, overshoot; | ||
| 66 | float alphaAtt, alphaRel; | ||
| 67 | |||
| 68 | float in_db = 20.0f * log10f( fmaxf( fabsf( in), 0.000001f)), out_db = 0.0f; | ||
| 69 | |||
| 70 | c->y_T[1] = c->y_T[0]; | ||
| 71 | |||
| 72 | slope = c->R - 1.0f; // feed-forward topology; was 1/C->R - 1 | ||
| 73 | |||
| 74 | overshoot = in_db - c->T; | ||
| 75 | |||
| 76 | |||
| 77 | if (overshoot <= -(c->W * 0.5f)) | ||
| 78 | { | ||
| 79 | out_db = in_db; | ||
| 80 | c->isActive = OFALSE; | ||
| 81 | } | ||
| 82 | else if ((overshoot > -(c->W * 0.5f)) && (overshoot < (c->W * 0.5f))) | ||
| 83 | { | ||
| 84 | out_db = in_db + slope * (powf((overshoot + c->W*0.5f),2) / (2.0f * c->W)); // .^ 2 ??? | ||
| 85 | c->isActive = OTRUE; | ||
| 86 | } | ||
| 87 | else if (overshoot >= (c->W * 0.5f)) | ||
| 88 | { | ||
| 89 | out_db = in_db + slope * overshoot; | ||
| 90 | c->isActive = OTRUE; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | |||
| 95 | c->x_T[0] = out_db - in_db; | ||
| 96 | |||
| 97 | alphaAtt = expf(-1.0f/(0.001f * c->tauAttack * leaf.sampleRate)); | ||
| 98 | alphaRel = expf(-1.0f/(0.001f * c->tauRelease * leaf.sampleRate)); | ||
| 99 | |||
| 100 | if (c->x_T[0] > c->y_T[1]) | ||
| 101 | c->y_T[0] = alphaAtt * c->y_T[1] + (1-alphaAtt) * c->x_T[0]; | ||
| 102 | else | ||
| 103 | c->y_T[0] = alphaRel * c->y_T[1] + (1-alphaRel) * c->x_T[0]; | ||
| 104 | |||
| 105 | float attenuation = powf(10.0f, ((c->M - c->y_T[0])/20.0f)); | ||
| 106 | |||
| 107 | /* | ||
| 108 | if (++ccount > 5000) | ||
| 109 | { | ||
| 110 | |||
| 111 | ccount = 0; | ||
| 112 | DBG(".5width: " + String(c->W * 0.5f)); | ||
| 113 | DBG("slope: " + String(slope) + " overshoot: " + String(overshoot)); | ||
| 114 | DBG("attenuation: " + String(attenuation)); | ||
| 115 | } | ||
| 116 | */ | ||
| 117 | return attenuation * in; | ||
| 118 | |||
| 119 | |||
| 120 | } | ||
| 121 | |||
| 122 | /* Feedback Leveler */ | ||
| 123 | |||
| 124 | void tFeedbackLeveler_init(tFeedbackLeveler* const p, float targetLevel, float factor, float strength, int mode) | ||
| 125 | { | ||
| 126 | p->curr=0.0f; | ||
| 127 | p->targetLevel=targetLevel; | ||
| 128 | tPowerFollower_init(&p->pwrFlw,factor); | ||
| 129 | p->mode=mode; | ||
| 130 | p->strength=strength; | ||
| 131 | } | ||
| 132 | |||
| 133 | void tFeedbackLeveler_free(tFeedbackLeveler* const p) | ||
| 134 | { | ||
| 135 | tPowerFollower_free(&p->pwrFlw); | ||
| 136 | } | ||
| 137 | |||
| 138 | void tFeedbackLeveler_setStrength(tFeedbackLeveler* const p, float strength) | ||
| 139 | { // strength is how strongly level diff is affecting the amp ratio | ||
| 140 | // try 0.125 for a start | ||
| 141 | p->strength=strength; | ||
| 142 | } | ||
| 143 | |||
| 144 | void tFeedbackLeveler_setFactor(tFeedbackLeveler* const p, float factor) | ||
| 145 | { | ||
| 146 | tPowerFollower_setFactor(&p->pwrFlw,factor); | ||
| 147 | } | ||
| 148 | |||
| 149 | void tFeedbackLeveler_setMode(tFeedbackLeveler* const p, int mode) | ||
| 150 | { // 0 for decaying with upwards lev limiting, 1 for constrained absolute level (also downwards limiting) | ||
| 151 | p->mode=mode; | ||
| 152 | } | ||
| 153 | |||
| 154 | float tFeedbackLeveler_tick(tFeedbackLeveler* const p, float input) | ||
| 155 | { | ||
| 156 | float levdiff=(tPowerFollower_tick(&p->pwrFlw, input)-p->targetLevel); | ||
| 157 | if (p->mode==0 && levdiff<0) levdiff=0; | ||
| 158 | p->curr=input*(1-p->strength*levdiff); | ||
| 159 | return p->curr; | ||
| 160 | } | ||
| 161 | |||
| 162 | float tFeedbackLeveler_sample(tFeedbackLeveler* const p) | ||
| 163 | { | ||
| 164 | return p->curr; | ||
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const p, float TargetLevel) | ||
| 169 | { | ||
| 170 | p->targetLevel=TargetLevel; | ||
| 171 | } | ||
| 172 | |||
| @@ -0,0 +1,1393 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-vocoder.c | ||
| 4 | Created: 20 Jan 2017 12:01:54pm | ||
| 5 | Author: Michael R Mulshine | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-effects.c" | ||
| 12 | #include "..\leaf.h" | ||
| 13 | |||
| 14 | #else | ||
| 15 | |||
| 16 | #include "../Inc/leaf-effects.h" | ||
| 17 | #include "../leaf.h" | ||
| 18 | |||
| 19 | #endif | ||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | //============================================================================================================ | ||
| 24 | // TALKBOX | ||
| 25 | //============================================================================================================ | ||
| 26 | |||
| 27 | void tTalkbox_init(tTalkbox* const v, int bufsize) | ||
| 28 | { | ||
| 29 | v->param[0] = 0.5f; //wet | ||
| 30 | v->param[1] = 0.0f; //dry | ||
| 31 | v->param[2] = 0; // Swap | ||
| 32 | v->param[3] = 1.0f; //quality | ||
| 33 | |||
| 34 | v->bufsize = bufsize; | ||
| 35 | |||
| 36 | v->car0 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 37 | v->car1 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 38 | v->window = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 39 | v->buf0 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 40 | v->buf1 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 41 | |||
| 42 | tTalkbox_update(v); | ||
| 43 | } | ||
| 44 | |||
| 45 | void tTalkbox_free(tTalkbox* const v) | ||
| 46 | { | ||
| 47 | leaf_free(v->car0); | ||
| 48 | leaf_free(v->car1); | ||
| 49 | leaf_free(v->window); | ||
| 50 | leaf_free(v->buf0); | ||
| 51 | leaf_free(v->buf1); | ||
| 52 | } | ||
| 53 | |||
| 54 | void tTalkbox_update(tTalkbox* const v) ///update internal parameters... | ||
| 55 | { | ||
| 56 | float fs = leaf.sampleRate; | ||
| 57 | if(fs < 8000.0f) fs = 8000.0f; | ||
| 58 | if(fs > 96000.0f) fs = 96000.0f; | ||
| 59 | |||
| 60 | int32_t n = (int32_t)(0.01633f * fs); | ||
| 61 | if(n > v->bufsize) n = v->bufsize; | ||
| 62 | |||
| 63 | //O = (VstInt32)(0.0005f * fs); | ||
| 64 | v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs); | ||
| 65 | |||
| 66 | if(n != v->N) //recalc hanning window | ||
| 67 | { | ||
| 68 | v->N = n; | ||
| 69 | float dp = TWO_PI / v->N; | ||
| 70 | float p = 0.0f; | ||
| 71 | for(n=0; n<v->N; n++) | ||
| 72 | { | ||
| 73 | v->window[n] = 0.5f - 0.5f * cosf(p); | ||
| 74 | p += dp; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | v->wet = 0.5f * v->param[0] * v->param[0]; | ||
| 78 | v->dry = 2.0f * v->param[1] * v->param[1]; | ||
| 79 | } | ||
| 80 | |||
| 81 | void tTalkbox_suspend(tTalkbox* const v) ///clear any buffers... | ||
| 82 | { | ||
| 83 | v->pos = v->K = 0; | ||
| 84 | v->emphasis = 0.0f; | ||
| 85 | v->FX = 0; | ||
| 86 | |||
| 87 | v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f; | ||
| 88 | v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f; | ||
| 89 | |||
| 90 | for (int32_t i = 0; i < v->bufsize; i++) | ||
| 91 | { | ||
| 92 | v->buf0[i] = 0; | ||
| 93 | v->buf1[i] = 0; | ||
| 94 | v->car0[i] = 0; | ||
| 95 | v->car1[i] = 0; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | #define ORD_MAX 100 // Was 50. Increasing this gets rid of glitchiness, lowering it breaks it; not sure how it affects performance | ||
| 101 | void tTalkbox_lpc(float *buf, float *car, int32_t n, int32_t o) | ||
| 102 | { | ||
| 103 | float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x; | ||
| 104 | int32_t i, j, nn=n; | ||
| 105 | |||
| 106 | for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed | ||
| 107 | { | ||
| 108 | z[j] = r[j] = 0.0f; | ||
| 109 | for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation | ||
| 110 | } | ||
| 111 | r[0] *= 1.001f; //stability fix | ||
| 112 | |||
| 113 | float min = 0.00001f; | ||
| 114 | if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; } | ||
| 115 | |||
| 116 | tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs | ||
| 117 | |||
| 118 | for(i=0; i<=o; i++) | ||
| 119 | { | ||
| 120 | if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f; | ||
| 121 | } | ||
| 122 | |||
| 123 | for(i=0; i<n; i++) | ||
| 124 | { | ||
| 125 | x = G * car[i]; | ||
| 126 | for(j=o; j>0; j--) //lattice filter | ||
| 127 | { | ||
| 128 | x -= k[j] * z[j-1]; | ||
| 129 | z[j] = z[j-1] + k[j] * x; | ||
| 130 | } | ||
| 131 | buf[i] = z[0] = x; //output buf[] will be windowed elsewhere | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | |||
| 136 | void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g) | ||
| 137 | { | ||
| 138 | int i, j; | ||
| 139 | float a[ORD_MAX], at[ORD_MAX], e=r[0]; | ||
| 140 | |||
| 141 | for(i=0; i<=p; i++) a[i] = at[i] = 0.0f; //probably don't need to clear at[] or k[] | ||
| 142 | |||
| 143 | for(i=1; i<=p; i++) | ||
| 144 | { | ||
| 145 | k[i] = -r[i]; | ||
| 146 | |||
| 147 | for(j=1; j<i; j++) | ||
| 148 | { | ||
| 149 | at[j] = a[j]; | ||
| 150 | k[i] -= a[j] * r[i-j]; | ||
| 151 | } | ||
| 152 | if(fabs(e) < 1.0e-20f) { e = 0.0f; break; } | ||
| 153 | k[i] /= e; // This might be costing us | ||
| 154 | |||
| 155 | a[i] = k[i]; | ||
| 156 | for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j]; | ||
| 157 | |||
| 158 | e *= 1.0f - k[i] * k[i]; | ||
| 159 | } | ||
| 160 | |||
| 161 | if(e < 1.0e-20f) e = 0.0f; | ||
| 162 | *g = sqrtf(e); | ||
| 163 | } | ||
| 164 | |||
| 165 | float tTalkbox_tick(tTalkbox* const v, float synth, float voice) | ||
| 166 | { | ||
| 167 | |||
| 168 | int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N; | ||
| 169 | float e=v->emphasis, w, o, x, dr, fx=v->FX; | ||
| 170 | float p, q, h0=0.3f, h1=0.77f; | ||
| 171 | |||
| 172 | o = voice; | ||
| 173 | x = synth; | ||
| 174 | |||
| 175 | dr = o; | ||
| 176 | |||
| 177 | p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p; | ||
| 178 | q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q; | ||
| 179 | v->d4 = x; | ||
| 180 | x = p + q; | ||
| 181 | |||
| 182 | if(v->K++) | ||
| 183 | { | ||
| 184 | v->K = 0; | ||
| 185 | |||
| 186 | v->car0[p0] = v->car1[p1] = x; //carrier input | ||
| 187 | |||
| 188 | x = o - e; e = o; //6dB/oct pre-emphasis | ||
| 189 | |||
| 190 | w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows | ||
| 191 | if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->N, v->O); p0 = 0; } | ||
| 192 | |||
| 193 | w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w; | ||
| 194 | if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->N, v->O); p1 = 0; } | ||
| 195 | } | ||
| 196 | |||
| 197 | p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p; | ||
| 198 | q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q; | ||
| 199 | v->u4 = fx; | ||
| 200 | x = p + q; | ||
| 201 | |||
| 202 | o = x; | ||
| 203 | |||
| 204 | v->emphasis = e; | ||
| 205 | v->pos = p0; | ||
| 206 | v->FX = fx; | ||
| 207 | |||
| 208 | float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]); | ||
| 209 | if(fabs(v->d0) < den) v->d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?) | ||
| 210 | if(fabs(v->d1) < den) v->d1 = 0.0f; | ||
| 211 | if(fabs(v->d2) < den) v->d2 = 0.0f; | ||
| 212 | if(fabs(v->d3) < den) v->d3 = 0.0f; | ||
| 213 | if(fabs(v->u0) < den) v->u0 = 0.0f; | ||
| 214 | if(fabs(v->u1) < den) v->u1 = 0.0f; | ||
| 215 | if(fabs(v->u2) < den) v->u2 = 0.0f; | ||
| 216 | if(fabs(v->u3) < den) v->u3 = 0.0f; | ||
| 217 | return o; | ||
| 218 | } | ||
| 219 | |||
| 220 | void tTalkbox_setQuality(tTalkbox* const v, float quality) | ||
| 221 | { | ||
| 222 | v->param[3] = quality; | ||
| 223 | v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate); | ||
| 224 | } | ||
| 225 | |||
| 226 | |||
| 227 | //============================================================================================================ | ||
| 228 | // VOCODER | ||
| 229 | //============================================================================================================ | ||
| 230 | |||
| 231 | void tVocoder_init (tVocoder* const v) | ||
| 232 | { | ||
| 233 | v->param[0] = 0.33f; //input select | ||
| 234 | v->param[1] = 0.50f; //output dB | ||
| 235 | v->param[2] = 0.40f; //hi thru | ||
| 236 | v->param[3] = 0.40f; //hi band | ||
| 237 | v->param[4] = 0.16f; //envelope | ||
| 238 | v->param[5] = 0.55f; //filter q | ||
| 239 | v->param[6] = 0.6667f;//freq range | ||
| 240 | v->param[7] = 0.33f; //num bands | ||
| 241 | |||
| 242 | tVocoder_update(v); | ||
| 243 | } | ||
| 244 | |||
| 245 | void tVocoder_free (tVocoder* const v) | ||
| 246 | { | ||
| 247 | |||
| 248 | } | ||
| 249 | |||
| 250 | void tVocoder_update (tVocoder* const v) | ||
| 251 | { | ||
| 252 | float tpofs = 6.2831853f * leaf.invSampleRate; | ||
| 253 | |||
| 254 | float rr, th, re; | ||
| 255 | |||
| 256 | float sh; | ||
| 257 | |||
| 258 | int32_t i; | ||
| 259 | |||
| 260 | v->gain = (float)pow(10.0f, 2.0f * v->param[1] - 3.0f * v->param[5] - 2.0f); | ||
| 261 | |||
| 262 | v->thru = (float)pow(10.0f, 0.5f + 2.0f * v->param[1]); | ||
| 263 | v->high = v->param[3] * v->param[3] * v->param[3] * v->thru; | ||
| 264 | v->thru *= v->param[2] * v->param[2] * v->param[2]; | ||
| 265 | |||
| 266 | if(v->param[7]<0.5f) | ||
| 267 | { | ||
| 268 | v->nbnd=8; | ||
| 269 | re=0.003f; | ||
| 270 | v->f[1][2] = 3000.0f; | ||
| 271 | v->f[2][2] = 2200.0f; | ||
| 272 | v->f[3][2] = 1500.0f; | ||
| 273 | v->f[4][2] = 1080.0f; | ||
| 274 | v->f[5][2] = 700.0f; | ||
| 275 | v->f[6][2] = 390.0f; | ||
| 276 | v->f[7][2] = 190.0f; | ||
| 277 | } | ||
| 278 | else | ||
| 279 | { | ||
| 280 | v->nbnd=16; | ||
| 281 | re=0.0015f; | ||
| 282 | v->f[ 1][2] = 5000.0f; //+1000 | ||
| 283 | v->f[ 2][2] = 4000.0f; //+750 | ||
| 284 | v->f[ 3][2] = 3250.0f; //+500 | ||
| 285 | v->f[ 4][2] = 2750.0f; //+450 | ||
| 286 | v->f[ 5][2] = 2300.0f; //+300 | ||
| 287 | v->f[ 6][2] = 2000.0f; //+250 | ||
| 288 | v->f[ 7][2] = 1750.0f; //+250 | ||
| 289 | v->f[ 8][2] = 1500.0f; //+250 | ||
| 290 | v->f[ 9][2] = 1250.0f; //+250 | ||
| 291 | v->f[10][2] = 1000.0f; //+250 | ||
| 292 | v->f[11][2] = 750.0f; //+210 | ||
| 293 | v->f[12][2] = 540.0f; //+190 | ||
| 294 | v->f[13][2] = 350.0f; //+155 | ||
| 295 | v->f[14][2] = 195.0f; //+100 | ||
| 296 | v->f[15][2] = 95.0f; | ||
| 297 | } | ||
| 298 | |||
| 299 | if(v->param[4]<0.05f) //freeze | ||
| 300 | { | ||
| 301 | for(i=0;i<v->nbnd;i++) v->f[i][12]=0.0f; | ||
| 302 | } | ||
| 303 | else | ||
| 304 | { | ||
| 305 | v->f[0][12] = (float)pow(10.0, -1.7 - 2.7f * v->param[4]); //envelope speed | ||
| 306 | |||
| 307 | rr = 0.022f / (float)v->nbnd; //minimum proportional to frequency to stop distortion | ||
| 308 | for(i=1;i<v->nbnd;i++) | ||
| 309 | { | ||
| 310 | v->f[i][12] = (float)(0.025 - rr * (double)i); | ||
| 311 | if(v->f[0][12] < v->f[i][12]) v->f[i][12] = v->f[0][12]; | ||
| 312 | } | ||
| 313 | v->f[0][12] = 0.5f * v->f[0][12]; //only top band is at full rate | ||
| 314 | } | ||
| 315 | |||
| 316 | rr = 1.0 - pow(10.0f, -1.0f - 1.2f * v->param[5]); | ||
| 317 | sh = (float)pow(2.0f, 3.0f * v->param[6] - 1.0f); //filter bank range shift | ||
| 318 | |||
| 319 | for(i=1;i<v->nbnd;i++) | ||
| 320 | { | ||
| 321 | v->f[i][2] *= sh; | ||
| 322 | th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr)); | ||
| 323 | v->f[i][0] = (float)(2.0 * rr * cos(th)); //a0 | ||
| 324 | v->f[i][1] = (float)(-rr * rr); //a1 | ||
| 325 | //was .98 | ||
| 326 | v->f[i][2] *= 0.96f; //shift 2nd stage slightly to stop high resonance peaks | ||
| 327 | th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr)); | ||
| 328 | v->f[i][2] = (float)(2.0 * rr * cos(th)); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | float tVocoder_tick (tVocoder* const v, float synth, float voice) | ||
| 333 | { | ||
| 334 | float a, b, o=0.0f, aa, bb, oo = v->kout, g = v->gain, ht = v->thru, hh = v->high, tmp; | ||
| 335 | uint32_t i, k = v->kval, nb = v->nbnd; | ||
| 336 | |||
| 337 | a = voice; //speech | ||
| 338 | b = synth; //synth | ||
| 339 | |||
| 340 | tmp = a - v->f[0][7]; //integrate modulator for HF band and filter bank pre-emphasis | ||
| 341 | v->f[0][7] = a; | ||
| 342 | a = tmp; | ||
| 343 | |||
| 344 | if(tmp<0.0f) tmp = -tmp; | ||
| 345 | v->f[0][11] -= v->f[0][12] * (v->f[0][11] - tmp); //high band envelope | ||
| 346 | o = v->f[0][11] * (ht * a + hh * (b - v->f[0][3])); //high band + high thru | ||
| 347 | |||
| 348 | v->f[0][3] = b; //integrate carrier for HF band | ||
| 349 | |||
| 350 | if(++k & 0x1) //this block runs at half sample rate | ||
| 351 | { | ||
| 352 | oo = 0.0f; | ||
| 353 | aa = a + v->f[0][9] - v->f[0][8] - v->f[0][8]; //apply zeros here instead of in each reson | ||
| 354 | v->f[0][9] = v->f[0][8]; v->f[0][8] = a; | ||
| 355 | bb = b + v->f[0][5] - v->f[0][4] - v->f[0][4]; | ||
| 356 | v->f[0][5] = v->f[0][4]; v->f[0][4] = b; | ||
| 357 | |||
| 358 | for(i=1; i<nb; i++) //filter bank: 4th-order band pass | ||
| 359 | { | ||
| 360 | tmp = v->f[i][0] * v->f[i][3] + v->f[i][1] * v->f[i][4] + bb; | ||
| 361 | v->f[i][4] = v->f[i][3]; | ||
| 362 | v->f[i][3] = tmp; | ||
| 363 | tmp += v->f[i][2] * v->f[i][5] + v->f[i][1] * v->f[i][6]; | ||
| 364 | v->f[i][6] = v->f[i][5]; | ||
| 365 | v->f[i][5] = tmp; | ||
| 366 | |||
| 367 | tmp = v->f[i][0] * v->f[i][7] + v->f[i][1] * v->f[i][8] + aa; | ||
| 368 | v->f[i][8] = v->f[i][7]; | ||
| 369 | v->f[i][7] = tmp; | ||
| 370 | tmp += v->f[i][2] * v->f[i][9] + v->f[i][1] * v->f[i][10]; | ||
| 371 | v->f[i][10] = v->f[i][9]; | ||
| 372 | v->f[i][9] = tmp; | ||
| 373 | |||
| 374 | if(tmp<0.0f) tmp = -tmp; | ||
| 375 | v->f[i][11] -= v->f[i][12] * (v->f[i][11] - tmp); | ||
| 376 | oo += v->f[i][5] * v->f[i][11]; | ||
| 377 | } | ||
| 378 | } | ||
| 379 | o += oo * g; //effect of interpolating back up to Fs would be minimal (aliasing >16kHz) | ||
| 380 | |||
| 381 | v->kout = oo; | ||
| 382 | v->kval = k & 0x1; | ||
| 383 | if(fabs(v->f[0][11])<1.0e-10) v->f[0][11] = 0.0f; //catch HF envelope denormal | ||
| 384 | |||
| 385 | for(i=1;i<nb;i++) | ||
| 386 | if(fabs(v->f[i][3])<1.0e-10 || fabs(v->f[i][7])<1.0e-10) | ||
| 387 | for(k=3; k<12; k++) v->f[i][k] = 0.0f; //catch reson & envelope denormals | ||
| 388 | |||
| 389 | if(fabs(o)>10.0f) tVocoder_suspend(v); //catch instability | ||
| 390 | |||
| 391 | return o; | ||
| 392 | |||
| 393 | } | ||
| 394 | |||
| 395 | void tVocoder_suspend (tVocoder* const v) | ||
| 396 | { | ||
| 397 | int32_t i, j; | ||
| 398 | |||
| 399 | for(i=0; i<v->nbnd; i++) for(j=3; j<12; j++) v->f[i][j] = 0.0f; //zero band filters and envelopes | ||
| 400 | v->kout = 0.0f; | ||
| 401 | v->kval = 0; | ||
| 402 | } | ||
| 403 | |||
| 404 | //============================================================================================================ | ||
| 405 | // PITCHSHIFTER | ||
| 406 | //============================================================================================================ | ||
| 407 | static int pitchshifter_attackdetect(tPitchShifter* ps); | ||
| 408 | |||
| 409 | void tPitchShifter_init(tPitchShifter* const ps, float* in, float* out, int bufSize, int frameSize) | ||
| 410 | { | ||
| 411 | ps->inBuffer = in; | ||
| 412 | ps->outBuffer = out; | ||
| 413 | ps->bufSize = bufSize; | ||
| 414 | ps->frameSize = frameSize; | ||
| 415 | ps->framesPerBuffer = ps->bufSize / ps->frameSize; | ||
| 416 | ps->curBlock = 1; | ||
| 417 | ps->lastBlock = 0; | ||
| 418 | ps->index = 0; | ||
| 419 | |||
| 420 | ps->hopSize = DEFHOPSIZE; | ||
| 421 | ps->windowSize = DEFWINDOWSIZE; | ||
| 422 | ps->fba = FBA; | ||
| 423 | |||
| 424 | tEnvPD_init(&ps->env, ps->windowSize, ps->hopSize, ps->frameSize); | ||
| 425 | |||
| 426 | tSNAC_init(&ps->snac, DEFOVERLAP); | ||
| 427 | |||
| 428 | tSOLAD_init(&ps->sola); | ||
| 429 | |||
| 430 | tHighpass_init(&ps->hp, HPFREQ); | ||
| 431 | |||
| 432 | tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO); | ||
| 433 | |||
| 434 | tPitchShifter_setTimeConstant(ps, DEFTIMECONSTANT); | ||
| 435 | } | ||
| 436 | |||
| 437 | void tPitchShifter_free(tPitchShifter* const ps) | ||
| 438 | { | ||
| 439 | tEnvPD_free(&ps->env); | ||
| 440 | tSNAC_free(&ps->snac); | ||
| 441 | tSOLAD_free(&ps->sola); | ||
| 442 | tHighpass_free(&ps->hp); | ||
| 443 | } | ||
| 444 | |||
| 445 | float tPitchShifter_tick(tPitchShifter* ps, float sample) | ||
| 446 | { | ||
| 447 | float period, out; | ||
| 448 | int i, iLast; | ||
| 449 | |||
| 450 | i = (ps->curBlock*ps->frameSize); | ||
| 451 | iLast = (ps->lastBlock*ps->frameSize)+ps->index; | ||
| 452 | |||
| 453 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 454 | ps->inBuffer[i+ps->index] = sample; | ||
| 455 | |||
| 456 | ps->index++; | ||
| 457 | if (ps->index >= ps->frameSize) | ||
| 458 | { | ||
| 459 | ps->index = 0; | ||
| 460 | |||
| 461 | tEnvPD_processBlock(&ps->env, &(ps->inBuffer[i])); | ||
| 462 | |||
| 463 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 464 | { | ||
| 465 | ps->fba = 5; | ||
| 466 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 467 | } | ||
| 468 | |||
| 469 | tSNAC_ioSamples(&ps->snac, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 470 | period = tSNAC_getPeriod(&ps->snac); | ||
| 471 | |||
| 472 | ps->curBlock++; | ||
| 473 | if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0; | ||
| 474 | ps->lastBlock++; | ||
| 475 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 476 | |||
| 477 | //separate here | ||
| 478 | |||
| 479 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 480 | |||
| 481 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 482 | tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 483 | |||
| 484 | } | ||
| 485 | |||
| 486 | return out; | ||
| 487 | } | ||
| 488 | |||
| 489 | float tPitchShifterToFreq_tick(tPitchShifter* ps, float sample, float freq) | ||
| 490 | { | ||
| 491 | float period, out; | ||
| 492 | int i, iLast; | ||
| 493 | |||
| 494 | i = (ps->curBlock*ps->frameSize); | ||
| 495 | iLast = (ps->lastBlock*ps->frameSize)+ps->index; | ||
| 496 | |||
| 497 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 498 | ps->inBuffer[i+ps->index] = sample; | ||
| 499 | |||
| 500 | ps->index++; | ||
| 501 | if (ps->index >= ps->frameSize) | ||
| 502 | { | ||
| 503 | ps->index = 0; | ||
| 504 | |||
| 505 | tEnvPD_processBlock(&ps->env, &(ps->inBuffer[i])); | ||
| 506 | |||
| 507 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 508 | { | ||
| 509 | ps->fba = 5; | ||
| 510 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 511 | } | ||
| 512 | |||
| 513 | tSNAC_ioSamples(&ps->snac, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 514 | period = tSNAC_getPeriod(&ps->snac); | ||
| 515 | |||
| 516 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 517 | |||
| 518 | ps->pitchFactor = period*freq*leaf.invSampleRate; | ||
| 519 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 520 | tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 521 | |||
| 522 | ps->curBlock++; | ||
| 523 | if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0; | ||
| 524 | ps->lastBlock++; | ||
| 525 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | return out; | ||
| 529 | } | ||
| 530 | |||
| 531 | float tPitchShifterToFunc_tick(tPitchShifter* ps, float sample, float (*fun)(float)) | ||
| 532 | { | ||
| 533 | float period, out; | ||
| 534 | int i, iLast; | ||
| 535 | |||
| 536 | i = (ps->curBlock*ps->frameSize); | ||
| 537 | iLast = (ps->lastBlock*ps->frameSize)+ps->index; | ||
| 538 | |||
| 539 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 540 | ps->inBuffer[i+ps->index] = sample; | ||
| 541 | |||
| 542 | ps->index++; | ||
| 543 | if (ps->index >= ps->frameSize) | ||
| 544 | { | ||
| 545 | ps->index = 0; | ||
| 546 | |||
| 547 | tEnvPD_processBlock(&ps->env, &(ps->inBuffer[i])); | ||
| 548 | |||
| 549 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 550 | { | ||
| 551 | ps->fba = 5; | ||
| 552 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 553 | } | ||
| 554 | |||
| 555 | tSNAC_ioSamples(&ps->snac, (&ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 556 | period = tSNAC_getPeriod(&ps->snac); | ||
| 557 | |||
| 558 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 559 | |||
| 560 | ps->pitchFactor = period/fun(period); | ||
| 561 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 562 | tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 563 | |||
| 564 | ps->curBlock++; | ||
| 565 | if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0; | ||
| 566 | ps->lastBlock++; | ||
| 567 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 568 | } | ||
| 569 | |||
| 570 | return out; | ||
| 571 | } | ||
| 572 | |||
| 573 | void tPitchShifter_ioSamples(tPitchShifter* ps, float* in, float* out, int size) | ||
| 574 | { | ||
| 575 | float period; | ||
| 576 | |||
| 577 | tEnvPD_processBlock(&ps->env, in); | ||
| 578 | |||
| 579 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 580 | { | ||
| 581 | ps->fba = 5; | ||
| 582 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 583 | } | ||
| 584 | |||
| 585 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 586 | period = tSNAC_getPeriod(&ps->snac); | ||
| 587 | |||
| 588 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 589 | |||
| 590 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 591 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 592 | |||
| 593 | for (int cc = 0; cc < size; ++cc) | ||
| 594 | { | ||
| 595 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 596 | } | ||
| 597 | } | ||
| 598 | |||
| 599 | void tPitchShifter_ioSamples_toFreq(tPitchShifter* ps, float* in, float* out, int size, float toFreq) | ||
| 600 | { | ||
| 601 | float period; | ||
| 602 | |||
| 603 | tEnvPD_processBlock(&ps->env, in); | ||
| 604 | |||
| 605 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 606 | { | ||
| 607 | ps->fba = 5; | ||
| 608 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 609 | } | ||
| 610 | |||
| 611 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 612 | period = tSNAC_getPeriod(&ps->snac); | ||
| 613 | |||
| 614 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 615 | ps->pitchFactor = period*toFreq; | ||
| 616 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 617 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 618 | |||
| 619 | for (int cc = 0; cc < size; ++cc) | ||
| 620 | { | ||
| 621 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 622 | } | ||
| 623 | } | ||
| 624 | |||
| 625 | void tPitchShifter_ioSamples_toPeriod(tPitchShifter* ps, float* in, float* out, int size, float toPeriod) | ||
| 626 | { | ||
| 627 | float period; | ||
| 628 | |||
| 629 | tEnvPD_processBlock(&ps->env, in); | ||
| 630 | |||
| 631 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 632 | { | ||
| 633 | ps->fba = 5; | ||
| 634 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 635 | } | ||
| 636 | |||
| 637 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 638 | period = tSNAC_getPeriod(&ps->snac); | ||
| 639 | |||
| 640 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 641 | ps->pitchFactor = period/toPeriod; | ||
| 642 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 643 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 644 | |||
| 645 | for (int cc = 0; cc < size; ++cc) | ||
| 646 | { | ||
| 647 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | void tPitchShifter_ioSamples_toFunc(tPitchShifter* ps, float* in, float* out, int size, float (*fun)(float)) | ||
| 652 | { | ||
| 653 | float period; | ||
| 654 | |||
| 655 | tEnvPD_processBlock(&ps->env, in); | ||
| 656 | |||
| 657 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 658 | { | ||
| 659 | ps->fba = 5; | ||
| 660 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 661 | } | ||
| 662 | |||
| 663 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 664 | period = tSNAC_getPeriod(&ps->snac); | ||
| 665 | |||
| 666 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 667 | ps->pitchFactor = period/fun(period); | ||
| 668 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 669 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 670 | |||
| 671 | for (int cc = 0; cc < size; ++cc) | ||
| 672 | { | ||
| 673 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 674 | } | ||
| 675 | } | ||
| 676 | |||
| 677 | void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf) | ||
| 678 | { | ||
| 679 | ps->pitchFactor = pf; | ||
| 680 | } | ||
| 681 | |||
| 682 | void tPitchShifter_setTimeConstant(tPitchShifter* ps, float tc) | ||
| 683 | { | ||
| 684 | ps->timeConstant = tc; | ||
| 685 | ps->radius = expf(-1000.0f * ps->hopSize * leaf.invSampleRate / ps->timeConstant); | ||
| 686 | } | ||
| 687 | |||
| 688 | void tPitchShifter_setHopSize(tPitchShifter* ps, int hs) | ||
| 689 | { | ||
| 690 | ps->hopSize = hs; | ||
| 691 | } | ||
| 692 | |||
| 693 | void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws) | ||
| 694 | { | ||
| 695 | ps->windowSize = ws; | ||
| 696 | } | ||
| 697 | |||
| 698 | float tPitchShifter_getPeriod(tPitchShifter* ps) | ||
| 699 | { | ||
| 700 | return tSNAC_getPeriod(&ps->snac); | ||
| 701 | } | ||
| 702 | |||
| 703 | static int pitchshifter_attackdetect(tPitchShifter* ps) | ||
| 704 | { | ||
| 705 | float envout; | ||
| 706 | |||
| 707 | envout = tEnvPD_tick(&ps->env); | ||
| 708 | |||
| 709 | if (envout >= 1.0f) | ||
| 710 | { | ||
| 711 | ps->lastmax = ps->max; | ||
| 712 | if (envout > ps->max) | ||
| 713 | { | ||
| 714 | ps->max = envout; | ||
| 715 | } | ||
| 716 | else | ||
| 717 | { | ||
| 718 | ps->deltamax = envout - ps->max; | ||
| 719 | ps->max = ps->max * ps->radius; | ||
| 720 | } | ||
| 721 | ps->deltamax = ps->max - ps->lastmax; | ||
| 722 | } | ||
| 723 | |||
| 724 | ps->fba = ps->fba ? (ps->fba - 1) : 0; | ||
| 725 | |||
| 726 | return (ps->fba == 0 && (ps->max > 60 && ps->deltamax > 6)) ? 1 : 0; | ||
| 727 | } | ||
| 728 | |||
| 729 | |||
| 730 | //============================================================================================================ | ||
| 731 | // PITCHSHIFT | ||
| 732 | //============================================================================================================ | ||
| 733 | |||
| 734 | static int pitchshift_attackdetect(tPitchShift* ps) | ||
| 735 | { | ||
| 736 | float envout; | ||
| 737 | |||
| 738 | envout = tEnvPD_tick(&ps->p->env); | ||
| 739 | |||
| 740 | if (envout >= 1.0f) | ||
| 741 | { | ||
| 742 | ps->p->lastmax = ps->p->max; | ||
| 743 | if (envout > ps->p->max) | ||
| 744 | { | ||
| 745 | ps->p->max = envout; | ||
| 746 | } | ||
| 747 | else | ||
| 748 | { | ||
| 749 | ps->p->deltamax = envout - ps->p->max; | ||
| 750 | ps->p->max = ps->p->max * ps->radius; | ||
| 751 | } | ||
| 752 | ps->p->deltamax = ps->p->max - ps->p->lastmax; | ||
| 753 | } | ||
| 754 | |||
| 755 | ps->p->fba = ps->p->fba ? (ps->p->fba - 1) : 0; | ||
| 756 | |||
| 757 | return (ps->p->fba == 0 && (ps->p->max > 60 && ps->p->deltamax > 6)) ? 1 : 0; | ||
| 758 | } | ||
| 759 | |||
| 760 | void tPitchShift_init (tPitchShift* const ps,tPeriodDetection* p, float* out, int bufSize) | ||
| 761 | { | ||
| 762 | ps->p = p; | ||
| 763 | |||
| 764 | ps->outBuffer = out; | ||
| 765 | ps->bufSize = bufSize; | ||
| 766 | ps->frameSize = p->frameSize; | ||
| 767 | ps->framesPerBuffer = ps->bufSize / ps->frameSize; | ||
| 768 | ps->curBlock = 1; | ||
| 769 | ps->lastBlock = 0; | ||
| 770 | ps->index = 0; | ||
| 771 | ps->pitchFactor = 1.0f; | ||
| 772 | |||
| 773 | tSOLAD_init(&ps->sola); | ||
| 774 | |||
| 775 | tHighpass_init(&ps->hp, HPFREQ); | ||
| 776 | |||
| 777 | tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO); | ||
| 778 | } | ||
| 779 | |||
| 780 | void tPitchShift_free(tPitchShift* const ps) | ||
| 781 | { | ||
| 782 | tSOLAD_free(&ps->sola); | ||
| 783 | tHighpass_free(&ps->hp); | ||
| 784 | } | ||
| 785 | |||
| 786 | void tPitchShift_setPitchFactor(tPitchShift* ps, float pf) | ||
| 787 | { | ||
| 788 | ps->pitchFactor = pf; | ||
| 789 | } | ||
| 790 | |||
| 791 | float tPitchShift_shift (tPitchShift* ps) | ||
| 792 | { | ||
| 793 | float period, out; | ||
| 794 | int i, iLast; | ||
| 795 | |||
| 796 | i = ps->p->i; | ||
| 797 | iLast = ps->p->iLast; | ||
| 798 | |||
| 799 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 800 | |||
| 801 | if (ps->p->indexstore >= ps->frameSize) | ||
| 802 | { | ||
| 803 | period = ps->p->period; | ||
| 804 | |||
| 805 | if(pitchshift_attackdetect(ps) == 1) | ||
| 806 | { | ||
| 807 | ps->p->fba = 5; | ||
| 808 | tSOLAD_setReadLag(&ps->sola, ps->p->windowSize); | ||
| 809 | } | ||
| 810 | |||
| 811 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 812 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 813 | |||
| 814 | tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 815 | } | ||
| 816 | |||
| 817 | return out; | ||
| 818 | } | ||
| 819 | |||
| 820 | float tPitchShift_shiftToFreq (tPitchShift* ps, float freq) | ||
| 821 | { | ||
| 822 | float period, out; | ||
| 823 | int i, iLast; | ||
| 824 | |||
| 825 | i = ps->p->i; | ||
| 826 | iLast = ps->p->iLast; | ||
| 827 | |||
| 828 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 829 | |||
| 830 | if (ps->p->indexstore >= ps->frameSize) | ||
| 831 | { | ||
| 832 | period = ps->p->period; | ||
| 833 | |||
| 834 | if(pitchshift_attackdetect(ps) == 1) | ||
| 835 | { | ||
| 836 | ps->p->fba = 5; | ||
| 837 | tSOLAD_setReadLag(&ps->sola, ps->p->windowSize); | ||
| 838 | } | ||
| 839 | |||
| 840 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 841 | |||
| 842 | ps->pitchFactor = period*freq*leaf.invSampleRate; | ||
| 843 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 844 | |||
| 845 | tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 846 | } | ||
| 847 | return out; | ||
| 848 | } | ||
| 849 | |||
| 850 | float tPitchShift_shiftToFunc (tPitchShift* ps, float (*fun)(float)) | ||
| 851 | { | ||
| 852 | float period, out; | ||
| 853 | int i, iLast; | ||
| 854 | |||
| 855 | i = ps->p->i; | ||
| 856 | iLast = ps->p->iLast; | ||
| 857 | |||
| 858 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 859 | |||
| 860 | if (ps->p->indexstore >= ps->frameSize) | ||
| 861 | { | ||
| 862 | period = ps->p->period; | ||
| 863 | |||
| 864 | if(pitchshift_attackdetect(ps) == 1) | ||
| 865 | { | ||
| 866 | ps->p->fba = 5; | ||
| 867 | tSOLAD_setReadLag(&ps->sola, ps->p->windowSize); | ||
| 868 | } | ||
| 869 | |||
| 870 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 871 | |||
| 872 | ps->pitchFactor = period/fun(period); | ||
| 873 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 874 | |||
| 875 | tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 876 | |||
| 877 | ps->curBlock++; | ||
| 878 | if (ps->curBlock >= ps->p->framesPerBuffer) ps->curBlock = 0; | ||
| 879 | ps->lastBlock++; | ||
| 880 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 881 | } | ||
| 882 | |||
| 883 | return out; | ||
| 884 | } | ||
| 885 | |||
| 886 | //============================================================================================================ | ||
| 887 | // SOLAD | ||
| 888 | //============================================================================================================ | ||
| 889 | /******************************************************************************/ | ||
| 890 | /***************** static function declarations *******************************/ | ||
| 891 | /******************************************************************************/ | ||
| 892 | |||
| 893 | static void solad_init(tSOLAD *w); | ||
| 894 | static inline float read_sample(tSOLAD *w, float floatindex); | ||
| 895 | static void pitchdown(tSOLAD *w, float *out); | ||
| 896 | static void pitchup(tSOLAD *w, float *out); | ||
| 897 | |||
| 898 | /******************************************************************************/ | ||
| 899 | /***************** public access functions ************************************/ | ||
| 900 | /******************************************************************************/ | ||
| 901 | |||
| 902 | // init | ||
| 903 | void tSOLAD_init(tSOLAD* const w) | ||
| 904 | { | ||
| 905 | w->pitchfactor = 1.; | ||
| 906 | w->delaybuf = (float*) leaf_alloc(sizeof(float) * (LOOPSIZE+16)); | ||
| 907 | solad_init(w); | ||
| 908 | } | ||
| 909 | |||
| 910 | void tSOLAD_free(tSOLAD* const w) | ||
| 911 | { | ||
| 912 | } | ||
| 913 | |||
| 914 | // send one block of input samples, receive one block of output samples | ||
| 915 | void tSOLAD_ioSamples(tSOLAD* const w, float* in, float* out, int blocksize) | ||
| 916 | { | ||
| 917 | int i = w->timeindex; | ||
| 918 | int n = w->blocksize = blocksize; | ||
| 919 | |||
| 920 | if(!i) w->delaybuf[LOOPSIZE] = in[0]; // copy one sample for interpolation | ||
| 921 | while(n--) w->delaybuf[i++] = *in++; // copy one input block to delay buffer | ||
| 922 | |||
| 923 | if(w->pitchfactor > 1) pitchup(w, out); | ||
| 924 | else pitchdown(w, out); | ||
| 925 | |||
| 926 | w->timeindex += blocksize; | ||
| 927 | w->timeindex &= LOOPMASK; | ||
| 928 | } | ||
| 929 | |||
| 930 | // set periodicity analysis data | ||
| 931 | void tSOLAD_setPeriod(tSOLAD* const w, float period) | ||
| 932 | { | ||
| 933 | if(period > MAXPERIOD) period = MAXPERIOD; | ||
| 934 | if(period > MINPERIOD) w->period = period; // ignore period when too small | ||
| 935 | } | ||
| 936 | |||
| 937 | // set pitch factor between 0.25 and 4 | ||
| 938 | void tSOLAD_setPitchFactor(tSOLAD* const w, float pitchfactor) | ||
| 939 | { | ||
| 940 | if(pitchfactor < 0.25) pitchfactor = 0.25; | ||
| 941 | else if(pitchfactor > 4.) pitchfactor = 4.; | ||
| 942 | w->pitchfactor = pitchfactor; | ||
| 943 | } | ||
| 944 | |||
| 945 | // force readpointer lag | ||
| 946 | void tSOLAD_setReadLag(tSOLAD* const w, float readlag) | ||
| 947 | { | ||
| 948 | if(readlag < 0) readlag = 0; | ||
| 949 | if(readlag < w->readlag) // do not jump backward, only forward | ||
| 950 | { | ||
| 951 | w->jump = w->readlag - readlag; | ||
| 952 | w->readlag = readlag; | ||
| 953 | w->xfadelength = readlag; | ||
| 954 | w->xfadevalue = 1; | ||
| 955 | } | ||
| 956 | } | ||
| 957 | |||
| 958 | // reset state variables | ||
| 959 | void tSOLAD_resetState(tSOLAD* const w) | ||
| 960 | { | ||
| 961 | int n = LOOPSIZE + 1; | ||
| 962 | float *buf = w->delaybuf; | ||
| 963 | |||
| 964 | while(n--) *buf++ = 0; | ||
| 965 | solad_init(w); | ||
| 966 | } | ||
| 967 | |||
| 968 | /******************************************************************************/ | ||
| 969 | /******************** private procedures **************************************/ | ||
| 970 | /******************************************************************************/ | ||
| 971 | |||
| 972 | /* | ||
| 973 | Function pitchdown() is called to read samples from the delay buffer when pitch | ||
| 974 | factor is between 0.25 and 1. The read pointer lags behind because of the slowed | ||
| 975 | down speed, and it must jump forward towards the write pointer soon as there is | ||
| 976 | sufficient space to jump. That is, if there is at least one period of the input | ||
| 977 | signal between read pointer and write pointer. When short periods follow up on | ||
| 978 | long periods, the read pointer may have space to jump over more than one period | ||
| 979 | lenghts. Jump length must be [periodlength ^ 2] in any case. | ||
| 980 | |||
| 981 | A linear crossfade function joins the jump-from point with the jump-to point. | ||
| 982 | The crossfade must be completed before another read pointer jump is allowed. | ||
| 983 | Length of the crossfade function is stored as a number of samples in terms of | ||
| 984 | the input sample rate. This length is dynamically translated | ||
| 985 | to a crossfade length expressed in output reading rate, according to pitch | ||
| 986 | factor which can change before the crossfade is completed. Crossfade length does | ||
| 987 | not cover an invariable length in periods for all pitch transposition factors. | ||
| 988 | For pitch factors from 0.5 till 1, crossfade length is stretched in the | ||
| 989 | output just as much as the signal itself, as crossfade speed is set to equal | ||
| 990 | pitch factor. For pitch factors below 0.5, the read pointer wants to jump | ||
| 991 | forward before one period is read, therefore the crossfade length as expressed | ||
| 992 | in output periods must be shorter. Crossfade speed is set to [1 - pitchfactor] | ||
| 993 | for those cases. Pitch factor 0.5 is the natural switch point between crossfade | ||
| 994 | speeds [pitchfactor] and [1 - pitchfactor] because 0.5 == 1 - 0.5. The crossfade | ||
| 995 | speed modification for pitch factors below 0.5 also means that much of the | ||
| 996 | original signal content will be skipped. | ||
| 997 | */ | ||
| 998 | |||
| 999 | |||
| 1000 | static void pitchdown(tSOLAD* const w, float *out) | ||
| 1001 | { | ||
| 1002 | int n = w->blocksize; | ||
| 1003 | float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values! | ||
| 1004 | float pitchfactor = w->pitchfactor; | ||
| 1005 | float period = w->period; | ||
| 1006 | float readlag = w->readlag; | ||
| 1007 | float readlagstep = 1 - pitchfactor; | ||
| 1008 | float jump = w->jump; | ||
| 1009 | float xfadevalue = w->xfadevalue; | ||
| 1010 | float xfadelength = w->xfadelength; | ||
| 1011 | float xfadespeed, xfadestep, readindex, outputsample; | ||
| 1012 | |||
| 1013 | if(pitchfactor > 0.5) xfadespeed = pitchfactor; | ||
| 1014 | else xfadespeed = 1 - pitchfactor; | ||
| 1015 | xfadestep = xfadespeed / xfadelength; | ||
| 1016 | |||
| 1017 | while(n--) | ||
| 1018 | { | ||
| 1019 | if(readlag > period) // check if read pointer may jump forward... | ||
| 1020 | { | ||
| 1021 | if(xfadevalue <= 0) // ...but do not interrupt crossfade | ||
| 1022 | { | ||
| 1023 | jump = period; // jump forward | ||
| 1024 | while((jump * 2) < readlag) jump *= 2; // use available space | ||
| 1025 | readlag -= jump; // reduce read pointer lag | ||
| 1026 | xfadevalue = 1; // start crossfade | ||
| 1027 | xfadelength = period - 1; | ||
| 1028 | xfadestep = xfadespeed / xfadelength; | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | readindex = refindex - readlag; | ||
| 1033 | outputsample = read_sample(w, readindex); | ||
| 1034 | |||
| 1035 | if(xfadevalue > 0) | ||
| 1036 | { | ||
| 1037 | outputsample *= (1 - xfadevalue); // fadein | ||
| 1038 | outputsample += read_sample(w, readindex - jump) * xfadevalue; // fadeout | ||
| 1039 | xfadevalue -= xfadestep; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | *out++ = outputsample; | ||
| 1043 | refindex += 1; | ||
| 1044 | readlag += readlagstep; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | w->jump = jump; // state variables | ||
| 1048 | w->readlag = readlag; | ||
| 1049 | w->xfadevalue = xfadevalue; | ||
| 1050 | w->xfadelength = xfadelength; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | |||
| 1054 | /* | ||
| 1055 | Function pitchup() for pitch factors above 1 is more complicated than | ||
| 1056 | pitchdown(). The read pointer increments faster than the write pointer and a | ||
| 1057 | backward jump must happen in time, reckoning with the crossfade region. The read | ||
| 1058 | pointer backward jump length is always one period. In order to minimize the area | ||
| 1059 | of signal duplicates, crossfade length is aimed at [period / pitchfactor]. | ||
| 1060 | This leads to a crossfade speed of [pitchfactor * pitchfactor]. | ||
| 1061 | |||
| 1062 | Some samples for the fade out (but not all of them) must already be in the | ||
| 1063 | buffer, otherwise we will run out of input samples before the crossfade is | ||
| 1064 | completed. The ratio of past samples and future samples for a crossfade of any | ||
| 1065 | length is as follows: | ||
| 1066 | |||
| 1067 | past samples: xfadelength * (1 - 1 / pitchfactor) | ||
| 1068 | future samples: xfadelength * (1 / pitchfactor) | ||
| 1069 | |||
| 1070 | For example in the case of pitch factor 1.5 this would be: | ||
| 1071 | |||
| 1072 | past samples: xfadelength * (1 - 1 / 1.5) = xfadelength * 1 / 3 | ||
| 1073 | future samples: xfadelength * (1 / 1.5) = xfadelength * 2 / 3 | ||
| 1074 | |||
| 1075 | In the case of pitch factor 4 this would be: | ||
| 1076 | |||
| 1077 | past samples: xfadelength * (1 - 1 / 4) = xfadelength * 3 / 4 | ||
| 1078 | future samples: xfadelength * (1 / 4) = xfadelength * 1 / 4 | ||
| 1079 | |||
| 1080 | The read pointer lag must therefore preserve a minimum dependent on pitch | ||
| 1081 | factor. The minimum is called 'limit' here: | ||
| 1082 | |||
| 1083 | limit = period * (pitchfactor - 1) / pitchfactor * pitchfactor | ||
| 1084 | |||
| 1085 | Components of this expression are combined to reuse them in operations, while | ||
| 1086 | (pitchfactor - 1) is changed to (pitchfactor - 0.99) to avoid numerical | ||
| 1087 | resolution issues for pitch factors slightly above 1: | ||
| 1088 | |||
| 1089 | xfadespeed = pitchfactor * pitchfactor | ||
| 1090 | limitfactor = (pitchfactor - 0.99) / xfadespeed | ||
| 1091 | limit = period * limitfactor | ||
| 1092 | |||
| 1093 | When read lag is smaller than this limit, the read pointer must preferably | ||
| 1094 | jump backward, unless a previous crossfade is not yet completed. Crossfades must | ||
| 1095 | preferably be completed, unless the read pointer lag becomes smaller than zero. | ||
| 1096 | With fluctuating period lengths and pitch factors, the readpointer lag limit may | ||
| 1097 | change from one input block to the next in such a way that the actual lag is | ||
| 1098 | suddenly much smaller than the limit, and the intended crossfade length can not | ||
| 1099 | be applied. Therefore the crossfade length is simply calculated from the | ||
| 1100 | available amount of samples for all cases, like so: | ||
| 1101 | |||
| 1102 | xfadelength = readlag / limitfactor | ||
| 1103 | |||
| 1104 | For most occurrences, this will amount to a crossfade length reduced to | ||
| 1105 | [period / pitchfactor] in the output for pitch factors above 1, while in some | ||
| 1106 | cases it will be considerably shorter. Fortunately, an incidental aberration of | ||
| 1107 | the intended crossfade length hardly ever creates an audible artifact. The | ||
| 1108 | reason to specify preferred crossfade length according to pitch factor is to | ||
| 1109 | minimize the impression of echoes without sacrificing too much of the signal | ||
| 1110 | content. The readpointer jump length remains one period in any case. | ||
| 1111 | |||
| 1112 | Sometimes, the input signal periodicity may decrease substantially between one | ||
| 1113 | signal block and the next. In such cases it may be possible for the read pointer | ||
| 1114 | to jump forward and reduce latency. For every signal block, a check on this | ||
| 1115 | possibility is done. A previous crossfade must be completed before a forward | ||
| 1116 | jump is allowed. | ||
| 1117 | */ | ||
| 1118 | static void pitchup(tSOLAD* const w, float *out) | ||
| 1119 | { | ||
| 1120 | int n = w->blocksize; | ||
| 1121 | float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values | ||
| 1122 | float pitchfactor = w->pitchfactor; | ||
| 1123 | float period = w->period; | ||
| 1124 | float readlag = w->readlag; | ||
| 1125 | float jump = w->jump; | ||
| 1126 | float xfadevalue = w->xfadevalue; | ||
| 1127 | float xfadelength = w->xfadelength; | ||
| 1128 | |||
| 1129 | float readlagstep = pitchfactor - 1; | ||
| 1130 | float xfadespeed = pitchfactor * pitchfactor; | ||
| 1131 | float xfadestep = xfadespeed / xfadelength; | ||
| 1132 | float limitfactor = (pitchfactor - (float)0.99) / xfadespeed; | ||
| 1133 | float limit = period * limitfactor; | ||
| 1134 | float readindex, outputsample; | ||
| 1135 | |||
| 1136 | if((readlag > (period + 2 * limit)) & (xfadevalue < 0)) | ||
| 1137 | { | ||
| 1138 | jump = period; // jump forward | ||
| 1139 | while((jump * 2) < (readlag - 2 * limit)) jump *= 2; // use available space | ||
| 1140 | readlag -= jump; // reduce read pointer lag | ||
| 1141 | xfadevalue = 1; // start crossfade | ||
| 1142 | xfadelength = period - 1; | ||
| 1143 | xfadestep = xfadespeed / xfadelength; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | while(n--) | ||
| 1147 | { | ||
| 1148 | if(readlag < limit) // check if read pointer should jump backward... | ||
| 1149 | { | ||
| 1150 | if((xfadevalue < 0) | (readlag < 0)) // ...but try not to interrupt crossfade | ||
| 1151 | { | ||
| 1152 | xfadelength = readlag / limitfactor; | ||
| 1153 | if(xfadelength < 1) xfadelength = 1; | ||
| 1154 | xfadestep = xfadespeed / xfadelength; | ||
| 1155 | |||
| 1156 | jump = -period; // jump backward | ||
| 1157 | readlag += period; // increase read pointer lag | ||
| 1158 | xfadevalue = 1; // start crossfade | ||
| 1159 | } | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | readindex = refindex - readlag; | ||
| 1163 | outputsample = read_sample(w, readindex); | ||
| 1164 | |||
| 1165 | if(xfadevalue > 0) | ||
| 1166 | { | ||
| 1167 | outputsample *= (1 - xfadevalue); | ||
| 1168 | outputsample += read_sample(w, readindex - jump) * xfadevalue; | ||
| 1169 | xfadevalue -= xfadestep; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | *out++ = outputsample; | ||
| 1173 | refindex += 1; | ||
| 1174 | readlag -= readlagstep; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | w->readlag = readlag; // state variables | ||
| 1178 | w->jump = jump; | ||
| 1179 | w->xfadelength = xfadelength; | ||
| 1180 | w->xfadevalue = xfadevalue; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | // read one sample from delay buffer, with linear interpolation | ||
| 1184 | static inline float read_sample(tSOLAD* const w, float floatindex) | ||
| 1185 | { | ||
| 1186 | int index = (int)floatindex; | ||
| 1187 | float fraction = floatindex - (float)index; | ||
| 1188 | float *buf = w->delaybuf; | ||
| 1189 | index &= LOOPMASK; | ||
| 1190 | |||
| 1191 | return (buf[index] + (fraction * (buf[index+1] - buf[index]))); | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | static void solad_init(tSOLAD* const w) | ||
| 1195 | { | ||
| 1196 | w->timeindex = 0; | ||
| 1197 | w->xfadevalue = -1; | ||
| 1198 | w->period = INITPERIOD; | ||
| 1199 | w->readlag = INITPERIOD; | ||
| 1200 | w->blocksize = INITPERIOD; | ||
| 1201 | } | ||
| 1202 | //============================================================================================================ | ||
| 1203 | // FORMANTSHIFTER | ||
| 1204 | //============================================================================================================ | ||
| 1205 | |||
| 1206 | void tFormantShifter_init(tFormantShifter* const fs, int bufsize, int order) | ||
| 1207 | { | ||
| 1208 | fs->ford = order; | ||
| 1209 | fs->bufsize = bufsize; | ||
| 1210 | fs->fk = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1211 | fs->fb = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1212 | fs->fc = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1213 | fs->frb = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1214 | fs->frc = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1215 | fs->fsig = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1216 | fs->fsmooth = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1217 | fs->ftvec = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 1218 | |||
| 1219 | fs->fbuff = (float**) leaf_alloc(sizeof(float*) * fs->ford); | ||
| 1220 | for (int i = 0; i < fs->ford; i++) | ||
| 1221 | { | ||
| 1222 | fs->fbuff[i] = (float*) leaf_alloc(sizeof(float) * fs->bufsize); | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | |||
| 1226 | fs->falph = powf(0.001f, 80.0f / (leaf.sampleRate)); | ||
| 1227 | fs->flamb = -(0.8517f*sqrt(atanf(0.06583f*leaf.sampleRate))-0.1916f); | ||
| 1228 | fs->fhp = 0.0f; | ||
| 1229 | fs->flp = 0.0f; | ||
| 1230 | fs->flpa = powf(0.001f, 10.0f / (leaf.sampleRate)); | ||
| 1231 | fs->fmute = 1.0f; | ||
| 1232 | fs->fmutealph = powf(0.001f, 1.0f / (leaf.sampleRate)); | ||
| 1233 | fs->cbi = 0; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | void tFormantShifter_free(tFormantShifter* const fs) | ||
| 1237 | { | ||
| 1238 | leaf_free(fs->fk); | ||
| 1239 | leaf_free(fs->fb); | ||
| 1240 | leaf_free(fs->fc); | ||
| 1241 | leaf_free(fs->frb); | ||
| 1242 | leaf_free(fs->frc); | ||
| 1243 | leaf_free(fs->fsig); | ||
| 1244 | leaf_free(fs->fsmooth); | ||
| 1245 | leaf_free(fs->ftvec); | ||
| 1246 | for (int i = 0; i < fs->ford; i++) | ||
| 1247 | { | ||
| 1248 | leaf_free(fs->fbuff[i]); | ||
| 1249 | } | ||
| 1250 | leaf_free(fs->fbuff); | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | |||
| 1254 | float tFormantShifter_tick(tFormantShifter* fs, float in, float fwarp) | ||
| 1255 | { | ||
| 1256 | return tFormantShifter_add(fs, tFormantShifter_remove(fs, in), fwarp); | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | float tFormantShifter_remove(tFormantShifter* fs, float in) | ||
| 1260 | { | ||
| 1261 | float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, fk; | ||
| 1262 | int ti4; | ||
| 1263 | ford = fs->ford; | ||
| 1264 | falph = fs->falph; | ||
| 1265 | foma = (1.0f - falph); | ||
| 1266 | flpa = fs->flpa; | ||
| 1267 | flamb = fs->flamb; | ||
| 1268 | |||
| 1269 | tf = in; | ||
| 1270 | ti4 = fs->cbi; | ||
| 1271 | |||
| 1272 | fa = tf - fs->fhp; | ||
| 1273 | fs->fhp = tf; | ||
| 1274 | fb = fa; | ||
| 1275 | for(int i = 0; i < ford; i++) | ||
| 1276 | { | ||
| 1277 | fs->fsig[i] = fa*fa*foma + fs->fsig[i]*falph; | ||
| 1278 | fc = (fb - fs->fc[i])*flamb + fs->fb[i]; | ||
| 1279 | fs->fc[i] = fc; | ||
| 1280 | fs->fb[i] = fb; | ||
| 1281 | fk = fa*fc*foma + fs->fk[i]*falph; | ||
| 1282 | fs->fk[i] = fk; | ||
| 1283 | tf = fk/(fs->fsig[i] + 0.000001f); | ||
| 1284 | tf = tf*foma + fs->fsmooth[i]*falph; | ||
| 1285 | fs->fsmooth[i] = tf; | ||
| 1286 | fs->fbuff[i][ti4] = tf; | ||
| 1287 | fb = fc - tf*fa; | ||
| 1288 | fa = fa - tf*fc; | ||
| 1289 | } | ||
| 1290 | fs->cbi++; | ||
| 1291 | if(fs->cbi >= fs->bufsize) | ||
| 1292 | { | ||
| 1293 | fs->cbi = 0; | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | return fa; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | float tFormantShifter_add(tFormantShifter* fs, float in, float fwarp) | ||
| 1300 | { | ||
| 1301 | float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, tf2, f0resp, f1resp, frlamb; | ||
| 1302 | int ti4; | ||
| 1303 | ford = fs->ford; | ||
| 1304 | falph = fs->falph; | ||
| 1305 | foma = (1.0f - falph); | ||
| 1306 | flpa = fs->flpa; | ||
| 1307 | flamb = fs->flamb; | ||
| 1308 | tf = exp2(fwarp/2.0f) * (1+flamb)/(1-flamb); | ||
| 1309 | frlamb = (tf-1)/(tf+1); | ||
| 1310 | ti4 = fs->cbi; | ||
| 1311 | |||
| 1312 | tf2 = in; | ||
| 1313 | fa = 0; | ||
| 1314 | fb = fa; | ||
| 1315 | for (int i=0; i<ford; i++) | ||
| 1316 | { | ||
| 1317 | fc = (fb-fs->frc[i])*frlamb + fs->frb[i]; | ||
| 1318 | tf = fs->fbuff[i][ti4]; | ||
| 1319 | fb = fc - tf*fa; | ||
| 1320 | fs->ftvec[i] = tf*fc; | ||
| 1321 | fa = fa - fs->ftvec[i]; | ||
| 1322 | } | ||
| 1323 | tf = -fa; | ||
| 1324 | for (int i=ford-1; i>=0; i--) | ||
| 1325 | { | ||
| 1326 | tf = tf + fs->ftvec[i]; | ||
| 1327 | } | ||
| 1328 | f0resp = tf; | ||
| 1329 | |||
| 1330 | // second time: compute 1-response | ||
| 1331 | fa = 1; | ||
| 1332 | fb = fa; | ||
| 1333 | for (int i=0; i<ford; i++) | ||
| 1334 | { | ||
| 1335 | fc = (fb-fs->frc[i])*frlamb + fs->frb[i]; | ||
| 1336 | tf = fs->fbuff[i][ti4]; | ||
| 1337 | fb = fc - tf*fa; | ||
| 1338 | fs->ftvec[i] = tf*fc; | ||
| 1339 | fa = fa - fs->ftvec[i]; | ||
| 1340 | } | ||
| 1341 | tf = -fa; | ||
| 1342 | for (int i=ford-1; i>=0; i--) | ||
| 1343 | { | ||
| 1344 | tf = tf + fs->ftvec[i]; | ||
| 1345 | } | ||
| 1346 | f1resp = tf; | ||
| 1347 | |||
| 1348 | // now solve equations for output, based on 0-response and 1-response | ||
| 1349 | tf = (float)2*tf2; | ||
| 1350 | tf2 = tf; | ||
| 1351 | tf = ((float)1 - f1resp + f0resp); | ||
| 1352 | if (tf!=0) | ||
| 1353 | { | ||
| 1354 | tf2 = (tf2 + f0resp) / tf; | ||
| 1355 | } | ||
| 1356 | else | ||
| 1357 | { | ||
| 1358 | tf2 = 0; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | // third time: update delay registers | ||
| 1362 | fa = tf2; | ||
| 1363 | fb = fa; | ||
| 1364 | for (int i=0; i<ford; i++) | ||
| 1365 | { | ||
| 1366 | fc = (fb-fs->frc[i])*frlamb + fs->frb[i]; | ||
| 1367 | fs->frc[i] = fc; | ||
| 1368 | fs->frb[i] = fb; | ||
| 1369 | tf = fs->fbuff[i][ti4]; | ||
| 1370 | fb = fc - tf*fa; | ||
| 1371 | fa = fa - tf*fc; | ||
| 1372 | } | ||
| 1373 | tf = tf2; | ||
| 1374 | tf = tf + flpa * fs->flp; // lowpass post-emphasis filter | ||
| 1375 | fs->flp = tf; | ||
| 1376 | |||
| 1377 | // Bring up the gain slowly when formant correction goes from disabled | ||
| 1378 | // to enabled, while things stabilize. | ||
| 1379 | if (fs->fmute>0.5) | ||
| 1380 | { | ||
| 1381 | tf = tf*(fs->fmute - 0.5)*2; | ||
| 1382 | } | ||
| 1383 | else | ||
| 1384 | { | ||
| 1385 | tf = 0; | ||
| 1386 | } | ||
| 1387 | tf2 = fs->fmutealph; | ||
| 1388 | fs->fmute = (1-tf2) + tf2*fs->fmute; | ||
| 1389 | // now tf is signal output | ||
| 1390 | // ...and we're done messing with formants | ||
| 1391 | |||
| 1392 | return tf; | ||
| 1393 | } | ||
| @@ -1,12 +1,23 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * leaf-WDF.c | 2 | * leaf-electrical.c |
| 3 | * | 3 | * |
| 4 | * Created on: Sep 25, 2019 | 4 | * Created on: Sep 25, 2019 |
| 5 | * Author: jeffsnyder | 5 | * Author: jeffsnyder |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #if _WIN32 || _WIN64 | ||
| 8 | 9 | ||
| 9 | #include "../Inc/leaf-WDF.h" | 10 | #include "..\Inc\leaf-electrical.h" |
| 11 | #include "..\leaf.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include "../Inc/leaf-electrical.h" | ||
| 16 | #include "../leaf.h" | ||
| 17 | |||
| 18 | #endif | ||
| 19 | |||
| 20 | //============================================================================== | ||
| 10 | 21 | ||
| 11 | static float get_port_resistance_for_resistor(tWDF* const r); | 22 | static float get_port_resistance_for_resistor(tWDF* const r); |
| 12 | static float get_port_resistance_for_capacitor(tWDF* const r); | 23 | static float get_port_resistance_for_capacitor(tWDF* const r); |
| @@ -0,0 +1,629 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | leaf-envelopes.c | ||
| 5 | Created: 20 Jan 2017 12:02:17pm | ||
| 6 | Author: Michael R Mulshine | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | |||
| 12 | #if _WIN32 || _WIN64 | ||
| 13 | |||
| 14 | #include "..\Inc\leaf-envelopes.h" | ||
| 15 | #include "..\Inc\leaf-tables.h" | ||
| 16 | #include "..\leaf.h" | ||
| 17 | |||
| 18 | #else | ||
| 19 | |||
| 20 | #include "../Inc/leaf-envelopes.h" | ||
| 21 | #include "../Inc/leaf-tables.h" | ||
| 22 | #include "../leaf.h" | ||
| 23 | |||
| 24 | #endif | ||
| 25 | |||
| 26 | #define LOGTEN 2.302585092994 | ||
| 27 | |||
| 28 | float mtof(float f) | ||
| 29 | { | ||
| 30 | if (f <= -1500.0f) return(0); | ||
| 31 | else if (f > 1499.0f) return(mtof(1499.0f)); | ||
| 32 | else return (8.17579891564f * expf(0.0577622650f * f)); | ||
| 33 | } | ||
| 34 | |||
| 35 | float ftom(float f) | ||
| 36 | { | ||
| 37 | return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f); | ||
| 38 | } | ||
| 39 | |||
| 40 | float powtodb(float f) | ||
| 41 | { | ||
| 42 | if (f <= 0) return (0); | ||
| 43 | else | ||
| 44 | { | ||
| 45 | float val = 100 + 10.f/LOGTEN * logf(f); | ||
| 46 | return (val < 0 ? 0 : val); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | float rmstodb(float f) | ||
| 51 | { | ||
| 52 | if (f <= 0) return (0); | ||
| 53 | else | ||
| 54 | { | ||
| 55 | float val = 100 + 20.f/LOGTEN * log(f); | ||
| 56 | return (val < 0 ? 0 : val); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | float dbtopow(float f) | ||
| 61 | { | ||
| 62 | if (f <= 0) | ||
| 63 | return(0); | ||
| 64 | else | ||
| 65 | { | ||
| 66 | if (f > 870.0f) | ||
| 67 | f = 870.0f; | ||
| 68 | return (expf((LOGTEN * 0.1f) * (f-100.0f))); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | float dbtorms(float f) | ||
| 73 | { | ||
| 74 | if (f <= 0) | ||
| 75 | return(0); | ||
| 76 | else | ||
| 77 | { | ||
| 78 | if (f > 485.0f) | ||
| 79 | f = 485.0f; | ||
| 80 | } | ||
| 81 | return (expf((LOGTEN * 0.05f) * (f-100.0f))); | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 85 | |||
| 86 | |||
| 87 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Envelope ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | ||
| 88 | void tEnvelope_init(tEnvelope* const env, float attack, float decay, oBool loop) | ||
| 89 | { | ||
| 90 | env->exp_buff = exp_decay; | ||
| 91 | env->inc_buff = attack_decay_inc; | ||
| 92 | env->buff_size = sizeof(exp_decay); | ||
| 93 | |||
| 94 | env->loop = loop; | ||
| 95 | |||
| 96 | if (attack > 8192.0f) | ||
| 97 | attack = 8192.0f; | ||
| 98 | if (attack < 0.0f) | ||
| 99 | attack = 0.0f; | ||
| 100 | |||
| 101 | if (decay > 8192.0f) | ||
| 102 | decay = 8192.0f; | ||
| 103 | if (decay < 0.0f) | ||
| 104 | decay = 0.0f; | ||
| 105 | |||
| 106 | int16_t attackIndex = ((int16_t)(attack * 8.0f))-1; | ||
| 107 | int16_t decayIndex = ((int16_t)(decay * 8.0f))-1; | ||
| 108 | int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1; | ||
| 109 | |||
| 110 | if (attackIndex < 0) | ||
| 111 | attackIndex = 0; | ||
| 112 | if (decayIndex < 0) | ||
| 113 | decayIndex = 0; | ||
| 114 | if (rampIndex < 0) | ||
| 115 | rampIndex = 0; | ||
| 116 | |||
| 117 | env->inRamp = OFALSE; | ||
| 118 | env->inAttack = OFALSE; | ||
| 119 | env->inDecay = OFALSE; | ||
| 120 | |||
| 121 | env->attackInc = env->inc_buff[attackIndex]; | ||
| 122 | env->decayInc = env->inc_buff[decayIndex]; | ||
| 123 | env->rampInc = env->inc_buff[rampIndex]; | ||
| 124 | |||
| 125 | } | ||
| 126 | |||
| 127 | void tEnvelope_free(tEnvelope* const env) | ||
| 128 | { | ||
| 129 | |||
| 130 | } | ||
| 131 | |||
| 132 | int tEnvelope_setAttack(tEnvelope* const env, float attack) | ||
| 133 | { | ||
| 134 | int32_t attackIndex; | ||
| 135 | |||
| 136 | if (attack < 0.0f) { | ||
| 137 | attackIndex = 0.0f; | ||
| 138 | } else if (attack < 8192.0f) { | ||
| 139 | attackIndex = ((int32_t)(attack * 8.0f))-1; | ||
| 140 | } else { | ||
| 141 | attackIndex = ((int32_t)(8192.0f * 8.0f))-1; | ||
| 142 | } | ||
| 143 | |||
| 144 | env->attackInc = env->inc_buff[attackIndex]; | ||
| 145 | |||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | int tEnvelope_setDecay(tEnvelope* const env, float decay) | ||
| 150 | { | ||
| 151 | int32_t decayIndex; | ||
| 152 | |||
| 153 | if (decay < 0.0f) { | ||
| 154 | decayIndex = 0.0f; | ||
| 155 | } else if (decay < 8192.0f) { | ||
| 156 | decayIndex = ((int32_t)(decay * 8.0f)) - 1; | ||
| 157 | } else { | ||
| 158 | decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1; | ||
| 159 | } | ||
| 160 | |||
| 161 | env->decayInc = env->inc_buff[decayIndex]; | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | int tEnvelope_loop(tEnvelope* const env, oBool loop) | ||
| 167 | { | ||
| 168 | env->loop = loop; | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | |||
| 174 | int tEnvelope_on(tEnvelope* const env, float velocity) | ||
| 175 | { | ||
| 176 | if (env->inAttack || env->inDecay) // In case envelope retriggered while it is still happening. | ||
| 177 | { | ||
| 178 | env->rampPhase = 0; | ||
| 179 | env->inRamp = OTRUE; | ||
| 180 | env->rampPeak = env->next; | ||
| 181 | } | ||
| 182 | else // Normal start. | ||
| 183 | { | ||
| 184 | env->inAttack = OTRUE; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 188 | env->attackPhase = 0; | ||
| 189 | env->decayPhase = 0; | ||
| 190 | env->inDecay = OFALSE; | ||
| 191 | env->gain = velocity; | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | float tEnvelope_tick(tEnvelope* const env) | ||
| 197 | { | ||
| 198 | if (env->inRamp) | ||
| 199 | { | ||
| 200 | if (env->rampPhase > UINT16_MAX) | ||
| 201 | { | ||
| 202 | env->inRamp = OFALSE; | ||
| 203 | env->inAttack = OTRUE; | ||
| 204 | env->next = 0.0f; | ||
| 205 | } | ||
| 206 | else | ||
| 207 | { | ||
| 208 | env->next = env->rampPeak * env->exp_buff[(uint32_t)env->rampPhase]; | ||
| 209 | } | ||
| 210 | |||
| 211 | env->rampPhase += env->rampInc; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (env->inAttack) | ||
| 215 | { | ||
| 216 | |||
| 217 | // If attack done, time to turn around. | ||
| 218 | if (env->attackPhase > UINT16_MAX) | ||
| 219 | { | ||
| 220 | env->inDecay = OTRUE; | ||
| 221 | env->inAttack = OFALSE; | ||
| 222 | env->next = env->gain * 1.0f; | ||
| 223 | } | ||
| 224 | else | ||
| 225 | { | ||
| 226 | // do interpolation ! | ||
| 227 | env->next = env->gain * env->exp_buff[UINT16_MAX - (uint32_t)env->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception | ||
| 228 | } | ||
| 229 | |||
| 230 | // Increment envelope attack. | ||
| 231 | env->attackPhase += env->attackInc; | ||
| 232 | |||
| 233 | } | ||
| 234 | |||
| 235 | if (env->inDecay) | ||
| 236 | { | ||
| 237 | |||
| 238 | // If decay done, finish. | ||
| 239 | if (env->decayPhase >= UINT16_MAX) | ||
| 240 | { | ||
| 241 | env->inDecay = OFALSE; | ||
| 242 | |||
| 243 | if (env->loop) | ||
| 244 | { | ||
| 245 | env->attackPhase = 0; | ||
| 246 | env->decayPhase = 0; | ||
| 247 | env->inAttack = OTRUE; | ||
| 248 | } | ||
| 249 | else | ||
| 250 | { | ||
| 251 | env->next = 0.0f; | ||
| 252 | } | ||
| 253 | |||
| 254 | } else { | ||
| 255 | |||
| 256 | env->next = env->gain * (env->exp_buff[(uint32_t)env->decayPhase]); // do interpolation ! | ||
| 257 | } | ||
| 258 | |||
| 259 | // Increment envelope decay; | ||
| 260 | env->decayPhase += env->decayInc; | ||
| 261 | } | ||
| 262 | |||
| 263 | return env->next; | ||
| 264 | } | ||
| 265 | |||
| 266 | /* ADSR */ | ||
| 267 | void tADSR_init(tADSR* const adsr, float attack, float decay, float sustain, float release) | ||
| 268 | { | ||
| 269 | adsr->exp_buff = exp_decay; | ||
| 270 | adsr->inc_buff = attack_decay_inc; | ||
| 271 | adsr->buff_size = sizeof(exp_decay); | ||
| 272 | |||
| 273 | if (attack > 8192.0f) | ||
| 274 | attack = 8192.0f; | ||
| 275 | if (attack < 0.0f) | ||
| 276 | attack = 0.0f; | ||
| 277 | |||
| 278 | if (decay > 8192.0f) | ||
| 279 | decay = 8192.0f; | ||
| 280 | if (decay < 0.0f) | ||
| 281 | decay = 0.0f; | ||
| 282 | |||
| 283 | if (sustain > 1.0f) | ||
| 284 | sustain = 1.0f; | ||
| 285 | if (sustain < 0.0f) | ||
| 286 | sustain = 0.0f; | ||
| 287 | |||
| 288 | if (release > 8192.0f) | ||
| 289 | release = 8192.0f; | ||
| 290 | if (release < 0.0f) | ||
| 291 | release = 0.0f; | ||
| 292 | |||
| 293 | int16_t attackIndex = ((int16_t)(attack * 8.0f))-1; | ||
| 294 | int16_t decayIndex = ((int16_t)(decay * 8.0f))-1; | ||
| 295 | int16_t releaseIndex = ((int16_t)(release * 8.0f))-1; | ||
| 296 | int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1; | ||
| 297 | |||
| 298 | if (attackIndex < 0) | ||
| 299 | attackIndex = 0; | ||
| 300 | if (decayIndex < 0) | ||
| 301 | decayIndex = 0; | ||
| 302 | if (releaseIndex < 0) | ||
| 303 | releaseIndex = 0; | ||
| 304 | if (rampIndex < 0) | ||
| 305 | rampIndex = 0; | ||
| 306 | |||
| 307 | adsr->inRamp = OFALSE; | ||
| 308 | adsr->inAttack = OFALSE; | ||
| 309 | adsr->inDecay = OFALSE; | ||
| 310 | adsr->inSustain = OFALSE; | ||
| 311 | adsr->inRelease = OFALSE; | ||
| 312 | |||
| 313 | adsr->sustain = sustain; | ||
| 314 | |||
| 315 | adsr->attackInc = adsr->inc_buff[attackIndex]; | ||
| 316 | adsr->decayInc = adsr->inc_buff[decayIndex]; | ||
| 317 | adsr->releaseInc = adsr->inc_buff[releaseIndex]; | ||
| 318 | adsr->rampInc = adsr->inc_buff[rampIndex]; | ||
| 319 | } | ||
| 320 | |||
| 321 | void tADSR_free(tADSR* const adsr) | ||
| 322 | { | ||
| 323 | |||
| 324 | } | ||
| 325 | |||
| 326 | int tADSR_setAttack(tADSR* const adsr, float attack) | ||
| 327 | { | ||
| 328 | int32_t attackIndex; | ||
| 329 | |||
| 330 | if (attack < 0.0f) { | ||
| 331 | attackIndex = 0.0f; | ||
| 332 | } else if (attack < 8192.0f) { | ||
| 333 | attackIndex = ((int32_t)(attack * 8.0f))-1; | ||
| 334 | } else { | ||
| 335 | attackIndex = ((int32_t)(8192.0f * 8.0f))-1; | ||
| 336 | } | ||
| 337 | |||
| 338 | adsr->attackInc = adsr->inc_buff[attackIndex]; | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | int tADSR_detDecay(tADSR* const adsr, float decay) | ||
| 344 | { | ||
| 345 | int32_t decayIndex; | ||
| 346 | |||
| 347 | if (decay < 0.0f) { | ||
| 348 | decayIndex = 0.0f; | ||
| 349 | } else if (decay < 8192.0f) { | ||
| 350 | decayIndex = ((int32_t)(decay * 8.0f)) - 1; | ||
| 351 | } else { | ||
| 352 | decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1; | ||
| 353 | } | ||
| 354 | |||
| 355 | adsr->decayInc = adsr->inc_buff[decayIndex]; | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | int tADSR_setSustain(tADSR *const adsr, float sustain) | ||
| 361 | { | ||
| 362 | if (sustain > 1.0f) adsr->sustain = 1.0f; | ||
| 363 | else if (sustain < 0.0f) adsr->sustain = 0.0f; | ||
| 364 | else adsr->sustain = sustain; | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | int tADSR_setRelease(tADSR* const adsr, float release) | ||
| 370 | { | ||
| 371 | int32_t releaseIndex; | ||
| 372 | |||
| 373 | if (release < 0.0f) { | ||
| 374 | releaseIndex = 0.0f; | ||
| 375 | } else if (release < 8192.0f) { | ||
| 376 | releaseIndex = ((int32_t)(release * 8.0f)) - 1; | ||
| 377 | } else { | ||
| 378 | releaseIndex = ((int32_t)(8192.0f * 8.0f)) - 1; | ||
| 379 | } | ||
| 380 | |||
| 381 | adsr->releaseInc = adsr->inc_buff[releaseIndex]; | ||
| 382 | |||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | int tADSR_on(tADSR* const adsr, float velocity) | ||
| 387 | { | ||
| 388 | if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening. | ||
| 389 | { | ||
| 390 | adsr->rampPhase = 0; | ||
| 391 | adsr->inRamp = OTRUE; | ||
| 392 | adsr->rampPeak = adsr->next; | ||
| 393 | } | ||
| 394 | else // Normal start. | ||
| 395 | { | ||
| 396 | adsr->inAttack = OTRUE; | ||
| 397 | } | ||
| 398 | |||
| 399 | adsr->attackPhase = 0; | ||
| 400 | adsr->decayPhase = 0; | ||
| 401 | adsr->releasePhase = 0; | ||
| 402 | adsr->inDecay = OFALSE; | ||
| 403 | adsr->inSustain = OFALSE; | ||
| 404 | adsr->inRelease = OFALSE; | ||
| 405 | adsr->gain = velocity; | ||
| 406 | |||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | int tADSR_off(tADSR* const adsr) | ||
| 411 | { | ||
| 412 | if (adsr->inRelease) return 0; | ||
| 413 | |||
| 414 | adsr->inAttack = OFALSE; | ||
| 415 | adsr->inDecay = OFALSE; | ||
| 416 | adsr->inSustain = OFALSE; | ||
| 417 | adsr->inRelease = OTRUE; | ||
| 418 | |||
| 419 | adsr->releasePeak = adsr->next; | ||
| 420 | |||
| 421 | return 0; | ||
| 422 | } | ||
| 423 | |||
| 424 | float tADSR_tick(tADSR* const adsr) | ||
| 425 | { | ||
| 426 | if (adsr->inRamp) | ||
| 427 | { | ||
| 428 | if (adsr->rampPhase > UINT16_MAX) | ||
| 429 | { | ||
| 430 | adsr->inRamp = OFALSE; | ||
| 431 | adsr->inAttack = OTRUE; | ||
| 432 | adsr->next = 0.0f; | ||
| 433 | } | ||
| 434 | else | ||
| 435 | { | ||
| 436 | adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase]; | ||
| 437 | } | ||
| 438 | |||
| 439 | adsr->rampPhase += adsr->rampInc; | ||
| 440 | } | ||
| 441 | |||
| 442 | if (adsr->inAttack) | ||
| 443 | { | ||
| 444 | |||
| 445 | // If attack done, time to turn around. | ||
| 446 | if (adsr->attackPhase > UINT16_MAX) | ||
| 447 | { | ||
| 448 | adsr->inDecay = OTRUE; | ||
| 449 | adsr->inAttack = OFALSE; | ||
| 450 | adsr->next = adsr->gain * 1.0f; | ||
| 451 | } | ||
| 452 | else | ||
| 453 | { | ||
| 454 | // do interpolation ! | ||
| 455 | adsr->next = adsr->gain * adsr->exp_buff[UINT16_MAX - (uint32_t)adsr->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception | ||
| 456 | } | ||
| 457 | |||
| 458 | // Increment ADSR attack. | ||
| 459 | adsr->attackPhase += adsr->attackInc; | ||
| 460 | |||
| 461 | } | ||
| 462 | |||
| 463 | if (adsr->inDecay) | ||
| 464 | { | ||
| 465 | |||
| 466 | // If decay done, sustain. | ||
| 467 | if (adsr->decayPhase >= UINT16_MAX) | ||
| 468 | { | ||
| 469 | adsr->inDecay = OFALSE; | ||
| 470 | adsr->inSustain = OTRUE; | ||
| 471 | adsr->next = adsr->gain * adsr->sustain; | ||
| 472 | } | ||
| 473 | |||
| 474 | else | ||
| 475 | { | ||
| 476 | adsr->next = adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)adsr->decayPhase]) * (1 - adsr->sustain))); // do interpolation ! | ||
| 477 | } | ||
| 478 | |||
| 479 | // Increment ADSR decay. | ||
| 480 | adsr->decayPhase += adsr->decayInc; | ||
| 481 | } | ||
| 482 | |||
| 483 | if (adsr->inRelease) | ||
| 484 | { | ||
| 485 | // If release done, finish. | ||
| 486 | if (adsr->releasePhase >= UINT16_MAX) | ||
| 487 | { | ||
| 488 | adsr->inRelease = OFALSE; | ||
| 489 | adsr->next = 0.0f; | ||
| 490 | } | ||
| 491 | else { | ||
| 492 | |||
| 493 | adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)adsr->releasePhase]); // do interpolation ! | ||
| 494 | } | ||
| 495 | |||
| 496 | // Increment envelope release; | ||
| 497 | adsr->releasePhase += adsr->releaseInc; | ||
| 498 | } | ||
| 499 | |||
| 500 | return adsr->next; | ||
| 501 | } | ||
| 502 | |||
| 503 | /* Ramp */ | ||
| 504 | void tRamp_init(tRamp* const ramp, float time, int samples_per_tick) | ||
| 505 | { | ||
| 506 | ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f); | ||
| 507 | ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick; | ||
| 508 | ramp->curr = 0.0f; | ||
| 509 | ramp->dest = 0.0f; | ||
| 510 | |||
| 511 | if (time < ramp->minimum_time) | ||
| 512 | { | ||
| 513 | ramp->time = ramp->minimum_time; | ||
| 514 | } | ||
| 515 | else | ||
| 516 | { | ||
| 517 | ramp->time = time; | ||
| 518 | } | ||
| 519 | |||
| 520 | ramp->samples_per_tick = samples_per_tick; | ||
| 521 | ramp->inc = ((ramp->dest - ramp->curr) / ramp->time * ramp->inv_sr_ms) * (float)ramp->samples_per_tick; | ||
| 522 | } | ||
| 523 | |||
| 524 | void tRamp_free(tRamp* const ramp) | ||
| 525 | { | ||
| 526 | |||
| 527 | } | ||
| 528 | |||
| 529 | int tRamp_setTime(tRamp* const r, float time) | ||
| 530 | { | ||
| 531 | if (time < r->minimum_time) | ||
| 532 | { | ||
| 533 | r->time = r->minimum_time; | ||
| 534 | } | ||
| 535 | else | ||
| 536 | { | ||
| 537 | r->time = time; | ||
| 538 | } | ||
| 539 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick); | ||
| 540 | return 0; | ||
| 541 | } | ||
| 542 | |||
| 543 | int tRamp_setDest(tRamp* const r, float dest) | ||
| 544 | { | ||
| 545 | r->dest = dest; | ||
| 546 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick); | ||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | int tRamp_setVal(tRamp* const r, float val) | ||
| 551 | { | ||
| 552 | r->curr = val; | ||
| 553 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick); | ||
| 554 | return 0; | ||
| 555 | } | ||
| 556 | |||
| 557 | float tRamp_tick(tRamp* const r) { | ||
| 558 | |||
| 559 | r->curr += r->inc; | ||
| 560 | |||
| 561 | if (((r->curr >= r->dest) && (r->inc > 0.0f)) || ((r->curr <= r->dest) && (r->inc < 0.0f))) r->inc = 0.0f; | ||
| 562 | // Palle: There is a slight risk that you overshoot here and stay on dest+inc, which with a large inc value could be a real problem | ||
| 563 | // I suggest you add: r->curr=r->dest in the true if case | ||
| 564 | |||
| 565 | return r->curr; | ||
| 566 | } | ||
| 567 | |||
| 568 | float tRamp_sample(tRamp* const r) { | ||
| 569 | |||
| 570 | return r->curr; | ||
| 571 | } | ||
| 572 | |||
| 573 | void tRampSampleRateChanged(tRamp* const r) | ||
| 574 | { | ||
| 575 | r->inv_sr_ms = 1.0f / (leaf.sampleRate * 0.001f); | ||
| 576 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms)*((float)r->samples_per_tick); | ||
| 577 | } | ||
| 578 | |||
| 579 | |||
| 580 | /* Exponential Smoother */ | ||
| 581 | void tExpSmooth_init(tExpSmooth* const smooth, float val, float factor) | ||
| 582 | { // factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms | ||
| 583 | smooth->curr=val; | ||
| 584 | smooth->dest=val; | ||
| 585 | if (factor<0) factor=0; | ||
| 586 | if (factor>1) factor=1; | ||
| 587 | smooth->factor=factor; | ||
| 588 | smooth->oneminusfactor=1.0f-factor; | ||
| 589 | } | ||
| 590 | |||
| 591 | void tExpSmooth_free(tExpSmooth* const smooth) | ||
| 592 | { | ||
| 593 | |||
| 594 | } | ||
| 595 | |||
| 596 | int tExpSmooth_setFactor(tExpSmooth* const smooth, float factor) | ||
| 597 | { // factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms | ||
| 598 | if (factor<0) | ||
| 599 | factor=0; | ||
| 600 | else | ||
| 601 | if (factor>1) factor=1; | ||
| 602 | smooth->factor=factor; | ||
| 603 | smooth->oneminusfactor=1.0f-factor; | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | int tExpSmooth_setDest(tExpSmooth* const smooth, float dest) | ||
| 608 | { | ||
| 609 | smooth->dest=dest; | ||
| 610 | return 0; | ||
| 611 | } | ||
| 612 | |||
| 613 | int tExpSmooth_setVal(tExpSmooth* const smooth, float val) | ||
| 614 | { | ||
| 615 | smooth->curr=val; | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | float tExpSmooth_tick(tExpSmooth* const smooth) | ||
| 620 | { | ||
| 621 | smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr; | ||
| 622 | return smooth->curr; | ||
| 623 | } | ||
| 624 | |||
| 625 | float tExpSmooth_sample(tExpSmooth* const smooth) | ||
| 626 | { | ||
| 627 | return smooth->curr; | ||
| 628 | } | ||
| 629 | |||
| @@ -8,13 +8,13 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #if _WIN32 || _WIN64 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | ||
| 11 | #include "..\Inc\leaf-filter.h" | 11 | #include "..\Inc\leaf-filters.h" |
| 12 | #include "..\Inc\leaf-tables.h" | 12 | #include "..\Inc\leaf-tables.h" |
| 13 | #include "..\leaf.h" | 13 | #include "..\leaf.h" |
| 14 | 14 | ||
| 15 | #else | 15 | #else |
| 16 | 16 | ||
| 17 | #include "../Inc/leaf-filter.h" | 17 | #include "../Inc/leaf-filters.h" |
| 18 | #include "../Inc/leaf-tables.h" | 18 | #include "../Inc/leaf-tables.h" |
| 19 | #include "../leaf.h" | 19 | #include "../leaf.h" |
| 20 | 20 | ||
| @@ -27,17 +27,17 @@ void tAllpass_init(tAllpass* const f, float initDelay, uint32_t maxDelay) · 6 unmodified lines | |||
| 27 | 27 | ||
| 28 | f->lastOut = 0.0f; | 28 | f->lastOut = 0.0f; |
| 29 | 29 | ||
| 30 | tDelayL_init(&f->delay, initDelay, maxDelay); | 30 | tLinearDelay_init(&f->delay, initDelay, maxDelay); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | void tAllpass_free(tAllpass* const f) | 33 | void tAllpass_free(tAllpass* const f) |
| 34 | { | 34 | { |
| 35 | tDelayL_free(&f->delay); | 35 | tLinearDelay_free(&f->delay); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | void tAllpass_setDelay(tAllpass* const f, float delay) | 38 | void tAllpass_setDelay(tAllpass* const f, float delay) |
| 39 | { | 39 | { |
| 40 | tDelayL_setDelay(&f->delay, delay); | 40 | tLinearDelay_setDelay(&f->delay, delay); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | void tAllpass_setGain(tAllpass* const f, float gain) | 43 | void tAllpass_setGain(tAllpass* const f, float gain) |
| @@ -49,7 +49,7 @@ float tAllpass_tick(tAllpass* const f, float input) · 5 unmodified lines | |||
| 49 | { | 49 | { |
| 50 | float s1 = (-f->gain) * f->lastOut + input; | 50 | float s1 = (-f->gain) * f->lastOut + input; |
| 51 | 51 | ||
| 52 | float s2 = tDelayL_tick(&f->delay, s1) + (f->gain) * input; | 52 | float s2 = tLinearDelay_tick(&f->delay, s1) + (f->gain) * input; |
| 53 | 53 | ||
| 54 | f->lastOut = s2; | 54 | f->lastOut = s2; |
| 55 | 55 | ||
| @@ -758,7 +758,7 @@ int tSVF_setQ(tSVF* const svf, float Q) · 702 unmodified lines | |||
| 758 | } | 758 | } |
| 759 | 759 | ||
| 760 | // Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable. | 760 | // Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable. |
| 761 | void tSVFE_init(tSVFE* const svf, SVFType type, uint16_t input, float Q) | 761 | void tEfficientSVF_init(tEfficientSVF* const svf, SVFType type, uint16_t input, float Q) |
| 762 | { | 762 | { |
| 763 | svf->type = type; | 763 | svf->type = type; |
| 764 | 764 | ||
| @@ -779,12 +779,12 @@ void tSVFE_init(tSVFE* const svf, SVFType type, uint16_t input, float Q) · 14 unmodified lines | |||
| 779 | svf->a3 = a3; | 779 | svf->a3 = a3; |
| 780 | } | 780 | } |
| 781 | 781 | ||
| 782 | void tSVFE_free(tSVFE* const svf) | 782 | void tEfficientSVF_free(tEfficientSVF* const svf) |
| 783 | { | 783 | { |
| 784 | 784 | ||
| 785 | } | 785 | } |
| 786 | 786 | ||
| 787 | float tSVFE_tick(tSVFE* const svf, float v0) | 787 | float tEfficientSVF_tick(tEfficientSVF* const svf, float v0) |
| 788 | { | 788 | { |
| 789 | float v1,v2,v3; | 789 | float v1,v2,v3; |
| 790 | v3 = v0 - svf->ic2eq; | 790 | v3 = v0 - svf->ic2eq; |
| @@ -802,7 +802,7 @@ float tSVFE_tick(tSVFE* const svf, float v0) · 11 unmodified lines | |||
| 802 | 802 | ||
| 803 | } | 803 | } |
| 804 | 804 | ||
| 805 | int tSVFE_setFreq(tSVFE* const svf, uint16_t input) | 805 | int tEfficientSVF_setFreq(tEfficientSVF* const svf, uint16_t input) |
| 806 | { | 806 | { |
| 807 | svf->g = filtertan[input]; | 807 | svf->g = filtertan[input]; |
| 808 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); | 808 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); |
| @@ -812,7 +812,7 @@ int tSVFE_setFreq(tSVFE* const svf, uint16_t input) · 3 unmodified lines | |||
| 812 | return 0; | 812 | return 0; |
| 813 | } | 813 | } |
| 814 | 814 | ||
| 815 | int tSVFE_setQ(tSVFE* const svf, float Q) | 815 | int tEfficientSVF_setQ(tEfficientSVF* const svf, float Q) |
| 816 | { | 816 | { |
| 817 | svf->k = 1.0f/Q; | 817 | svf->k = 1.0f/Q; |
| 818 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); | 818 | svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k)); |
| @@ -1,206 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-formant.c | ||
| 4 | Created: 30 Nov 2018 11:03:30am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-formant.h" | ||
| 12 | #else | ||
| 13 | |||
| 14 | #include "../Inc/leaf-formant.h" | ||
| 15 | |||
| 16 | #endif | ||
| 17 | |||
| 18 | |||
| 19 | void tFormantShifter_init(tFormantShifter* const fs, int bufsize, int order) | ||
| 20 | { | ||
| 21 | fs->ford = order; | ||
| 22 | fs->bufsize = bufsize; | ||
| 23 | fs->fk = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 24 | fs->fb = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 25 | fs->fc = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 26 | fs->frb = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 27 | fs->frc = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 28 | fs->fsig = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 29 | fs->fsmooth = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 30 | fs->ftvec = (float*) leaf_alloc(sizeof(float) * fs->ford); | ||
| 31 | |||
| 32 | fs->fbuff = (float**) leaf_alloc(sizeof(float*) * fs->ford); | ||
| 33 | for (int i = 0; i < fs->ford; i++) | ||
| 34 | { | ||
| 35 | fs->fbuff[i] = (float*) leaf_alloc(sizeof(float) * fs->bufsize); | ||
| 36 | } | ||
| 37 | |||
| 38 | |||
| 39 | fs->falph = powf(0.001f, 80.0f / (leaf.sampleRate)); | ||
| 40 | fs->flamb = -(0.8517f*sqrt(atanf(0.06583f*leaf.sampleRate))-0.1916f); | ||
| 41 | fs->fhp = 0.0f; | ||
| 42 | fs->flp = 0.0f; | ||
| 43 | fs->flpa = powf(0.001f, 10.0f / (leaf.sampleRate)); | ||
| 44 | fs->fmute = 1.0f; | ||
| 45 | fs->fmutealph = powf(0.001f, 1.0f / (leaf.sampleRate)); | ||
| 46 | fs->cbi = 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | void tFormantShifter_free(tFormantShifter* const fs) | ||
| 50 | { | ||
| 51 | leaf_free(fs->fk); | ||
| 52 | leaf_free(fs->fb); | ||
| 53 | leaf_free(fs->fc); | ||
| 54 | leaf_free(fs->frb); | ||
| 55 | leaf_free(fs->frc); | ||
| 56 | leaf_free(fs->fsig); | ||
| 57 | leaf_free(fs->fsmooth); | ||
| 58 | leaf_free(fs->ftvec); | ||
| 59 | for (int i = 0; i < fs->ford; i++) | ||
| 60 | { | ||
| 61 | leaf_free(fs->fbuff[i]); | ||
| 62 | } | ||
| 63 | leaf_free(fs->fbuff); | ||
| 64 | } | ||
| 65 | |||
| 66 | |||
| 67 | float tFormantShifter_tick(tFormantShifter* fs, float in, float fwarp) | ||
| 68 | { | ||
| 69 | return tFormantShifter_add(fs, tFormantShifter_remove(fs, in), fwarp); | ||
| 70 | } | ||
| 71 | |||
| 72 | float tFormantShifter_remove(tFormantShifter* fs, float in) | ||
| 73 | { | ||
| 74 | float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, fk; | ||
| 75 | int ti4; | ||
| 76 | ford = fs->ford; | ||
| 77 | falph = fs->falph; | ||
| 78 | foma = (1.0f - falph); | ||
| 79 | flpa = fs->flpa; | ||
| 80 | flamb = fs->flamb; | ||
| 81 | |||
| 82 | tf = in; | ||
| 83 | ti4 = fs->cbi; | ||
| 84 | |||
| 85 | fa = tf - fs->fhp; | ||
| 86 | fs->fhp = tf; | ||
| 87 | fb = fa; | ||
| 88 | for(int i = 0; i < ford; i++) | ||
| 89 | { | ||
| 90 | fs->fsig[i] = fa*fa*foma + fs->fsig[i]*falph; | ||
| 91 | fc = (fb - fs->fc[i])*flamb + fs->fb[i]; | ||
| 92 | fs->fc[i] = fc; | ||
| 93 | fs->fb[i] = fb; | ||
| 94 | fk = fa*fc*foma + fs->fk[i]*falph; | ||
| 95 | fs->fk[i] = fk; | ||
| 96 | tf = fk/(fs->fsig[i] + 0.000001f); | ||
| 97 | tf = tf*foma + fs->fsmooth[i]*falph; | ||
| 98 | fs->fsmooth[i] = tf; | ||
| 99 | fs->fbuff[i][ti4] = tf; | ||
| 100 | fb = fc - tf*fa; | ||
| 101 | fa = fa - tf*fc; | ||
| 102 | } | ||
| 103 | fs->cbi++; | ||
| 104 | if(fs->cbi >= fs->bufsize) | ||
| 105 | { | ||
| 106 | fs->cbi = 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | return fa; | ||
| 110 | } | ||
| 111 | |||
| 112 | float tFormantShifter_add(tFormantShifter* fs, float in, float fwarp) | ||
| 113 | { | ||
| 114 | float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, tf2, f0resp, f1resp, frlamb; | ||
| 115 | int ti4; | ||
| 116 | ford = fs->ford; | ||
| 117 | falph = fs->falph; | ||
| 118 | foma = (1.0f - falph); | ||
| 119 | flpa = fs->flpa; | ||
| 120 | flamb = fs->flamb; | ||
| 121 | tf = exp2(fwarp/2.0f) * (1+flamb)/(1-flamb); | ||
| 122 | frlamb = (tf-1)/(tf+1); | ||
| 123 | ti4 = fs->cbi; | ||
| 124 | |||
| 125 | tf2 = in; | ||
| 126 | fa = 0; | ||
| 127 | fb = fa; | ||
| 128 | for (int i=0; i<ford; i++) | ||
| 129 | { | ||
| 130 | fc = (fb-fs->frc[i])*frlamb + fs->frb[i]; | ||
| 131 | tf = fs->fbuff[i][ti4]; | ||
| 132 | fb = fc - tf*fa; | ||
| 133 | fs->ftvec[i] = tf*fc; | ||
| 134 | fa = fa - fs->ftvec[i]; | ||
| 135 | } | ||
| 136 | tf = -fa; | ||
| 137 | for (int i=ford-1; i>=0; i--) | ||
| 138 | { | ||
| 139 | tf = tf + fs->ftvec[i]; | ||
| 140 | } | ||
| 141 | f0resp = tf; | ||
| 142 | |||
| 143 | // second time: compute 1-response | ||
| 144 | fa = 1; | ||
| 145 | fb = fa; | ||
| 146 | for (int i=0; i<ford; i++) | ||
| 147 | { | ||
| 148 | fc = (fb-fs->frc[i])*frlamb + fs->frb[i]; | ||
| 149 | tf = fs->fbuff[i][ti4]; | ||
| 150 | fb = fc - tf*fa; | ||
| 151 | fs->ftvec[i] = tf*fc; | ||
| 152 | fa = fa - fs->ftvec[i]; | ||
| 153 | } | ||
| 154 | tf = -fa; | ||
| 155 | for (int i=ford-1; i>=0; i--) | ||
| 156 | { | ||
| 157 | tf = tf + fs->ftvec[i]; | ||
| 158 | } | ||
| 159 | f1resp = tf; | ||
| 160 | |||
| 161 | // now solve equations for output, based on 0-response and 1-response | ||
| 162 | tf = (float)2*tf2; | ||
| 163 | tf2 = tf; | ||
| 164 | tf = ((float)1 - f1resp + f0resp); | ||
| 165 | if (tf!=0) | ||
| 166 | { | ||
| 167 | tf2 = (tf2 + f0resp) / tf; | ||
| 168 | } | ||
| 169 | else | ||
| 170 | { | ||
| 171 | tf2 = 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | // third time: update delay registers | ||
| 175 | fa = tf2; | ||
| 176 | fb = fa; | ||
| 177 | for (int i=0; i<ford; i++) | ||
| 178 | { | ||
| 179 | fc = (fb-fs->frc[i])*frlamb + fs->frb[i]; | ||
| 180 | fs->frc[i] = fc; | ||
| 181 | fs->frb[i] = fb; | ||
| 182 | tf = fs->fbuff[i][ti4]; | ||
| 183 | fb = fc - tf*fa; | ||
| 184 | fa = fa - tf*fc; | ||
| 185 | } | ||
| 186 | tf = tf2; | ||
| 187 | tf = tf + flpa * fs->flp; // lowpass post-emphasis filter | ||
| 188 | fs->flp = tf; | ||
| 189 | |||
| 190 | // Bring up the gain slowly when formant correction goes from disabled | ||
| 191 | // to enabled, while things stabilize. | ||
| 192 | if (fs->fmute>0.5) | ||
| 193 | { | ||
| 194 | tf = tf*(fs->fmute - 0.5)*2; | ||
| 195 | } | ||
| 196 | else | ||
| 197 | { | ||
| 198 | tf = 0; | ||
| 199 | } | ||
| 200 | tf2 = fs->fmutealph; | ||
| 201 | fs->fmute = (1-tf2) + tf2*fs->fmute; | ||
| 202 | // now tf is signal output | ||
| 203 | // ...and we're done messing with formants | ||
| 204 | |||
| 205 | return tf; | ||
| 206 | } | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | /*============================================================================== | 1 | /*============================================================================== |
| 2 | 2 | ||
| 3 | leaf-808.c | 3 | leaf-instruments.c |
| 4 | Created: 30 Nov 2018 10:24:21am | 4 | Created: 30 Nov 2018 10:24:21am |
| 5 | Author: airship | 5 | Author: airship |
| 6 | 6 | ||
| @@ -8,11 +8,11 @@ · 1 unmodified line | |||
| 8 | 8 | ||
| 9 | #if _WIN32 || _WIN64 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | ||
| 11 | #include "..\Inc\leaf-808.h" | 11 | #include "..\Inc\leaf-instruments.h" |
| 12 | 12 | ||
| 13 | #else | 13 | #else |
| 14 | 14 | ||
| 15 | #include "../Inc/leaf-808.h" | 15 | #include "../Inc/leaf-instruments.h" |
| 16 | 16 | ||
| 17 | #endif | 17 | #endif |
| 18 | 18 | ||
| @@ -355,3 +355,5 @@ float LEAF_interpolation_linear (float A, float B, float alpha) · 354 unmodified lines | |||
| 355 | 355 | ||
| 356 | return out; | 356 | return out; |
| 357 | } | 357 | } |
| 358 | |||
| 359 | |||
| @@ -305,3 +305,216 @@ int tPoly_isOn(tPoly* const poly, uint8_t voice) · 304 unmodified lines | |||
| 305 | return (poly->voices[voice][0] > 0) ? 1 : 0; | 305 | return (poly->voices[voice][0] > 0) ? 1 : 0; |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | |||
| 309 | //==================================================================================== | ||
| 310 | /* Stack */ | ||
| 311 | //==================================================================================== | ||
| 312 | |||
| 313 | void tStack_init(tStack* const ns) | ||
| 314 | { | ||
| 315 | ns->ordered = OFALSE; | ||
| 316 | ns->size = 0; | ||
| 317 | ns->pos = 0; | ||
| 318 | ns->capacity = STACK_SIZE; | ||
| 319 | |||
| 320 | for (int i = 0; i < STACK_SIZE; i++) ns->data[i] = -1; | ||
| 321 | } | ||
| 322 | |||
| 323 | void tStack_free(tStack* const ns) | ||
| 324 | { | ||
| 325 | |||
| 326 | } | ||
| 327 | |||
| 328 | // If stack contains note, returns index. Else returns -1; | ||
| 329 | int tStack_contains(tStack* const ns, uint16_t noteVal) | ||
| 330 | { | ||
| 331 | for (int i = 0; i < ns->size; i++) | ||
| 332 | { | ||
| 333 | if (ns->data[i] == noteVal) return i; | ||
| 334 | } | ||
| 335 | return -1; | ||
| 336 | } | ||
| 337 | |||
| 338 | void tStack_add(tStack* const ns, uint16_t noteVal) | ||
| 339 | { | ||
| 340 | uint8_t j; | ||
| 341 | |||
| 342 | int whereToInsert = 0; | ||
| 343 | if (ns->ordered) | ||
| 344 | { | ||
| 345 | for (j = 0; j < ns->size; j++) | ||
| 346 | { | ||
| 347 | if (noteVal > ns->data[j]) | ||
| 348 | { | ||
| 349 | if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1)) | ||
| 350 | { | ||
| 351 | whereToInsert = j+1; | ||
| 352 | break; | ||
| 353 | } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | //first move notes that are already in the stack one position to the right | ||
| 359 | for (j = ns->size; j > whereToInsert; j--) | ||
| 360 | { | ||
| 361 | ns->data[j] = ns->data[(j - 1)]; | ||
| 362 | } | ||
| 363 | |||
| 364 | //then, insert the new note into the front of the stack | ||
| 365 | ns->data[whereToInsert] = noteVal; | ||
| 366 | |||
| 367 | ns->size++; | ||
| 368 | } | ||
| 369 | |||
| 370 | int tStack_addIfNotAlreadyThere(tStack* const ns, uint16_t noteVal) | ||
| 371 | { | ||
| 372 | uint8_t j; | ||
| 373 | |||
| 374 | int added = 0; | ||
| 375 | |||
| 376 | if (tStack_contains(ns, noteVal) == -1) | ||
| 377 | { | ||
| 378 | int whereToInsert = 0; | ||
| 379 | if (ns->ordered) | ||
| 380 | { | ||
| 381 | for (j = 0; j < ns->size; j++) | ||
| 382 | { | ||
| 383 | if (noteVal > ns->data[j]) | ||
| 384 | { | ||
| 385 | if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1)) | ||
| 386 | { | ||
| 387 | whereToInsert = j+1; | ||
| 388 | break; | ||
| 389 | } | ||
| 390 | } | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | //first move notes that are already in the stack one position to the right | ||
| 395 | for (j = ns->size; j > whereToInsert; j--) | ||
| 396 | { | ||
| 397 | ns->data[j] = ns->data[(j - 1)]; | ||
| 398 | } | ||
| 399 | |||
| 400 | //then, insert the new note into the front of the stack | ||
| 401 | ns->data[whereToInsert] = noteVal; | ||
| 402 | |||
| 403 | ns->size++; | ||
| 404 | |||
| 405 | added = 1; | ||
| 406 | } | ||
| 407 | |||
| 408 | return added; | ||
| 409 | } | ||
| 410 | |||
| 411 | |||
| 412 | // Remove noteVal. return 1 if removed, 0 if not | ||
| 413 | int tStack_remove(tStack* const ns, uint16_t noteVal) | ||
| 414 | { | ||
| 415 | uint8_t k; | ||
| 416 | int foundIndex = tStack_contains(ns, noteVal); | ||
| 417 | int removed = 0; | ||
| 418 | |||
| 419 | if (foundIndex >= 0) | ||
| 420 | { | ||
| 421 | for (k = 0; k < (ns->size - foundIndex); k++) | ||
| 422 | { | ||
| 423 | if ((k+foundIndex) >= (ns->capacity - 1)) | ||
| 424 | { | ||
| 425 | ns->data[k + foundIndex] = -1; | ||
| 426 | } | ||
| 427 | else | ||
| 428 | { | ||
| 429 | ns->data[k + foundIndex] = ns->data[k + foundIndex + 1]; | ||
| 430 | if ((k + foundIndex) == (ns->size - 1)) | ||
| 431 | { | ||
| 432 | ns->data[k + foundIndex + 1] = -1; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | } | ||
| 437 | // in case it got put on the stack multiple times | ||
| 438 | foundIndex--; | ||
| 439 | ns->size--; | ||
| 440 | removed = 1; | ||
| 441 | } | ||
| 442 | |||
| 443 | |||
| 444 | |||
| 445 | return removed; | ||
| 446 | } | ||
| 447 | |||
| 448 | // Doesn't change size of data types | ||
| 449 | void tStack_setCapacity(tStack* const ns, uint16_t cap) | ||
| 450 | { | ||
| 451 | if (cap <= 0) | ||
| 452 | ns->capacity = 1; | ||
| 453 | else if (cap <= STACK_SIZE) | ||
| 454 | ns->capacity = cap; | ||
| 455 | else | ||
| 456 | ns->capacity = STACK_SIZE; | ||
| 457 | |||
| 458 | for (int i = cap; i < STACK_SIZE; i++) | ||
| 459 | { | ||
| 460 | if ((int)ns->data[i] != -1) | ||
| 461 | { | ||
| 462 | ns->data[i] = -1; | ||
| 463 | ns->size -= 1; | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | if (ns->pos >= cap) | ||
| 468 | { | ||
| 469 | ns->pos = 0; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | int tStack_getSize(tStack* const ns) | ||
| 474 | { | ||
| 475 | return ns->size; | ||
| 476 | } | ||
| 477 | |||
| 478 | void tStack_clear(tStack* const ns) | ||
| 479 | { | ||
| 480 | for (int i = 0; i < STACK_SIZE; i++) | ||
| 481 | { | ||
| 482 | ns->data[i] = -1; | ||
| 483 | } | ||
| 484 | ns->pos = 0; | ||
| 485 | ns->size = 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | // Next item in order of addition to stack. Return 0-31 if there is a next item to move to. Returns -1 otherwise. | ||
| 489 | int tStack_next(tStack* const ns) | ||
| 490 | { | ||
| 491 | int step = 0; | ||
| 492 | if (ns->size != 0) // if there is at least one note in the stack | ||
| 493 | { | ||
| 494 | if (ns->pos > 0) // if you're not at the most recent note (first one), then go backward in the array (moving from earliest to latest) | ||
| 495 | { | ||
| 496 | ns->pos--; | ||
| 497 | } | ||
| 498 | else | ||
| 499 | { | ||
| 500 | ns->pos = (ns->size - 1); // if you are the most recent note, go back to the earliest note in the array | ||
| 501 | } | ||
| 502 | |||
| 503 | step = ns->data[ns->pos]; | ||
| 504 | return step; | ||
| 505 | } | ||
| 506 | else | ||
| 507 | { | ||
| 508 | return -1; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | int tStack_get(tStack* const ns, int which) | ||
| 513 | { | ||
| 514 | return ns->data[which]; | ||
| 515 | } | ||
| 516 | |||
| 517 | int tStack_first(tStack* const ns) | ||
| 518 | { | ||
| 519 | return ns->data[0]; | ||
| 520 | } | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | /*============================================================================== | 1 | /*============================================================================== |
| 2 | 2 | ||
| 3 | leaf-oscillator.c | 3 | leaf-oscillators.c |
| 4 | Created: 20 Jan 2017 12:00:58pm | 4 | Created: 20 Jan 2017 12:00:58pm |
| 5 | Author: Michael R Mulshine | 5 | Author: Michael R Mulshine |
| 6 | 6 | ||
| @@ -9,212 +9,17 @@ · 2 unmodified lines | |||
| 9 | #if _WIN32 || _WIN64 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | ||
| 11 | #include "..\Inc\leaf-tables.h" | 11 | #include "..\Inc\leaf-tables.h" |
| 12 | #include "..\Inc\leaf-oscillator.h" | 12 | #include "..\Inc\leaf-oscillators.h" |
| 13 | #include "..\leaf.h" | 13 | #include "..\leaf.h" |
| 14 | 14 | ||
| 15 | #else | 15 | #else |
| 16 | 16 | ||
| 17 | #include "../Inc/leaf-tables.h" | 17 | #include "../Inc/leaf-tables.h" |
| 18 | #include "../Inc/leaf-oscillator.h" | 18 | #include "../Inc/leaf-oscillators.h" |
| 19 | #include "../leaf.h" | 19 | #include "../leaf.h" |
| 20 | 20 | ||
| 21 | #endif | 21 | #endif |
| 22 | 22 | ||
| 23 | void tNeuronSampleRateChanged(tNeuron* n) | ||
| 24 | { | ||
| 25 | |||
| 26 | } | ||
| 27 | |||
| 28 | void tNeuron_init(tNeuron* const n) | ||
| 29 | { | ||
| 30 | tPoleZero_init(&n->f); | ||
| 31 | |||
| 32 | tPoleZero_setBlockZero(&n->f, 0.99f); | ||
| 33 | |||
| 34 | n->timeStep = 1.0f / 50.0f; | ||
| 35 | |||
| 36 | n->current = 0.0f; // 100.0f for sound | ||
| 37 | n->voltage = 0.0f; | ||
| 38 | |||
| 39 | n->mode = NeuronNormal; | ||
| 40 | |||
| 41 | n->P[0] = 0.0f; | ||
| 42 | n->P[1] = 0.0f; | ||
| 43 | n->P[2] = 1.0f; | ||
| 44 | |||
| 45 | n->V[0] = -12.0f; | ||
| 46 | n->V[1] = 115.0f; | ||
| 47 | n->V[2] = 10.613f; | ||
| 48 | |||
| 49 | n->gK = 36.0f; | ||
| 50 | n->gN = 120.0f; | ||
| 51 | n->gL = 0.3f; | ||
| 52 | n->C = 1.0f; | ||
| 53 | |||
| 54 | n->rate[2] = n->gL/n->C; | ||
| 55 | } | ||
| 56 | |||
| 57 | void tNeuron_free(tNeuron* const n) | ||
| 58 | { | ||
| 59 | tPoleZero_free(&n->f); | ||
| 60 | } | ||
| 61 | |||
| 62 | void tNeuron_reset(tNeuron* const n) | ||
| 63 | { | ||
| 64 | |||
| 65 | tPoleZero_setBlockZero(&n->f, 0.99f); | ||
| 66 | |||
| 67 | n->timeStep = 1.0f / 50.0f; | ||
| 68 | |||
| 69 | n->current = 0.0f; // 100.0f for sound | ||
| 70 | n->voltage = 0.0f; | ||
| 71 | |||
| 72 | n->mode = NeuronNormal; | ||
| 73 | |||
| 74 | n->P[0] = 0.0f; | ||
| 75 | n->P[1] = 0.0f; | ||
| 76 | n->P[2] = 1.0f; | ||
| 77 | |||
| 78 | n->V[0] = -12.0f; | ||
| 79 | n->V[1] = 115.0f; | ||
| 80 | n->V[2] = 10.613f; | ||
| 81 | |||
| 82 | n->gK = 36.0f; | ||
| 83 | n->gN = 120.0f; | ||
| 84 | n->gL = 0.3f; | ||
| 85 | n->C = 1.0f; | ||
| 86 | |||
| 87 | n->rate[2] = n->gL/n->C; | ||
| 88 | } | ||
| 89 | |||
| 90 | |||
| 91 | void tNeuron_setV1(tNeuron* const n, float V1) | ||
| 92 | { | ||
| 93 | n->V[0] = V1; | ||
| 94 | } | ||
| 95 | |||
| 96 | |||
| 97 | void tNeuron_setV2(tNeuron* const n, float V2) | ||
| 98 | { | ||
| 99 | n->V[1] = V2; | ||
| 100 | } | ||
| 101 | |||
| 102 | void tNeuron_setV3(tNeuron* const n, float V3) | ||
| 103 | { | ||
| 104 | n->V[2] = V3; | ||
| 105 | } | ||
| 106 | |||
| 107 | void tNeuron_setTimeStep(tNeuron* const n, float timeStep) | ||
| 108 | { | ||
| 109 | n->timeStep = timeStep; | ||
| 110 | } | ||
| 111 | |||
| 112 | void tNeuron_setK(tNeuron* const n, float K) | ||
| 113 | { | ||
| 114 | n->gK = K; | ||
| 115 | } | ||
| 116 | |||
| 117 | void tNeuron_setL(tNeuron* const n, float L) | ||
| 118 | { | ||
| 119 | n->gL = L; | ||
| 120 | n->rate[2] = n->gL/n->C; | ||
| 121 | } | ||
| 122 | |||
| 123 | void tNeuron_setN(tNeuron* const n, float N) | ||
| 124 | { | ||
| 125 | n->gN = N; | ||
| 126 | } | ||
| 127 | |||
| 128 | void tNeuron_setC(tNeuron* const n, float C) | ||
| 129 | { | ||
| 130 | n->C = C; | ||
| 131 | n->rate[2] = n->gL/n->C; | ||
| 132 | } | ||
| 133 | |||
| 134 | float tNeuron_tick(tNeuron* const n) | ||
| 135 | { | ||
| 136 | float output = 0.0f; | ||
| 137 | float voltage = n->voltage; | ||
| 138 | |||
| 139 | n->alpha[0] = (0.01f * (10.0f - voltage)) / (expf((10.0f - voltage)/10.0f) - 1.0f); | ||
| 140 | n->alpha[1] = (0.1f * (25.0f-voltage)) / (expf((25.0f-voltage)/10.0f) - 1.0f); | ||
| 141 | n->alpha[2] = (0.07f * expf((-1.0f * voltage)/20.0f)); | ||
| 142 | |||
| 143 | n->beta[0] = (0.125f * expf((-1.0f* voltage)/80.0f)); | ||
| 144 | n->beta[1] = (4.0f * expf((-1.0f * voltage)/18.0f)); | ||
| 145 | n->beta[2] = (1.0f / (expf((30.0f-voltage)/10.0f) + 1.0f)); | ||
| 146 | |||
| 147 | for (int i = 0; i < 3; i++) | ||
| 148 | { | ||
| 149 | n->P[i] = (n->alpha[i] * n->timeStep) + ((1.0f - ((n->alpha[i] + n->beta[i]) * n->timeStep)) * n->P[i]); | ||
| 150 | |||
| 151 | if (n->P[i] > 1.0f) n->P[i] = 0.0f; | ||
| 152 | else if (n->P[i] < -1.0f) n->P[i] = 0.0f; | ||
| 153 | } | ||
| 154 | // rate[0]= k ; rate[1] = Na ; rate[2] = l | ||
| 155 | n->rate[0] = ((n->gK * powf(n->P[0], 4.0f)) / n->C); | ||
| 156 | n->rate[1] = ((n->gN * powf(n->P[1], 3.0f) * n->P[2]) / n->C); | ||
| 157 | |||
| 158 | //calculate the final membrane voltage based on the computed variables | ||
| 159 | n->voltage = voltage + | ||
| 160 | (n->timeStep * n->current / n->C) - | ||
| 161 | (n->timeStep * ( n->rate[0] * (voltage - n->V[0]) + n->rate[1] * (voltage - n->V[1]) + n->rate[2] * (voltage - n->V[2]))); | ||
| 162 | |||
| 163 | if (n->mode == NeuronTanh) | ||
| 164 | { | ||
| 165 | n->voltage = 100.0f * tanhf(0.01f * n->voltage); | ||
| 166 | } | ||
| 167 | else if (n->mode == NeuronAaltoShaper) | ||
| 168 | { | ||
| 169 | float shapeVoltage = 0.01f * n->voltage; | ||
| 170 | |||
| 171 | float w, c, xc, xc2, xc4; | ||
| 172 | |||
| 173 | float sqrt8 = 2.82842712475f; | ||
| 174 | |||
| 175 | float wscale = 1.30612244898f; | ||
| 176 | float m_drive = 1.0f; | ||
| 177 | |||
| 178 | xc = LEAF_clip(-sqrt8, shapeVoltage, sqrt8); | ||
| 179 | |||
| 180 | xc2 = xc*xc; | ||
| 181 | |||
| 182 | c = 0.5f * shapeVoltage * (3.0f - (xc2)); | ||
| 183 | |||
| 184 | xc4 = xc2 * xc2; | ||
| 185 | |||
| 186 | w = (1.0f - xc2 * 0.25f + xc4 * 0.015625f) * wscale; | ||
| 187 | |||
| 188 | shapeVoltage = w * (c + 0.05f * xc2) * (m_drive + 0.75f); | ||
| 189 | |||
| 190 | n->voltage = 100.0f * shapeVoltage; | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | if (n->voltage > 100.0f) n->voltage = 100.0f; | ||
| 195 | else if (n->voltage < -100.) n->voltage = -100.0f; | ||
| 196 | |||
| 197 | //(inputCurrent + (voltage - ((voltage * timeStep) / timeConstant)) + P[0] + P[1] + P[2]) => voltage; | ||
| 198 | // now we should have a result | ||
| 199 | //set the output voltage to the "step" ugen, which controls the DAC. | ||
| 200 | output = n->voltage * 0.01f; // volts | ||
| 201 | |||
| 202 | output = tPoleZero_tick(&n->f, output); | ||
| 203 | |||
| 204 | return output; | ||
| 205 | |||
| 206 | } | ||
| 207 | |||
| 208 | void tNeuron_setMode (tNeuron* const n, NeuronMode mode) | ||
| 209 | { | ||
| 210 | n->mode = mode; | ||
| 211 | } | ||
| 212 | |||
| 213 | void tNeuron_setCurrent (tNeuron* const n, float current) | ||
| 214 | { | ||
| 215 | n->current = current; | ||
| 216 | } | ||
| 217 | |||
| 218 | // Cycle | 23 | // Cycle |
| 219 | void tCycle_init(tCycle* const c) | 24 | void tCycle_init(tCycle* const c) |
| 220 | { | 25 | { |
| @@ -258,56 +63,25 @@ void tCycleSampleRateChanged (tCycle* const c) · 37 unmodified lines | |||
| 258 | c->inc = c->freq * leaf.invSampleRate; | 63 | c->inc = c->freq * leaf.invSampleRate; |
| 259 | } | 64 | } |
| 260 | 65 | ||
| 261 | /* Phasor */ | 66 | //======================================================================== |
| 262 | void tPhasorSampleRateChanged (tPhasor* const p) | 67 | /* Triangle */ |
| 263 | { | 68 | void tTriangle_start(tTriangle* const c) |
| 264 | p->inc = p->freq * leaf.invSampleRate; | ||
| 265 | }; | ||
| 266 | |||
| 267 | void tPhasor_init(tPhasor* const p) | ||
| 268 | { | ||
| 269 | p->phase = 0.0f; | ||
| 270 | p->inc = 0.0f; | ||
| 271 | } | ||
| 272 | |||
| 273 | void tPhasor_free(tPhasor* const p) | ||
| 274 | { | 69 | { |
| 275 | 70 | ||
| 276 | } | 71 | } |
| 277 | 72 | ||
| 278 | int tPhasor_setFreq(tPhasor* const p, float freq) | 73 | void tTriangle_init(tTriangle* const c) |
| 279 | { | 74 | { |
| 280 | if (freq < 0.0f) freq = 0.0f; | 75 | c->inc = 0.0f; |
| 281 | 76 | c->phase = 0.0f; | |
| 282 | p->freq = freq; | ||
| 283 | p->inc = freq * leaf.invSampleRate; | ||
| 284 | |||
| 285 | return 0; | ||
| 286 | } | 77 | } |
| 287 | 78 | ||
| 288 | float tPhasor_tick(tPhasor* const p) | 79 | void tTriangle_free(tTriangle* const c) |
| 289 | { | 80 | { |
| 290 | p->phase += p->inc; | ||
| 291 | |||
| 292 | if (p->phase >= 1.0f) p->phase -= 1.0f; | ||
| 293 | 81 | ||
| 294 | return p->phase; | ||
| 295 | } | 82 | } |
| 296 | 83 | ||
| 297 | 84 | int tTriangle_setFreq(tTriangle* const c, float freq) | |
| 298 | |||
| 299 | void tSawtooth_init(tSawtooth* const c) | ||
| 300 | { | ||
| 301 | c->inc = 0.0f; | ||
| 302 | c->phase = 0.0f; | ||
| 303 | } | ||
| 304 | |||
| 305 | void tSawtooth_free(tSawtooth* const c) | ||
| 306 | { | ||
| 307 | |||
| 308 | } | ||
| 309 | |||
| 310 | int tSawtooth_setFreq(tSawtooth* const c, float freq) | ||
| 311 | { | 85 | { |
| 312 | if (freq < 0.0f) freq = 0.0f; | 86 | if (freq < 0.0f) freq = 0.0f; |
| 313 | 87 | ||
| @@ -317,7 +91,8 @@ int tSawtooth_setFreq(tSawtooth* const c, float freq) · 3 unmodified lines | |||
| 317 | return 0; | 91 | return 0; |
| 318 | } | 92 | } |
| 319 | 93 | ||
| 320 | float tSawtooth_tick(tSawtooth* const c) | 94 | |
| 95 | float tTriangle_tick(tTriangle* const c) | ||
| 321 | { | 96 | { |
| 322 | // Phasor increment | 97 | // Phasor increment |
| 323 | c->phase += c->inc; | 98 | c->phase += c->inc; |
| @@ -332,89 +107,85 @@ float tSawtooth_tick(tSawtooth* const c) · 8 unmodified lines | |||
| 332 | 107 | ||
| 333 | if (c->freq <= 20.0f) | 108 | if (c->freq <= 20.0f) |
| 334 | { | 109 | { |
| 335 | out = sawtooth[T20][idx]; | 110 | out = triangle[T20][idx]; |
| 336 | } | 111 | } |
| 337 | else if (c->freq <= 40.0f) | 112 | else if (c->freq <= 40.0f) |
| 338 | { | 113 | { |
| 339 | w = ((40.0f - c->freq) * INV_20); | 114 | w = ((40.0f - c->freq) * INV_20); |
| 340 | out = (sawtooth[T20][idx] * w) + (sawtooth[T40][idx] * (1.0f - w)); | 115 | out = (triangle[T20][idx] * w) + (triangle[T40][idx] * (1.0f - w)); |
| 341 | } | 116 | } |
| 342 | else if (c->freq <= 80.0f) | 117 | else if (c->freq <= 80.0f) |
| 343 | { | 118 | { |
| 344 | w = ((80.0f - c->freq) * INV_40); | 119 | w = ((80.0f - c->freq) * INV_40); |
| 345 | out = (sawtooth[T40][idx] * w) + (sawtooth[T80][idx] * (1.0f - w)); | 120 | out = (triangle[T40][idx] * w) + (triangle[T80][idx] * (1.0f - w)); |
| 346 | } | 121 | } |
| 347 | else if (c->freq <= 160.0f) | 122 | else if (c->freq <= 160.0f) |
| 348 | { | 123 | { |
| 349 | w = ((160.0f - c->freq) * INV_80); | 124 | w = ((160.0f - c->freq) * INV_80); |
| 350 | out = (sawtooth[T80][idx] * w) + (sawtooth[T160][idx] * (1.0f - w)); | 125 | out = (triangle[T80][idx] * w) + (triangle[T160][idx] * (1.0f - w)); |
| 351 | } | 126 | } |
| 352 | else if (c->freq <= 320.0f) | 127 | else if (c->freq <= 320.0f) |
| 353 | { | 128 | { |
| 354 | w = ((320.0f - c->freq) * INV_160); | 129 | w = ((320.0f - c->freq) * INV_160); |
| 355 | out = (sawtooth[T160][idx] * w) + (sawtooth[T320][idx] * (1.0f - w)); | 130 | out = (triangle[T160][idx] * w) + (triangle[T320][idx] * (1.0f - w)); |
| 356 | } | 131 | } |
| 357 | else if (c->freq <= 640.0f) | 132 | else if (c->freq <= 640.0f) |
| 358 | { | 133 | { |
| 359 | w = ((640.0f - c->freq) * INV_320); | 134 | w = ((640.0f - c->freq) * INV_320); |
| 360 | out = (sawtooth[T320][idx] * w) + (sawtooth[T640][idx] * (1.0f - w)); | 135 | out = (triangle[T320][idx] * w) + (triangle[T640][idx] * (1.0f - w)); |
| 361 | } | 136 | } |
| 362 | else if (c->freq <= 1280.0f) | 137 | else if (c->freq <= 1280.0f) |
| 363 | { | 138 | { |
| 364 | w = ((1280.0f - c->freq) * INV_640); | 139 | w = ((1280.0f - c->freq) * INV_640); |
| 365 | out = (sawtooth[T640][idx] * w) + (sawtooth[T1280][idx] * (1.0f - w)); | 140 | out = (triangle[T640][idx] * w) + (triangle[T1280][idx] * (1.0f - w)); |
| 366 | } | 141 | } |
| 367 | else if (c->freq <= 2560.0f) | 142 | else if (c->freq <= 2560.0f) |
| 368 | { | 143 | { |
| 369 | w = ((2560.0f - c->freq) * INV_1280); | 144 | w = ((2560.0f - c->freq) * INV_1280); |
| 370 | out = (sawtooth[T1280][idx] * w) + (sawtooth[T2560][idx] * (1.0f - w)); | 145 | out = (triangle[T1280][idx] * w) + (triangle[T2560][idx] * (1.0f - w)); |
| 371 | } | 146 | } |
| 372 | else if (c->freq <= 5120.0f) | 147 | else if (c->freq <= 5120.0f) |
| 373 | { | 148 | { |
| 374 | w = ((5120.0f - c->freq) * INV_2560); | 149 | w = ((5120.0f - c->freq) * INV_2560); |
| 375 | out = (sawtooth[T2560][idx] * w) + (sawtooth[T5120][idx] * (1.0f - w)); | 150 | out = (triangle[T2560][idx] * w) + (triangle[T5120][idx] * (1.0f - w)); |
| 376 | } | 151 | } |
| 377 | else if (c->freq <= 10240.0f) | 152 | else if (c->freq <= 10240.0f) |
| 378 | { | 153 | { |
| 379 | w = ((10240.0f - c->freq) * INV_5120); | 154 | w = ((10240.0f - c->freq) * INV_5120); |
| 380 | out = (sawtooth[T5120][idx] * w) + (sawtooth[T10240][idx] * (1.0f - w)); | 155 | out = (triangle[T5120][idx] * w) + (triangle[T10240][idx] * (1.0f - w)); |
| 381 | } | 156 | } |
| 382 | else if (c->freq <= 20480.0f) | 157 | else if (c->freq <= 20480.0f) |
| 383 | { | 158 | { |
| 384 | w = ((20480.0f - c->freq) * INV_10240); | 159 | w = ((20480.0f - c->freq) * INV_10240); |
| 385 | out = (sawtooth[T10240][idx] * w) + (sawtooth[T20480][idx] * (1.0f - w)); | 160 | out = (triangle[T10240][idx] * w) + (triangle[T20480][idx] * (1.0f - w)); |
| 386 | } | 161 | } |
| 387 | else | 162 | else |
| 388 | { | 163 | { |
| 389 | out = sawtooth[T20480][idx]; | 164 | out = triangle[T20480][idx]; |
| 390 | } | 165 | } |
| 391 | 166 | ||
| 392 | return out; | 167 | return out; |
| 393 | } | 168 | } |
| 394 | 169 | ||
| 395 | void tSawtoothSampleRateChanged (tSawtooth* const c) | 170 | void tTriangleSampleRateChanged (tTriangle* const c) |
| 396 | { | 171 | { |
| 397 | c->inc = c->freq * leaf.invSampleRate; | 172 | c->inc = c->freq * leaf.invSampleRate; |
| 398 | } | 173 | } |
| 399 | 174 | ||
| 400 | /* Triangle */ | 175 | //======================================================================== |
| 401 | void tTriangle_start(tTriangle* const c) | 176 | /* Square */ |
| 402 | { | 177 | void tSquare_init(tSquare* const c) |
| 403 | |||
| 404 | } | ||
| 405 | |||
| 406 | void tTriangle_init(tTriangle* const c) | ||
| 407 | { | 178 | { |
| 408 | c->inc = 0.0f; | 179 | c->inc = 0.0f; |
| 409 | c->phase = 0.0f; | 180 | c->phase = 0.0f; |
| 410 | } | 181 | } |
| 411 | 182 | ||
| 412 | void tTriangle_free(tTriangle* const c) | 183 | void tSquare_free(tSquare* const c) |
| 413 | { | 184 | { |
| 414 | 185 | ||
| 415 | } | 186 | } |
| 416 | 187 | ||
| 417 | int tTriangle_setFreq(tTriangle* const c, float freq) | 188 | int tSquare_setFreq(tSquare* const c, float freq) |
| 418 | { | 189 | { |
| 419 | if (freq < 0.0f) freq = 0.0f; | 190 | if (freq < 0.0f) freq = 0.0f; |
| 420 | 191 | ||
| @@ -424,100 +195,99 @@ int tTriangle_setFreq(tTriangle* const c, float freq) · 3 unmodified lines | |||
| 424 | return 0; | 195 | return 0; |
| 425 | } | 196 | } |
| 426 | 197 | ||
| 427 | 198 | float tSquare_tick(tSquare* const c) | |
| 428 | float tTriangle_tick(tTriangle* const c) | ||
| 429 | { | 199 | { |
| 430 | // Phasor increment | 200 | // Phasor increment |
| 431 | c->phase += c->inc; | 201 | c->phase += c->inc; |
| 432 | while (c->phase >= 1.0f) c->phase -= 1.0f; | 202 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 433 | 203 | ||
| 434 | float out = 0.0f; | 204 | float out = 0.0f; |
| 435 | float w; | 205 | float w = 0.0f; |
| 436 | |||
| 437 | int idx = (int)(c->phase * TRI_TABLE_SIZE); | 206 | int idx = (int)(c->phase * TRI_TABLE_SIZE); |
| 438 | 207 | ||
| 439 | // Wavetable synthesis | 208 | // Wavetable synthesis |
| 440 | 209 | ||
| 441 | if (c->freq <= 20.0f) | 210 | if (c->freq <= 20.0f) |
| 442 | { | 211 | { |
| 443 | out = triangle[T20][idx]; | 212 | out = squarewave[T20][idx]; |
| 444 | } | 213 | } |
| 445 | else if (c->freq <= 40.0f) | 214 | else if (c->freq <= 40.0f) |
| 446 | { | 215 | { |
| 447 | w = ((40.0f - c->freq) * INV_20); | 216 | w = ((40.0f - c->freq) * INV_20); |
| 448 | out = (triangle[T20][idx] * w) + (triangle[T40][idx] * (1.0f - w)); | 217 | out = (squarewave[T20][idx] * w) + (squarewave[T40][idx] * (1.0f - w)); |
| 449 | } | 218 | } |
| 450 | else if (c->freq <= 80.0f) | 219 | else if (c->freq <= 80.0f) |
| 451 | { | 220 | { |
| 452 | w = ((80.0f - c->freq) * INV_40); | 221 | w = ((80.0f - c->freq) * INV_40); |
| 453 | out = (triangle[T40][idx] * w) + (triangle[T80][idx] * (1.0f - w)); | 222 | out = (squarewave[T40][idx] * w) + (squarewave[T80][idx] * (1.0f - w)); |
| 454 | } | 223 | } |
| 455 | else if (c->freq <= 160.0f) | 224 | else if (c->freq <= 160.0f) |
| 456 | { | 225 | { |
| 457 | w = ((160.0f - c->freq) * INV_80); | 226 | w = ((160.0f - c->freq) * INV_80); |
| 458 | out = (triangle[T80][idx] * w) + (triangle[T160][idx] * (1.0f - w)); | 227 | out = (squarewave[T80][idx] * w) + (squarewave[T160][idx] * (1.0f - w)); |
| 459 | } | 228 | } |
| 460 | else if (c->freq <= 320.0f) | 229 | else if (c->freq <= 320.0f) |
| 461 | { | 230 | { |
| 462 | w = ((320.0f - c->freq) * INV_160); | 231 | w = ((320.0f - c->freq) * INV_160); |
| 463 | out = (triangle[T160][idx] * w) + (triangle[T320][idx] * (1.0f - w)); | 232 | out = (squarewave[T160][idx] * w) + (squarewave[T320][idx] * (1.0f - w)); |
| 464 | } | 233 | } |
| 465 | else if (c->freq <= 640.0f) | 234 | else if (c->freq <= 640.0f) |
| 466 | { | 235 | { |
| 467 | w = ((640.0f - c->freq) * INV_320); | 236 | w = ((640.0f - c->freq) * INV_320); |
| 468 | out = (triangle[T320][idx] * w) + (triangle[T640][idx] * (1.0f - w)); | 237 | out = (squarewave[T320][idx] * w) + (squarewave[T640][idx] * (1.0f - w)); |
| 469 | } | 238 | } |
| 470 | else if (c->freq <= 1280.0f) | 239 | else if (c->freq <= 1280.0f) |
| 471 | { | 240 | { |
| 472 | w = ((1280.0f - c->freq) * INV_640); | 241 | w = ((1280.0f - c->freq) * INV_640); |
| 473 | out = (triangle[T640][idx] * w) + (triangle[T1280][idx] * (1.0f - w)); | 242 | out = (squarewave[T640][idx] * w) + (squarewave[T1280][idx] * (1.0f - w)); |
| 474 | } | 243 | } |
| 475 | else if (c->freq <= 2560.0f) | 244 | else if (c->freq <= 2560.0f) |
| 476 | { | 245 | { |
| 477 | w = ((2560.0f - c->freq) * INV_1280); | 246 | w = ((2560.0f - c->freq) * INV_1280); |
| 478 | out = (triangle[T1280][idx] * w) + (triangle[T2560][idx] * (1.0f - w)); | 247 | out = (squarewave[T1280][idx] * w) + (squarewave[T2560][idx] * (1.0f - w)); |
| 479 | } | 248 | } |
| 480 | else if (c->freq <= 5120.0f) | 249 | else if (c->freq <= 5120.0f) |
| 481 | { | 250 | { |
| 482 | w = ((5120.0f - c->freq) * INV_2560); | 251 | w = ((5120.0f - c->freq) * INV_2560); |
| 483 | out = (triangle[T2560][idx] * w) + (triangle[T5120][idx] * (1.0f - w)); | 252 | out = (squarewave[T2560][idx] * w) + (squarewave[T5120][idx] * (1.0f - w)); |
| 484 | } | 253 | } |
| 485 | else if (c->freq <= 10240.0f) | 254 | else if (c->freq <= 10240.0f) |
| 486 | { | 255 | { |
| 487 | w = ((10240.0f - c->freq) * INV_5120); | 256 | w = ((10240.0f - c->freq) * INV_5120); |
| 488 | out = (triangle[T5120][idx] * w) + (triangle[T10240][idx] * (1.0f - w)); | 257 | out = (squarewave[T5120][idx] * w) + (squarewave[T10240][idx] * (1.0f - w)); |
| 489 | } | 258 | } |
| 490 | else if (c->freq <= 20480.0f) | 259 | else if (c->freq <= 20480.0f) |
| 491 | { | 260 | { |
| 492 | w = ((20480.0f - c->freq) * INV_10240); | 261 | w = ((20480.0f - c->freq) * INV_10240); |
| 493 | out = (triangle[T10240][idx] * w) + (triangle[T20480][idx] * (1.0f - w)); | 262 | out = (squarewave[T10240][idx] * w) + (squarewave[T20480][idx] * (1.0f - w)); |
| 494 | } | 263 | } |
| 495 | else | 264 | else |
| 496 | { | 265 | { |
| 497 | out = triangle[T20480][idx]; | 266 | out = squarewave[T20480][idx]; |
| 498 | } | 267 | } |
| 499 | 268 | ||
| 500 | return out; | 269 | return out; |
| 501 | } | 270 | } |
| 502 | 271 | ||
| 503 | void tTriangleSampleRateChanged (tTriangle* const c) | 272 | void tSquareSampleRateChanged (tSquare* const c) |
| 504 | { | 273 | { |
| 505 | c->inc = c->freq * leaf.invSampleRate; | 274 | c->inc = c->freq * leaf.invSampleRate; |
| 506 | } | 275 | } |
| 507 | 276 | ||
| 508 | /* Square */ | 277 | //===================================================================== |
| 509 | void tSquare_init(tSquare* const c) | 278 | // Sawtooth |
| 279 | void tSawtooth_init(tSawtooth* const c) | ||
| 510 | { | 280 | { |
| 511 | c->inc = 0.0f; | 281 | c->inc = 0.0f; |
| 512 | c->phase = 0.0f; | 282 | c->phase = 0.0f; |
| 513 | } | 283 | } |
| 514 | 284 | ||
| 515 | void tSquare_free(tSquare* const c) | 285 | void tSawtooth_free(tSawtooth* const c) |
| 516 | { | 286 | { |
| 517 | 287 | ||
| 518 | } | 288 | } |
| 519 | 289 | ||
| 520 | int tSquare_setFreq(tSquare* const c, float freq) | 290 | int tSawtooth_setFreq(tSawtooth* const c, float freq) |
| 521 | { | 291 | { |
| 522 | if (freq < 0.0f) freq = 0.0f; | 292 | if (freq < 0.0f) freq = 0.0f; |
| 523 | 293 | ||
| @@ -527,85 +297,123 @@ int tSquare_setFreq(tSquare* const c, float freq) · 3 unmodified lines | |||
| 527 | return 0; | 297 | return 0; |
| 528 | } | 298 | } |
| 529 | 299 | ||
| 530 | float tSquare_tick(tSquare* const c) | 300 | float tSawtooth_tick(tSawtooth* const c) |
| 531 | { | 301 | { |
| 532 | // Phasor increment | 302 | // Phasor increment |
| 533 | c->phase += c->inc; | 303 | c->phase += c->inc; |
| 534 | while (c->phase >= 1.0f) c->phase -= 1.0f; | 304 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 535 | 305 | ||
| 536 | float out = 0.0f; | 306 | float out = 0.0f; |
| 537 | float w = 0.0f; | 307 | float w; |
| 308 | |||
| 538 | int idx = (int)(c->phase * TRI_TABLE_SIZE); | 309 | int idx = (int)(c->phase * TRI_TABLE_SIZE); |
| 539 | 310 | ||
| 540 | // Wavetable synthesis | 311 | // Wavetable synthesis |
| 541 | 312 | ||
| 542 | if (c->freq <= 20.0f) | 313 | if (c->freq <= 20.0f) |
| 543 | { | 314 | { |
| 544 | out = squarewave[T20][idx]; | 315 | out = sawtooth[T20][idx]; |
| 545 | } | 316 | } |
| 546 | else if (c->freq <= 40.0f) | 317 | else if (c->freq <= 40.0f) |
| 547 | { | 318 | { |
| 548 | w = ((40.0f - c->freq) * INV_20); | 319 | w = ((40.0f - c->freq) * INV_20); |
| 549 | out = (squarewave[T20][idx] * w) + (squarewave[T40][idx] * (1.0f - w)); | 320 | out = (sawtooth[T20][idx] * w) + (sawtooth[T40][idx] * (1.0f - w)); |
| 550 | } | 321 | } |
| 551 | else if (c->freq <= 80.0f) | 322 | else if (c->freq <= 80.0f) |
| 552 | { | 323 | { |
| 553 | w = ((80.0f - c->freq) * INV_40); | 324 | w = ((80.0f - c->freq) * INV_40); |
| 554 | out = (squarewave[T40][idx] * w) + (squarewave[T80][idx] * (1.0f - w)); | 325 | out = (sawtooth[T40][idx] * w) + (sawtooth[T80][idx] * (1.0f - w)); |
| 555 | } | 326 | } |
| 556 | else if (c->freq <= 160.0f) | 327 | else if (c->freq <= 160.0f) |
| 557 | { | 328 | { |
| 558 | w = ((160.0f - c->freq) * INV_80); | 329 | w = ((160.0f - c->freq) * INV_80); |
| 559 | out = (squarewave[T80][idx] * w) + (squarewave[T160][idx] * (1.0f - w)); | 330 | out = (sawtooth[T80][idx] * w) + (sawtooth[T160][idx] * (1.0f - w)); |
| 560 | } | 331 | } |
| 561 | else if (c->freq <= 320.0f) | 332 | else if (c->freq <= 320.0f) |
| 562 | { | 333 | { |
| 563 | w = ((320.0f - c->freq) * INV_160); | 334 | w = ((320.0f - c->freq) * INV_160); |
| 564 | out = (squarewave[T160][idx] * w) + (squarewave[T320][idx] * (1.0f - w)); | 335 | out = (sawtooth[T160][idx] * w) + (sawtooth[T320][idx] * (1.0f - w)); |
| 565 | } | 336 | } |
| 566 | else if (c->freq <= 640.0f) | 337 | else if (c->freq <= 640.0f) |
| 567 | { | 338 | { |
| 568 | w = ((640.0f - c->freq) * INV_320); | 339 | w = ((640.0f - c->freq) * INV_320); |
| 569 | out = (squarewave[T320][idx] * w) + (squarewave[T640][idx] * (1.0f - w)); | 340 | out = (sawtooth[T320][idx] * w) + (sawtooth[T640][idx] * (1.0f - w)); |
| 570 | } | 341 | } |
| 571 | else if (c->freq <= 1280.0f) | 342 | else if (c->freq <= 1280.0f) |
| 572 | { | 343 | { |
| 573 | w = ((1280.0f - c->freq) * INV_640); | 344 | w = ((1280.0f - c->freq) * INV_640); |
| 574 | out = (squarewave[T640][idx] * w) + (squarewave[T1280][idx] * (1.0f - w)); | 345 | out = (sawtooth[T640][idx] * w) + (sawtooth[T1280][idx] * (1.0f - w)); |
| 575 | } | 346 | } |
| 576 | else if (c->freq <= 2560.0f) | 347 | else if (c->freq <= 2560.0f) |
| 577 | { | 348 | { |
| 578 | w = ((2560.0f - c->freq) * INV_1280); | 349 | w = ((2560.0f - c->freq) * INV_1280); |
| 579 | out = (squarewave[T1280][idx] * w) + (squarewave[T2560][idx] * (1.0f - w)); | 350 | out = (sawtooth[T1280][idx] * w) + (sawtooth[T2560][idx] * (1.0f - w)); |
| 580 | } | 351 | } |
| 581 | else if (c->freq <= 5120.0f) | 352 | else if (c->freq <= 5120.0f) |
| 582 | { | 353 | { |
| 583 | w = ((5120.0f - c->freq) * INV_2560); | 354 | w = ((5120.0f - c->freq) * INV_2560); |
| 584 | out = (squarewave[T2560][idx] * w) + (squarewave[T5120][idx] * (1.0f - w)); | 355 | out = (sawtooth[T2560][idx] * w) + (sawtooth[T5120][idx] * (1.0f - w)); |
| 585 | } | 356 | } |
| 586 | else if (c->freq <= 10240.0f) | 357 | else if (c->freq <= 10240.0f) |
| 587 | { | 358 | { |
| 588 | w = ((10240.0f - c->freq) * INV_5120); | 359 | w = ((10240.0f - c->freq) * INV_5120); |
| 589 | out = (squarewave[T5120][idx] * w) + (squarewave[T10240][idx] * (1.0f - w)); | 360 | out = (sawtooth[T5120][idx] * w) + (sawtooth[T10240][idx] * (1.0f - w)); |
| 590 | } | 361 | } |
| 591 | else if (c->freq <= 20480.0f) | 362 | else if (c->freq <= 20480.0f) |
| 592 | { | 363 | { |
| 593 | w = ((20480.0f - c->freq) * INV_10240); | 364 | w = ((20480.0f - c->freq) * INV_10240); |
| 594 | out = (squarewave[T10240][idx] * w) + (squarewave[T20480][idx] * (1.0f - w)); | 365 | out = (sawtooth[T10240][idx] * w) + (sawtooth[T20480][idx] * (1.0f - w)); |
| 595 | } | 366 | } |
| 596 | else | 367 | else |
| 597 | { | 368 | { |
| 598 | out = squarewave[T20480][idx]; | 369 | out = sawtooth[T20480][idx]; |
| 599 | } | 370 | } |
| 600 | 371 | ||
| 601 | return out; | 372 | return out; |
| 602 | } | 373 | } |
| 603 | 374 | ||
| 604 | void tSquareSampleRateChanged (tSquare* const c) | 375 | void tSawtoothSampleRateChanged (tSawtooth* const c) |
| 605 | { | 376 | { |
| 606 | c->inc = c->freq * leaf.invSampleRate; | 377 | c->inc = c->freq * leaf.invSampleRate; |
| 607 | } | 378 | } |
| 608 | 379 | ||
| 380 | //======================================================================== | ||
| 381 | /* Phasor */ | ||
| 382 | void tPhasorSampleRateChanged (tPhasor* const p) | ||
| 383 | { | ||
| 384 | p->inc = p->freq * leaf.invSampleRate; | ||
| 385 | }; | ||
| 386 | |||
| 387 | void tPhasor_init(tPhasor* const p) | ||
| 388 | { | ||
| 389 | p->phase = 0.0f; | ||
| 390 | p->inc = 0.0f; | ||
| 391 | } | ||
| 392 | |||
| 393 | void tPhasor_free(tPhasor* const p) | ||
| 394 | { | ||
| 395 | |||
| 396 | } | ||
| 397 | |||
| 398 | int tPhasor_setFreq(tPhasor* const p, float freq) | ||
| 399 | { | ||
| 400 | if (freq < 0.0f) freq = 0.0f; | ||
| 401 | |||
| 402 | p->freq = freq; | ||
| 403 | p->inc = freq * leaf.invSampleRate; | ||
| 404 | |||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | |||
| 408 | float tPhasor_tick(tPhasor* const p) | ||
| 409 | { | ||
| 410 | p->phase += p->inc; | ||
| 411 | |||
| 412 | if (p->phase >= 1.0f) p->phase -= 1.0f; | ||
| 413 | |||
| 414 | return p->phase; | ||
| 415 | } | ||
| 416 | |||
| 609 | /* Noise */ | 417 | /* Noise */ |
| 610 | void tNoise_init(tNoise* const n, NoiseType type) | 418 | void tNoise_init(tNoise* const n, NoiseType type) |
| 611 | { | 419 | { |
| @@ -636,3 +444,201 @@ float tNoise_tick(tNoise* const n) · 24 unmodified lines | |||
| 636 | return rand; | 444 | return rand; |
| 637 | } | 445 | } |
| 638 | } | 446 | } |
| 447 | |||
| 448 | //================================================================================= | ||
| 449 | /* Neuron */ | ||
| 450 | |||
| 451 | void tNeuronSampleRateChanged(tNeuron* n) | ||
| 452 | { | ||
| 453 | |||
| 454 | } | ||
| 455 | |||
| 456 | void tNeuron_init(tNeuron* const n) | ||
| 457 | { | ||
| 458 | tPoleZero_init(&n->f); | ||
| 459 | |||
| 460 | tPoleZero_setBlockZero(&n->f, 0.99f); | ||
| 461 | |||
| 462 | n->timeStep = 1.0f / 50.0f; | ||
| 463 | |||
| 464 | n->current = 0.0f; // 100.0f for sound | ||
| 465 | n->voltage = 0.0f; | ||
| 466 | |||
| 467 | n->mode = NeuronNormal; | ||
| 468 | |||
| 469 | n->P[0] = 0.0f; | ||
| 470 | n->P[1] = 0.0f; | ||
| 471 | n->P[2] = 1.0f; | ||
| 472 | |||
| 473 | n->V[0] = -12.0f; | ||
| 474 | n->V[1] = 115.0f; | ||
| 475 | n->V[2] = 10.613f; | ||
| 476 | |||
| 477 | n->gK = 36.0f; | ||
| 478 | n->gN = 120.0f; | ||
| 479 | n->gL = 0.3f; | ||
| 480 | n->C = 1.0f; | ||
| 481 | |||
| 482 | n->rate[2] = n->gL/n->C; | ||
| 483 | } | ||
| 484 | |||
| 485 | void tNeuron_free(tNeuron* const n) | ||
| 486 | { | ||
| 487 | tPoleZero_free(&n->f); | ||
| 488 | } | ||
| 489 | |||
| 490 | void tNeuron_reset(tNeuron* const n) | ||
| 491 | { | ||
| 492 | |||
| 493 | tPoleZero_setBlockZero(&n->f, 0.99f); | ||
| 494 | |||
| 495 | n->timeStep = 1.0f / 50.0f; | ||
| 496 | |||
| 497 | n->current = 0.0f; // 100.0f for sound | ||
| 498 | n->voltage = 0.0f; | ||
| 499 | |||
| 500 | n->mode = NeuronNormal; | ||
| 501 | |||
| 502 | n->P[0] = 0.0f; | ||
| 503 | n->P[1] = 0.0f; | ||
| 504 | n->P[2] = 1.0f; | ||
| 505 | |||
| 506 | n->V[0] = -12.0f; | ||
| 507 | n->V[1] = 115.0f; | ||
| 508 | n->V[2] = 10.613f; | ||
| 509 | |||
| 510 | n->gK = 36.0f; | ||
| 511 | n->gN = 120.0f; | ||
| 512 | n->gL = 0.3f; | ||
| 513 | n->C = 1.0f; | ||
| 514 | |||
| 515 | n->rate[2] = n->gL/n->C; | ||
| 516 | } | ||
| 517 | |||
| 518 | |||
| 519 | void tNeuron_setV1(tNeuron* const n, float V1) | ||
| 520 | { | ||
| 521 | n->V[0] = V1; | ||
| 522 | } | ||
| 523 | |||
| 524 | |||
| 525 | void tNeuron_setV2(tNeuron* const n, float V2) | ||
| 526 | { | ||
| 527 | n->V[1] = V2; | ||
| 528 | } | ||
| 529 | |||
| 530 | void tNeuron_setV3(tNeuron* const n, float V3) | ||
| 531 | { | ||
| 532 | n->V[2] = V3; | ||
| 533 | } | ||
| 534 | |||
| 535 | void tNeuron_setTimeStep(tNeuron* const n, float timeStep) | ||
| 536 | { | ||
| 537 | n->timeStep = timeStep; | ||
| 538 | } | ||
| 539 | |||
| 540 | void tNeuron_setK(tNeuron* const n, float K) | ||
| 541 | { | ||
| 542 | n->gK = K; | ||
| 543 | } | ||
| 544 | |||
| 545 | void tNeuron_setL(tNeuron* const n, float L) | ||
| 546 | { | ||
| 547 | n->gL = L; | ||
| 548 | n->rate[2] = n->gL/n->C; | ||
| 549 | } | ||
| 550 | |||
| 551 | void tNeuron_setN(tNeuron* const n, float N) | ||
| 552 | { | ||
| 553 | n->gN = N; | ||
| 554 | } | ||
| 555 | |||
| 556 | void tNeuron_setC(tNeuron* const n, float C) | ||
| 557 | { | ||
| 558 | n->C = C; | ||
| 559 | n->rate[2] = n->gL/n->C; | ||
| 560 | } | ||
| 561 | |||
| 562 | float tNeuron_tick(tNeuron* const n) | ||
| 563 | { | ||
| 564 | float output = 0.0f; | ||
| 565 | float voltage = n->voltage; | ||
| 566 | |||
| 567 | n->alpha[0] = (0.01f * (10.0f - voltage)) / (expf((10.0f - voltage)/10.0f) - 1.0f); | ||
| 568 | n->alpha[1] = (0.1f * (25.0f-voltage)) / (expf((25.0f-voltage)/10.0f) - 1.0f); | ||
| 569 | n->alpha[2] = (0.07f * expf((-1.0f * voltage)/20.0f)); | ||
| 570 | |||
| 571 | n->beta[0] = (0.125f * expf((-1.0f* voltage)/80.0f)); | ||
| 572 | n->beta[1] = (4.0f * expf((-1.0f * voltage)/18.0f)); | ||
| 573 | n->beta[2] = (1.0f / (expf((30.0f-voltage)/10.0f) + 1.0f)); | ||
| 574 | |||
| 575 | for (int i = 0; i < 3; i++) | ||
| 576 | { | ||
| 577 | n->P[i] = (n->alpha[i] * n->timeStep) + ((1.0f - ((n->alpha[i] + n->beta[i]) * n->timeStep)) * n->P[i]); | ||
| 578 | |||
| 579 | if (n->P[i] > 1.0f) n->P[i] = 0.0f; | ||
| 580 | else if (n->P[i] < -1.0f) n->P[i] = 0.0f; | ||
| 581 | } | ||
| 582 | // rate[0]= k ; rate[1] = Na ; rate[2] = l | ||
| 583 | n->rate[0] = ((n->gK * powf(n->P[0], 4.0f)) / n->C); | ||
| 584 | n->rate[1] = ((n->gN * powf(n->P[1], 3.0f) * n->P[2]) / n->C); | ||
| 585 | |||
| 586 | //calculate the final membrane voltage based on the computed variables | ||
| 587 | n->voltage = voltage + | ||
| 588 | (n->timeStep * n->current / n->C) - | ||
| 589 | (n->timeStep * ( n->rate[0] * (voltage - n->V[0]) + n->rate[1] * (voltage - n->V[1]) + n->rate[2] * (voltage - n->V[2]))); | ||
| 590 | |||
| 591 | if (n->mode == NeuronTanh) | ||
| 592 | { | ||
| 593 | n->voltage = 100.0f * tanhf(0.01f * n->voltage); | ||
| 594 | } | ||
| 595 | else if (n->mode == NeuronAaltoShaper) | ||
| 596 | { | ||
| 597 | float shapeVoltage = 0.01f * n->voltage; | ||
| 598 | |||
| 599 | float w, c, xc, xc2, xc4; | ||
| 600 | |||
| 601 | float sqrt8 = 2.82842712475f; | ||
| 602 | |||
| 603 | float wscale = 1.30612244898f; | ||
| 604 | float m_drive = 1.0f; | ||
| 605 | |||
| 606 | xc = LEAF_clip(-sqrt8, shapeVoltage, sqrt8); | ||
| 607 | |||
| 608 | xc2 = xc*xc; | ||
| 609 | |||
| 610 | c = 0.5f * shapeVoltage * (3.0f - (xc2)); | ||
| 611 | |||
| 612 | xc4 = xc2 * xc2; | ||
| 613 | |||
| 614 | w = (1.0f - xc2 * 0.25f + xc4 * 0.015625f) * wscale; | ||
| 615 | |||
| 616 | shapeVoltage = w * (c + 0.05f * xc2) * (m_drive + 0.75f); | ||
| 617 | |||
| 618 | n->voltage = 100.0f * shapeVoltage; | ||
| 619 | } | ||
| 620 | |||
| 621 | |||
| 622 | if (n->voltage > 100.0f) n->voltage = 100.0f; | ||
| 623 | else if (n->voltage < -100.) n->voltage = -100.0f; | ||
| 624 | |||
| 625 | //(inputCurrent + (voltage - ((voltage * timeStep) / timeConstant)) + P[0] + P[1] + P[2]) => voltage; | ||
| 626 | // now we should have a result | ||
| 627 | //set the output voltage to the "step" ugen, which controls the DAC. | ||
| 628 | output = n->voltage * 0.01f; // volts | ||
| 629 | |||
| 630 | output = tPoleZero_tick(&n->f, output); | ||
| 631 | |||
| 632 | return output; | ||
| 633 | |||
| 634 | } | ||
| 635 | |||
| 636 | void tNeuron_setMode (tNeuron* const n, NeuronMode mode) | ||
| 637 | { | ||
| 638 | n->mode = mode; | ||
| 639 | } | ||
| 640 | |||
| 641 | void tNeuron_setCurrent (tNeuron* const n, float current) | ||
| 642 | { | ||
| 643 | n->current = current; | ||
| 644 | } | ||
| @@ -0,0 +1,596 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-string.c | ||
| 4 | Created: 30 Nov 2018 10:41:42am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-physical.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include "../Inc/leaf-physical.h" | ||
| 16 | |||
| 17 | #endif | ||
| 18 | |||
| 19 | /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tPluck ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | ||
| 20 | void tPluck_init (tPluck* const p, float lowestFrequency) | ||
| 21 | { | ||
| 22 | if ( lowestFrequency <= 0.0f ) lowestFrequency = 10.0f; | ||
| 23 | |||
| 24 | tNoise_init(&p->noise, WhiteNoise); | ||
| 25 | |||
| 26 | tOnePole_init(&p->pickFilter, 0.0f); | ||
| 27 | |||
| 28 | tOneZero_init(&p->loopFilter, 0.0f); | ||
| 29 | |||
| 30 | tAllpassDelay_init(&p->delayLine, 0.0f, leaf.sampleRate * 2); | ||
| 31 | |||
| 32 | tPluck_setFrequency(p, 220.0f); | ||
| 33 | } | ||
| 34 | |||
| 35 | void tPluck_free (tPluck* const p) | ||
| 36 | { | ||
| 37 | tNoise_free(&p->noise); | ||
| 38 | tOnePole_free(&p->pickFilter); | ||
| 39 | tOneZero_free(&p->loopFilter); | ||
| 40 | tAllpassDelay_free(&p->delayLine); | ||
| 41 | } | ||
| 42 | |||
| 43 | float tPluck_getLastOut (tPluck *p) | ||
| 44 | { | ||
| 45 | return p->lastOut; | ||
| 46 | } | ||
| 47 | |||
| 48 | float tPluck_tick (tPluck *p) | ||
| 49 | { | ||
| 50 | return (p->lastOut = 3.0f * tAllpassDelay_tick(&p->delayLine, tOneZero_tick(&p->loopFilter, tAllpassDelay_getLastOut(&p->delayLine) * p->loopGain ) )); | ||
| 51 | } | ||
| 52 | |||
| 53 | void tPluck_pluck (tPluck* const p, float amplitude) | ||
| 54 | { | ||
| 55 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 56 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 57 | |||
| 58 | tOnePole_setPole(&p->pickFilter, 0.999f - (amplitude * 0.15f)); | ||
| 59 | tOnePole_setGain(&p->pickFilter, amplitude * 0.5f ); | ||
| 60 | |||
| 61 | // Fill delay with noise additively with current contents. | ||
| 62 | for ( uint32_t i = 0; i < (uint32_t)tAllpassDelay_getDelay(&p->delayLine); i++ ) | ||
| 63 | tAllpassDelay_tick(&p->delayLine, 0.6f * tAllpassDelay_getLastOut(&p->delayLine) + tOnePole_tick(&p->pickFilter, tNoise_tick(&p->noise) ) ); | ||
| 64 | } | ||
| 65 | |||
| 66 | // Start a note with the given frequency and amplitude.; | ||
| 67 | void tPluck_noteOn (tPluck* const p, float frequency, float amplitude ) | ||
| 68 | { | ||
| 69 | p->lastFreq = frequency; | ||
| 70 | tPluck_setFrequency( p, frequency ); | ||
| 71 | tPluck_pluck( p, amplitude ); | ||
| 72 | } | ||
| 73 | |||
| 74 | // Stop a note with the given amplitude (speed of decay). | ||
| 75 | void tPluck_noteOff (tPluck* const p, float amplitude ) | ||
| 76 | { | ||
| 77 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 78 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 79 | |||
| 80 | p->loopGain = 1.0f - amplitude; | ||
| 81 | } | ||
| 82 | |||
| 83 | // Set instrument parameters for a particular frequency. | ||
| 84 | void tPluck_setFrequency (tPluck* const p, float frequency ) | ||
| 85 | { | ||
| 86 | if ( frequency <= 0.0f ) frequency = 0.001f; | ||
| 87 | |||
| 88 | // Delay = length - filter delay. | ||
| 89 | float delay = ( leaf.sampleRate / frequency ) - tOneZero_getPhaseDelay(&p->loopFilter, frequency ); | ||
| 90 | |||
| 91 | tAllpassDelay_setDelay(&p->delayLine, delay ); | ||
| 92 | |||
| 93 | p->loopGain = 0.99f + (frequency * 0.000005f); | ||
| 94 | |||
| 95 | if ( p->loopGain >= 0.999f ) p->loopGain = 0.999f; | ||
| 96 | |||
| 97 | } | ||
| 98 | |||
| 99 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 100 | void tPluck_controlChange (tPluck* const p, int number, float value) | ||
| 101 | { | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | void tPluckSampleRateChanged(tPluck* const p) | ||
| 106 | { | ||
| 107 | //tPluckSetFrequency(p, p->lastFreq); | ||
| 108 | } | ||
| 109 | |||
| 110 | /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tKarplusStrong ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | ||
| 111 | void tKarplusStrong_init (tKarplusStrong* const p, float lowestFrequency) | ||
| 112 | { | ||
| 113 | if ( lowestFrequency <= 0.0f ) lowestFrequency = 8.0f; | ||
| 114 | |||
| 115 | tAllpassDelay_init(&p->delayLine, 0.0f, leaf.sampleRate * 2); | ||
| 116 | |||
| 117 | tLinearDelay_init(&p->combDelay, 0.0f, leaf.sampleRate * 2); | ||
| 118 | |||
| 119 | tOneZero_init(&p->filter, 0.0f); | ||
| 120 | |||
| 121 | tNoise_init(&p->noise, WhiteNoise); | ||
| 122 | |||
| 123 | for (int i = 0; i < 4; i++) | ||
| 124 | { | ||
| 125 | tBiQuad_init(&p->biquad[i]); | ||
| 126 | } | ||
| 127 | |||
| 128 | p->pluckAmplitude = 0.3f; | ||
| 129 | p->pickupPosition = 0.4f; | ||
| 130 | |||
| 131 | p->stretching = 0.9999f; | ||
| 132 | p->baseLoopGain = 0.995f; | ||
| 133 | p->loopGain = 0.999f; | ||
| 134 | |||
| 135 | tKarplusStrong_setFrequency( p, 220.0f ); | ||
| 136 | |||
| 137 | } | ||
| 138 | |||
| 139 | void tKarplusStrong_free (tKarplusStrong* const p) | ||
| 140 | { | ||
| 141 | tAllpassDelay_free(&p->delayLine); | ||
| 142 | tLinearDelay_free(&p->combDelay); | ||
| 143 | tOneZero_free(&p->filter); | ||
| 144 | tNoise_free(&p->noise); | ||
| 145 | |||
| 146 | for (int i = 0; i < 4; i++) | ||
| 147 | { | ||
| 148 | tBiQuad_free(&p->biquad[i]); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | float tKarplusStrong_getLastOut (tKarplusStrong* const p) | ||
| 153 | { | ||
| 154 | return p->lastOut; | ||
| 155 | } | ||
| 156 | |||
| 157 | float tKarplusStrong_tick (tKarplusStrong* const p) | ||
| 158 | { | ||
| 159 | float temp = tAllpassDelay_getLastOut(&p->delayLine) * p->loopGain; | ||
| 160 | |||
| 161 | // Calculate allpass stretching. | ||
| 162 | for (int i=0; i<4; i++) temp = tBiQuad_tick(&p->biquad[i],temp); | ||
| 163 | |||
| 164 | // Moving average filter. | ||
| 165 | temp = tOneZero_tick(&p->filter, temp); | ||
| 166 | |||
| 167 | float out = tAllpassDelay_tick(&p->delayLine, temp); | ||
| 168 | out = out - tLinearDelay_tick(&p->combDelay, out); | ||
| 169 | p->lastOut = out; | ||
| 170 | |||
| 171 | return p->lastOut; | ||
| 172 | } | ||
| 173 | |||
| 174 | void tKarplusStrong_pluck (tKarplusStrong* const p, float amplitude) | ||
| 175 | { | ||
| 176 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 177 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 178 | |||
| 179 | p->pluckAmplitude = amplitude; | ||
| 180 | |||
| 181 | for ( uint32_t i=0; i < (uint32_t)tAllpassDelay_getDelay(&p->delayLine); i++ ) | ||
| 182 | { | ||
| 183 | // Fill delay with noise additively with current contents. | ||
| 184 | tAllpassDelay_tick(&p->delayLine, (tAllpassDelay_getLastOut(&p->delayLine) * 0.6f) + 0.4f * tNoise_tick(&p->noise) * p->pluckAmplitude ); | ||
| 185 | //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) ); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | // Start a note with the given frequency and amplitude.; | ||
| 190 | void tKarplusStrong_noteOn (tKarplusStrong* const p, float frequency, float amplitude ) | ||
| 191 | { | ||
| 192 | tKarplusStrong_setFrequency( p, frequency ); | ||
| 193 | tKarplusStrong_pluck( p, amplitude ); | ||
| 194 | } | ||
| 195 | |||
| 196 | // Stop a note with the given amplitude (speed of decay). | ||
| 197 | void tKarplusStrong_noteOff (tKarplusStrong* const p, float amplitude ) | ||
| 198 | { | ||
| 199 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 200 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 201 | |||
| 202 | p->loopGain = 1.0f - amplitude; | ||
| 203 | } | ||
| 204 | |||
| 205 | // Set instrument parameters for a particular frequency. | ||
| 206 | void tKarplusStrong_setFrequency (tKarplusStrong* const p, float frequency ) | ||
| 207 | { | ||
| 208 | if ( frequency <= 0.0f ) frequency = 0.001f; | ||
| 209 | |||
| 210 | p->lastFrequency = frequency; | ||
| 211 | p->lastLength = leaf.sampleRate / p->lastFrequency; | ||
| 212 | float delay = p->lastLength - 0.5f; | ||
| 213 | tAllpassDelay_setDelay(&p->delayLine, delay); | ||
| 214 | |||
| 215 | // MAYBE MODIFY LOOP GAINS | ||
| 216 | p->loopGain = p->baseLoopGain + (frequency * 0.000005f); | ||
| 217 | if (p->loopGain >= 1.0f) p->loopGain = 0.99999f; | ||
| 218 | |||
| 219 | tKarplusStrong_setStretch(p, p->stretching); | ||
| 220 | |||
| 221 | tLinearDelay_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength ); | ||
| 222 | |||
| 223 | } | ||
| 224 | |||
| 225 | // Set the stretch "factor" of the string (0.0 - 1.0). | ||
| 226 | void tKarplusStrong_setStretch (tKarplusStrong* const p, float stretch ) | ||
| 227 | { | ||
| 228 | p->stretching = stretch; | ||
| 229 | float coefficient; | ||
| 230 | float freq = p->lastFrequency * 2.0f; | ||
| 231 | float dFreq = ( (0.5f * leaf.sampleRate) - freq ) * 0.25f; | ||
| 232 | float temp = 0.5f + (stretch * 0.5f); | ||
| 233 | if ( temp > 0.9999f ) temp = 0.9999f; | ||
| 234 | |||
| 235 | for ( int i=0; i<4; i++ ) | ||
| 236 | { | ||
| 237 | coefficient = temp * temp; | ||
| 238 | tBiQuad_setA2(&p->biquad[i], coefficient); | ||
| 239 | tBiQuad_setB0(&p->biquad[i], coefficient); | ||
| 240 | tBiQuad_setB2(&p->biquad[i], 1.0f); | ||
| 241 | |||
| 242 | coefficient = -2.0f * temp * cos(TWO_PI * freq / leaf.sampleRate); | ||
| 243 | tBiQuad_setA1(&p->biquad[i], coefficient); | ||
| 244 | tBiQuad_setB1(&p->biquad[i], coefficient); | ||
| 245 | |||
| 246 | freq += dFreq; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | // Set the pluck or "excitation" position along the string (0.0 - 1.0). | ||
| 251 | void tKarplusStrong_setPickupPosition (tKarplusStrong* const p, float position ) | ||
| 252 | { | ||
| 253 | if (position < 0.0f) p->pickupPosition = 0.0f; | ||
| 254 | else if (position <= 1.0f) p->pickupPosition = position; | ||
| 255 | else p->pickupPosition = 1.0f; | ||
| 256 | |||
| 257 | tLinearDelay_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength); | ||
| 258 | } | ||
| 259 | |||
| 260 | // Set the base loop gain. | ||
| 261 | void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const p, float aGain ) | ||
| 262 | { | ||
| 263 | p->baseLoopGain = aGain; | ||
| 264 | p->loopGain = p->baseLoopGain + (p->lastFrequency * 0.000005f); | ||
| 265 | if ( p->loopGain > 0.99999f ) p->loopGain = 0.99999f; | ||
| 266 | } | ||
| 267 | |||
| 268 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 269 | void tKarplusStrong_controlChange (tKarplusStrong* const p, SKControlType type, float value) | ||
| 270 | { | ||
| 271 | if ( value < 0.0f ) value = 0.0f; | ||
| 272 | else if (value > 128.0f) value = 128.0f; | ||
| 273 | |||
| 274 | float normalizedValue = value * INV_128; | ||
| 275 | |||
| 276 | if (type == SKPickPosition) // 4 | ||
| 277 | tKarplusStrong_setPickupPosition( p, normalizedValue ); | ||
| 278 | else if (type == SKStringDamping) // 11 | ||
| 279 | tKarplusStrong_setBaseLoopGain( p, 0.97f + (normalizedValue * 0.03f) ); | ||
| 280 | else if (type == SKDetune) // 1 | ||
| 281 | tKarplusStrong_setStretch( p, 0.91f + (0.09f * (1.0f - normalizedValue)) ); | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | void tKarplusStrongSampleRateChanged (tKarplusStrong* const c) | ||
| 286 | { | ||
| 287 | tKarplusStrong_setFrequency(c, c->lastFrequency); | ||
| 288 | tKarplusStrong_setStretch(c, c->stretching); | ||
| 289 | } | ||
| 290 | |||
| 291 | /* Simple Living String*/ | ||
| 292 | |||
| 293 | void tSimpleLivingString_init(tSimpleLivingString* const p, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode) | ||
| 294 | { | ||
| 295 | p->curr=0.0f; | ||
| 296 | tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions) | ||
| 297 | tSimpleLivingString_setFreq(p, freq); | ||
| 298 | tLinearDelay_init(&p->delayLine,p->waveLengthInSamples, 2400); | ||
| 299 | tOnePole_init(&p->bridgeFilter, dampFreq); | ||
| 300 | tHighpass_init(&p->DCblocker,13); | ||
| 301 | p->decay=decay; | ||
| 302 | tFeedbackLeveler_init(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode); | ||
| 303 | p->levMode=levMode; | ||
| 304 | } | ||
| 305 | |||
| 306 | void tSimpleLivingString_free(tSimpleLivingString* const p) | ||
| 307 | { | ||
| 308 | tExpSmooth_free(&p->wlSmooth); | ||
| 309 | tLinearDelay_free(&p->delayLine); | ||
| 310 | tOnePole_free(&p->bridgeFilter); | ||
| 311 | tHighpass_free(&p->DCblocker); | ||
| 312 | tFeedbackLeveler_free(&p->fbLev); | ||
| 313 | } | ||
| 314 | |||
| 315 | int tSimpleLivingString_setFreq(tSimpleLivingString* const p, float freq) | ||
| 316 | { | ||
| 317 | if (freq<20) freq=20; | ||
| 318 | else if (freq>10000) freq=10000; | ||
| 319 | p->waveLengthInSamples = leaf.sampleRate/freq; | ||
| 320 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | int tSimpleLivingString_setWaveLength(tSimpleLivingString* const p, float waveLength) | ||
| 325 | { | ||
| 326 | if (waveLength<4.8) waveLength=4.8; | ||
| 327 | else if (waveLength>2400) waveLength=2400; | ||
| 328 | p->waveLengthInSamples = waveLength; | ||
| 329 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | int tSimpleLivingString_setDampFreq(tSimpleLivingString* const p, float dampFreq) | ||
| 334 | { | ||
| 335 | tOnePole_setFreq(&p->bridgeFilter, dampFreq); | ||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | int tSimpleLivingString_setDecay(tSimpleLivingString* const p, float decay) | ||
| 340 | { | ||
| 341 | p->decay=decay; | ||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | int tSimpleLivingString_setTargetLev(tSimpleLivingString* const p, float targetLev) | ||
| 346 | { | ||
| 347 | tFeedbackLeveler_setTargetLevel(&p->fbLev, targetLev); | ||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | int tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor) | ||
| 352 | { | ||
| 353 | tFeedbackLeveler_setFactor(&p->fbLev, levSmoothFactor); | ||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | int tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength) | ||
| 358 | { | ||
| 359 | tFeedbackLeveler_setStrength(&p->fbLev, levStrength); | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | int tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode) | ||
| 364 | { | ||
| 365 | tFeedbackLeveler_setMode(&p->fbLev, levMode); | ||
| 366 | p->levMode=levMode; | ||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | float tSimpleLivingString_tick(tSimpleLivingString* const p, float input) | ||
| 371 | { | ||
| 372 | float stringOut=tOnePole_tick(&p->bridgeFilter,tLinearDelay_tickOut(&p->delayLine)); | ||
| 373 | float stringInput=tHighpass_tick(&p->DCblocker, tFeedbackLeveler_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input)); | ||
| 374 | tLinearDelay_tickIn(&p->delayLine, stringInput); | ||
| 375 | tLinearDelay_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth)); | ||
| 376 | p->curr = stringOut; | ||
| 377 | return p->curr; | ||
| 378 | } | ||
| 379 | |||
| 380 | float tSimpleLivingString_sample(tSimpleLivingString* const p) | ||
| 381 | { | ||
| 382 | return p->curr; | ||
| 383 | } | ||
| 384 | |||
| 385 | /* Living String*/ | ||
| 386 | |||
| 387 | void tLivingString_init(tLivingString* const p, float freq, float pickPos, float prepIndex, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode) | ||
| 388 | { | ||
| 389 | p->curr=0.0f; | ||
| 390 | tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions) | ||
| 391 | tLivingString_setFreq(p, freq); | ||
| 392 | tExpSmooth_init(&p->ppSmooth, pickPos, 0.01); // smoother for pick position | ||
| 393 | tLivingString_setPickPos(p, pickPos); | ||
| 394 | p->prepIndex=prepIndex; | ||
| 395 | tLinearDelay_init(&p->delLF,p->waveLengthInSamples, 2400); | ||
| 396 | tLinearDelay_init(&p->delUF,p->waveLengthInSamples, 2400); | ||
| 397 | tLinearDelay_init(&p->delUB,p->waveLengthInSamples, 2400); | ||
| 398 | tLinearDelay_init(&p->delLB,p->waveLengthInSamples, 2400); | ||
| 399 | tOnePole_init(&p->bridgeFilter, dampFreq); | ||
| 400 | tOnePole_init(&p->nutFilter, dampFreq); | ||
| 401 | tOnePole_init(&p->prepFilterU, dampFreq); | ||
| 402 | tOnePole_init(&p->prepFilterL, dampFreq); | ||
| 403 | tHighpass_init(&p->DCblockerU,13); | ||
| 404 | tHighpass_init(&p->DCblockerL,13); | ||
| 405 | p->decay=decay; | ||
| 406 | tFeedbackLeveler_init(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode); | ||
| 407 | tFeedbackLeveler_init(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode); | ||
| 408 | p->levMode=levMode; | ||
| 409 | } | ||
| 410 | |||
| 411 | void tLivingString_free(tLivingString* const p) | ||
| 412 | { | ||
| 413 | tExpSmooth_free(&p->wlSmooth); | ||
| 414 | tExpSmooth_free(&p->ppSmooth); | ||
| 415 | tLinearDelay_free(&p->delLF); | ||
| 416 | tLinearDelay_free(&p->delUF); | ||
| 417 | tLinearDelay_free(&p->delUB); | ||
| 418 | tLinearDelay_free(&p->delLB); | ||
| 419 | tOnePole_free(&p->bridgeFilter); | ||
| 420 | tOnePole_free(&p->nutFilter); | ||
| 421 | tOnePole_free(&p->prepFilterU); | ||
| 422 | tOnePole_free(&p->prepFilterL); | ||
| 423 | tHighpass_free(&p->DCblockerU); | ||
| 424 | tHighpass_free(&p->DCblockerL); | ||
| 425 | tFeedbackLeveler_free(&p->fbLevU); | ||
| 426 | tFeedbackLeveler_free(&p->fbLevL); | ||
| 427 | } | ||
| 428 | |||
| 429 | int tLivingString_setFreq(tLivingString* const p, float freq) | ||
| 430 | { // NOTE: It is faster to set wavelength in samples directly | ||
| 431 | if (freq<20) freq=20; | ||
| 432 | else if (freq>10000) freq=10000; | ||
| 433 | p->waveLengthInSamples = leaf.sampleRate/freq; | ||
| 434 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | int tLivingString_setWaveLength(tLivingString* const p, float waveLength) | ||
| 439 | { | ||
| 440 | if (waveLength<4.8) waveLength=4.8; | ||
| 441 | else if (waveLength>2400) waveLength=2400; | ||
| 442 | p->waveLengthInSamples = waveLength; | ||
| 443 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | |||
| 447 | int tLivingString_setPickPos(tLivingString* const p, float pickPos) | ||
| 448 | { // between 0 and 1 | ||
| 449 | if (pickPos<0.f) pickPos=0.f; | ||
| 450 | else if (pickPos>1.f) pickPos=1.f; | ||
| 451 | p->pickPos = pickPos; | ||
| 452 | tExpSmooth_setDest(&p->ppSmooth, p->pickPos); | ||
| 453 | return 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | int tLivingString_setPrepIndex(tLivingString* const p, float prepIndex) | ||
| 457 | { // between 0 and 1 | ||
| 458 | if (prepIndex<0.f) prepIndex=0.f; | ||
| 459 | else if (prepIndex>1.f) prepIndex=1.f; | ||
| 460 | p->prepIndex = prepIndex; | ||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | int tLivingString_setDampFreq(tLivingString* const p, float dampFreq) | ||
| 465 | { | ||
| 466 | tOnePole_setFreq(&p->bridgeFilter, dampFreq); | ||
| 467 | tOnePole_setFreq(&p->nutFilter, dampFreq); | ||
| 468 | tOnePole_setFreq(&p->prepFilterU, dampFreq); | ||
| 469 | tOnePole_setFreq(&p->prepFilterL, dampFreq); | ||
| 470 | return 0; | ||
| 471 | } | ||
| 472 | |||
| 473 | int tLivingString_setDecay(tLivingString* const p, float decay) | ||
| 474 | { | ||
| 475 | p->decay=decay; | ||
| 476 | return 0; | ||
| 477 | } | ||
| 478 | |||
| 479 | int tLivingString_setTargetLev(tLivingString* const p, float targetLev) | ||
| 480 | { | ||
| 481 | tFeedbackLeveler_setTargetLevel(&p->fbLevU, targetLev); | ||
| 482 | tFeedbackLeveler_setTargetLevel(&p->fbLevL, targetLev); | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | int tLivingString_setLevSmoothFactor(tLivingString* const p, float levSmoothFactor) | ||
| 487 | { | ||
| 488 | tFeedbackLeveler_setFactor(&p->fbLevU, levSmoothFactor); | ||
| 489 | tFeedbackLeveler_setFactor(&p->fbLevL, levSmoothFactor); | ||
| 490 | return 0; | ||
| 491 | } | ||
| 492 | |||
| 493 | int tLivingString_setLevStrength(tLivingString* const p, float levStrength) | ||
| 494 | { | ||
| 495 | tFeedbackLeveler_setStrength(&p->fbLevU, levStrength); | ||
| 496 | tFeedbackLeveler_setStrength(&p->fbLevL, levStrength); | ||
| 497 | return 0; | ||
| 498 | } | ||
| 499 | |||
| 500 | int tLivingString_setLevMode(tLivingString* const p, int levMode) | ||
| 501 | { | ||
| 502 | tFeedbackLeveler_setMode(&p->fbLevU, levMode); | ||
| 503 | tFeedbackLeveler_setMode(&p->fbLevL, levMode); | ||
| 504 | p->levMode=levMode; | ||
| 505 | return 0; | ||
| 506 | } | ||
| 507 | |||
| 508 | float tLivingString_tick(tLivingString* const p, float input) | ||
| 509 | { | ||
| 510 | // from pickPos upwards=forwards | ||
| 511 | float fromLF=tLinearDelay_tickOut(&p->delLF); | ||
| 512 | float fromUF=tLinearDelay_tickOut(&p->delUF); | ||
| 513 | float fromUB=tLinearDelay_tickOut(&p->delUB); | ||
| 514 | float fromLB=tLinearDelay_tickOut(&p->delLB); | ||
| 515 | // into upper half of string, from nut, going backwards | ||
| 516 | float fromNut=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->nutFilter, fromUF))); | ||
| 517 | tLinearDelay_tickIn(&p->delUB, fromNut); | ||
| 518 | // into lower half of string, from pickpoint, going backwards | ||
| 519 | float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF); | ||
| 520 | float intoLower=p->prepIndex*fromLowerPrep+(1-p->prepIndex)*fromUB+input; | ||
| 521 | tLinearDelay_tickIn(&p->delLB, intoLower); | ||
| 522 | // into lower half of string, from bridge | ||
| 523 | float fromBridge=-tFeedbackLeveler_tick(&p->fbLevL, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->bridgeFilter, fromLB))); | ||
| 524 | tLinearDelay_tickIn(&p->delLF, fromBridge); | ||
| 525 | // into upper half of string, from pickpoint, going forwards/upwards | ||
| 526 | float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB); | ||
| 527 | float intoUpper=p->prepIndex*fromUpperPrep+(1-p->prepIndex)*fromLF+input; | ||
| 528 | tLinearDelay_tickIn(&p->delUF, intoUpper); | ||
| 529 | // update all delay lengths | ||
| 530 | float pickP=tExpSmooth_tick(&p->ppSmooth); | ||
| 531 | float wLen=tExpSmooth_tick(&p->wlSmooth); | ||
| 532 | float lowLen=pickP*wLen; | ||
| 533 | float upLen=(1-pickP)*wLen; | ||
| 534 | tLinearDelay_setDelay(&p->delLF, lowLen); | ||
| 535 | tLinearDelay_setDelay(&p->delLB, lowLen); | ||
| 536 | tLinearDelay_setDelay(&p->delUF, upLen); | ||
| 537 | tLinearDelay_setDelay(&p->delUB, upLen); | ||
| 538 | p->curr = fromBridge; | ||
| 539 | return p->curr; | ||
| 540 | } | ||
| 541 | |||
| 542 | float tLivingString_sample(tLivingString* const p) | ||
| 543 | { | ||
| 544 | return p->curr; | ||
| 545 | } | ||
| 546 | |||
| 547 | ///Reed Table model | ||
| 548 | //default values from STK are 0.6 offset and -0.8 slope | ||
| 549 | |||
| 550 | void tReedTable_init (tReedTable* const p, float offset, float slope) | ||
| 551 | { | ||
| 552 | p->offset = offset; | ||
| 553 | p->slope = slope; | ||
| 554 | } | ||
| 555 | |||
| 556 | void tReedTable_free (tReedTable* const p) | ||
| 557 | { | ||
| 558 | ; | ||
| 559 | } | ||
| 560 | |||
| 561 | float tReedTable_tick (tReedTable* const p, float input) | ||
| 562 | { | ||
| 563 | // The input is differential pressure across the reed. | ||
| 564 | float output = p->offset + (p->slope * input); | ||
| 565 | |||
| 566 | // If output is > 1, the reed has slammed shut and the | ||
| 567 | // reflection function value saturates at 1.0. | ||
| 568 | if ( output > 1.0f) output = 1.0f; | ||
| 569 | |||
| 570 | // This is nearly impossible in a physical system, but | ||
| 571 | // a reflection function value of -1.0 corresponds to | ||
| 572 | // an open end (and no discontinuity in bore profile). | ||
| 573 | if ( output < -1.0f) output = -1.0f; | ||
| 574 | |||
| 575 | return output; | ||
| 576 | } | ||
| 577 | |||
| 578 | float tReedTable_tanh_tick (tReedTable* const p, float input) | ||
| 579 | { | ||
| 580 | // The input is differential pressure across the reed. | ||
| 581 | float output = p->offset + (p->slope * input); | ||
| 582 | |||
| 583 | // If output is > 1, the reed has slammed shut and the | ||
| 584 | // reflection function value saturates at 1.0. | ||
| 585 | return tanhf(output); | ||
| 586 | } | ||
| 587 | |||
| 588 | void tReedTable_setOffset (tReedTable* const p, float offset) | ||
| 589 | { | ||
| 590 | p->offset = offset; | ||
| 591 | } | ||
| 592 | |||
| 593 | void tReedTable_setSlope (tReedTable* const p, float slope) | ||
| 594 | { | ||
| 595 | p->slope = slope; | ||
| 596 | } | ||
| @@ -1,563 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-pitch.c | ||
| 4 | Created: 30 Nov 2018 11:02:59am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-pitch.h" | ||
| 12 | #else | ||
| 13 | |||
| 14 | #include "../Inc/leaf-pitch.h" | ||
| 15 | |||
| 16 | #endif | ||
| 17 | |||
| 18 | static int pitchshifter_attackdetect(tPitchShifter* ps); | ||
| 19 | |||
| 20 | void tPitchShifter_init(tPitchShifter* const ps, float* in, float* out, int bufSize, int frameSize) | ||
| 21 | { | ||
| 22 | ps->inBuffer = in; | ||
| 23 | ps->outBuffer = out; | ||
| 24 | ps->bufSize = bufSize; | ||
| 25 | ps->frameSize = frameSize; | ||
| 26 | ps->framesPerBuffer = ps->bufSize / ps->frameSize; | ||
| 27 | ps->curBlock = 1; | ||
| 28 | ps->lastBlock = 0; | ||
| 29 | ps->index = 0; | ||
| 30 | |||
| 31 | ps->hopSize = DEFHOPSIZE; | ||
| 32 | ps->windowSize = DEFWINDOWSIZE; | ||
| 33 | ps->fba = FBA; | ||
| 34 | |||
| 35 | tEnv_init(&ps->env, ps->windowSize, ps->hopSize, ps->frameSize); | ||
| 36 | |||
| 37 | tSNAC_init(&ps->snac, DEFOVERLAP); | ||
| 38 | |||
| 39 | tSOLAD_init(&ps->sola); | ||
| 40 | |||
| 41 | tHighpass_init(&ps->hp, HPFREQ); | ||
| 42 | |||
| 43 | tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO); | ||
| 44 | |||
| 45 | tPitchShifter_setTimeConstant(ps, DEFTIMECONSTANT); | ||
| 46 | } | ||
| 47 | |||
| 48 | void tPitchShifter_free(tPitchShifter* const ps) | ||
| 49 | { | ||
| 50 | tEnv_free(&ps->env); | ||
| 51 | tSNAC_free(&ps->snac); | ||
| 52 | tSOLAD_free(&ps->sola); | ||
| 53 | tHighpass_free(&ps->hp); | ||
| 54 | } | ||
| 55 | |||
| 56 | float tPitchShifter_tick(tPitchShifter* ps, float sample) | ||
| 57 | { | ||
| 58 | float period, out; | ||
| 59 | int i, iLast; | ||
| 60 | |||
| 61 | i = (ps->curBlock*ps->frameSize); | ||
| 62 | iLast = (ps->lastBlock*ps->frameSize)+ps->index; | ||
| 63 | |||
| 64 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 65 | ps->inBuffer[i+ps->index] = sample; | ||
| 66 | |||
| 67 | ps->index++; | ||
| 68 | if (ps->index >= ps->frameSize) | ||
| 69 | { | ||
| 70 | ps->index = 0; | ||
| 71 | |||
| 72 | tEnv_processBlock(&ps->env, &(ps->inBuffer[i])); | ||
| 73 | |||
| 74 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 75 | { | ||
| 76 | ps->fba = 5; | ||
| 77 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 78 | } | ||
| 79 | |||
| 80 | tSNAC_ioSamples(&ps->snac, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 81 | period = tSNAC_getPeriod(&ps->snac); | ||
| 82 | |||
| 83 | ps->curBlock++; | ||
| 84 | if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0; | ||
| 85 | ps->lastBlock++; | ||
| 86 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 87 | |||
| 88 | //separate here | ||
| 89 | |||
| 90 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 91 | |||
| 92 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 93 | tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 94 | |||
| 95 | } | ||
| 96 | |||
| 97 | return out; | ||
| 98 | } | ||
| 99 | |||
| 100 | float tPitchShifterToFreq_tick(tPitchShifter* ps, float sample, float freq) | ||
| 101 | { | ||
| 102 | float period, out; | ||
| 103 | int i, iLast; | ||
| 104 | |||
| 105 | i = (ps->curBlock*ps->frameSize); | ||
| 106 | iLast = (ps->lastBlock*ps->frameSize)+ps->index; | ||
| 107 | |||
| 108 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 109 | ps->inBuffer[i+ps->index] = sample; | ||
| 110 | |||
| 111 | ps->index++; | ||
| 112 | if (ps->index >= ps->frameSize) | ||
| 113 | { | ||
| 114 | ps->index = 0; | ||
| 115 | |||
| 116 | tEnv_processBlock(&ps->env, &(ps->inBuffer[i])); | ||
| 117 | |||
| 118 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 119 | { | ||
| 120 | ps->fba = 5; | ||
| 121 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 122 | } | ||
| 123 | |||
| 124 | tSNAC_ioSamples(&ps->snac, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 125 | period = tSNAC_getPeriod(&ps->snac); | ||
| 126 | |||
| 127 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 128 | |||
| 129 | ps->pitchFactor = period*freq*leaf.invSampleRate; | ||
| 130 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 131 | tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 132 | |||
| 133 | ps->curBlock++; | ||
| 134 | if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0; | ||
| 135 | ps->lastBlock++; | ||
| 136 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | return out; | ||
| 140 | } | ||
| 141 | |||
| 142 | float tPitchShifterToFunc_tick(tPitchShifter* ps, float sample, float (*fun)(float)) | ||
| 143 | { | ||
| 144 | float period, out; | ||
| 145 | int i, iLast; | ||
| 146 | |||
| 147 | i = (ps->curBlock*ps->frameSize); | ||
| 148 | iLast = (ps->lastBlock*ps->frameSize)+ps->index; | ||
| 149 | |||
| 150 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 151 | ps->inBuffer[i+ps->index] = sample; | ||
| 152 | |||
| 153 | ps->index++; | ||
| 154 | if (ps->index >= ps->frameSize) | ||
| 155 | { | ||
| 156 | ps->index = 0; | ||
| 157 | |||
| 158 | tEnv_processBlock(&ps->env, &(ps->inBuffer[i])); | ||
| 159 | |||
| 160 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 161 | { | ||
| 162 | ps->fba = 5; | ||
| 163 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 164 | } | ||
| 165 | |||
| 166 | tSNAC_ioSamples(&ps->snac, (&ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 167 | period = tSNAC_getPeriod(&ps->snac); | ||
| 168 | |||
| 169 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 170 | |||
| 171 | ps->pitchFactor = period/fun(period); | ||
| 172 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 173 | tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 174 | |||
| 175 | ps->curBlock++; | ||
| 176 | if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0; | ||
| 177 | ps->lastBlock++; | ||
| 178 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | return out; | ||
| 182 | } | ||
| 183 | |||
| 184 | void tPitchShifter_ioSamples(tPitchShifter* ps, float* in, float* out, int size) | ||
| 185 | { | ||
| 186 | float period; | ||
| 187 | |||
| 188 | tEnv_processBlock(&ps->env, in); | ||
| 189 | |||
| 190 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 191 | { | ||
| 192 | ps->fba = 5; | ||
| 193 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 194 | } | ||
| 195 | |||
| 196 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 197 | period = tSNAC_getPeriod(&ps->snac); | ||
| 198 | |||
| 199 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 200 | |||
| 201 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 202 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 203 | |||
| 204 | for (int cc = 0; cc < size; ++cc) | ||
| 205 | { | ||
| 206 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | void tPitchShifter_ioSamples_toFreq(tPitchShifter* ps, float* in, float* out, int size, float toFreq) | ||
| 211 | { | ||
| 212 | float period; | ||
| 213 | |||
| 214 | tEnv_processBlock(&ps->env, in); | ||
| 215 | |||
| 216 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 217 | { | ||
| 218 | ps->fba = 5; | ||
| 219 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 220 | } | ||
| 221 | |||
| 222 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 223 | period = tSNAC_getPeriod(&ps->snac); | ||
| 224 | |||
| 225 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 226 | ps->pitchFactor = period*toFreq; | ||
| 227 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 228 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 229 | |||
| 230 | for (int cc = 0; cc < size; ++cc) | ||
| 231 | { | ||
| 232 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | void tPitchShifter_ioSamples_toPeriod(tPitchShifter* ps, float* in, float* out, int size, float toPeriod) | ||
| 237 | { | ||
| 238 | float period; | ||
| 239 | |||
| 240 | tEnv_processBlock(&ps->env, in); | ||
| 241 | |||
| 242 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 243 | { | ||
| 244 | ps->fba = 5; | ||
| 245 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 246 | } | ||
| 247 | |||
| 248 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 249 | period = tSNAC_getPeriod(&ps->snac); | ||
| 250 | |||
| 251 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 252 | ps->pitchFactor = period/toPeriod; | ||
| 253 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 254 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 255 | |||
| 256 | for (int cc = 0; cc < size; ++cc) | ||
| 257 | { | ||
| 258 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | void tPitchShifter_ioSamples_toFunc(tPitchShifter* ps, float* in, float* out, int size, float (*fun)(float)) | ||
| 263 | { | ||
| 264 | float period; | ||
| 265 | |||
| 266 | tEnv_processBlock(&ps->env, in); | ||
| 267 | |||
| 268 | if(pitchshifter_attackdetect(ps) == 1) | ||
| 269 | { | ||
| 270 | ps->fba = 5; | ||
| 271 | tSOLAD_setReadLag(&ps->sola, ps->windowSize); | ||
| 272 | } | ||
| 273 | |||
| 274 | tSNAC_ioSamples(&ps->snac, in, out, size); | ||
| 275 | period = tSNAC_getPeriod(&ps->snac); | ||
| 276 | |||
| 277 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 278 | ps->pitchFactor = period/fun(period); | ||
| 279 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 280 | tSOLAD_ioSamples(&ps->sola, in, out, size); | ||
| 281 | |||
| 282 | for (int cc = 0; cc < size; ++cc) | ||
| 283 | { | ||
| 284 | out[cc] = tHighpass_tick(&ps->hp, out[cc]); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf) | ||
| 289 | { | ||
| 290 | ps->pitchFactor = pf; | ||
| 291 | } | ||
| 292 | |||
| 293 | void tPitchShifter_setTimeConstant(tPitchShifter* ps, float tc) | ||
| 294 | { | ||
| 295 | ps->timeConstant = tc; | ||
| 296 | ps->radius = expf(-1000.0f * ps->hopSize * leaf.invSampleRate / ps->timeConstant); | ||
| 297 | } | ||
| 298 | |||
| 299 | void tPitchShifter_setHopSize(tPitchShifter* ps, int hs) | ||
| 300 | { | ||
| 301 | ps->hopSize = hs; | ||
| 302 | } | ||
| 303 | |||
| 304 | void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws) | ||
| 305 | { | ||
| 306 | ps->windowSize = ws; | ||
| 307 | } | ||
| 308 | |||
| 309 | float tPitchShifter_getPeriod(tPitchShifter* ps) | ||
| 310 | { | ||
| 311 | return tSNAC_getPeriod(&ps->snac); | ||
| 312 | } | ||
| 313 | |||
| 314 | static int pitchshifter_attackdetect(tPitchShifter* ps) | ||
| 315 | { | ||
| 316 | float envout; | ||
| 317 | |||
| 318 | envout = tEnv_tick(&ps->env); | ||
| 319 | |||
| 320 | if (envout >= 1.0f) | ||
| 321 | { | ||
| 322 | ps->lastmax = ps->max; | ||
| 323 | if (envout > ps->max) | ||
| 324 | { | ||
| 325 | ps->max = envout; | ||
| 326 | } | ||
| 327 | else | ||
| 328 | { | ||
| 329 | ps->deltamax = envout - ps->max; | ||
| 330 | ps->max = ps->max * ps->radius; | ||
| 331 | } | ||
| 332 | ps->deltamax = ps->max - ps->lastmax; | ||
| 333 | } | ||
| 334 | |||
| 335 | ps->fba = ps->fba ? (ps->fba - 1) : 0; | ||
| 336 | |||
| 337 | return (ps->fba == 0 && (ps->max > 60 && ps->deltamax > 6)) ? 1 : 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | void tPeriod_init (tPeriod* const p, float* in, float* out, int bufSize, int frameSize) | ||
| 342 | { | ||
| 343 | p->inBuffer = in; | ||
| 344 | p->outBuffer = out; | ||
| 345 | p->bufSize = bufSize; | ||
| 346 | p->frameSize = frameSize; | ||
| 347 | p->framesPerBuffer = p->bufSize / p->frameSize; | ||
| 348 | p->curBlock = 1; | ||
| 349 | p->lastBlock = 0; | ||
| 350 | p->index = 0; | ||
| 351 | |||
| 352 | p->hopSize = DEFHOPSIZE; | ||
| 353 | p->windowSize = DEFWINDOWSIZE; | ||
| 354 | p->fba = FBA; | ||
| 355 | |||
| 356 | tEnv_init(&p->env, p->windowSize, p->hopSize, p->frameSize); | ||
| 357 | |||
| 358 | tSNAC_init(&p->snac, DEFOVERLAP); | ||
| 359 | |||
| 360 | p->timeConstant = DEFTIMECONSTANT; | ||
| 361 | p->radius = expf(-1000.0f * p->hopSize * leaf.invSampleRate / p->timeConstant); | ||
| 362 | } | ||
| 363 | |||
| 364 | void tPeriod_free (tPeriod* const p) | ||
| 365 | { | ||
| 366 | tEnv_free(&p->env); | ||
| 367 | tSNAC_free(&p->snac); | ||
| 368 | } | ||
| 369 | |||
| 370 | float tPeriod_findPeriod (tPeriod* p, float sample) | ||
| 371 | { | ||
| 372 | int i, iLast; | ||
| 373 | |||
| 374 | i = (p->curBlock*p->frameSize); | ||
| 375 | iLast = (p->lastBlock*p->frameSize)+p->index; | ||
| 376 | |||
| 377 | p->i = i; | ||
| 378 | p->iLast = iLast; | ||
| 379 | |||
| 380 | p->inBuffer[i+p->index] = sample; | ||
| 381 | |||
| 382 | p->index++; | ||
| 383 | p->indexstore = p->index; | ||
| 384 | if (p->index >= p->frameSize) | ||
| 385 | { | ||
| 386 | p->index = 0; | ||
| 387 | |||
| 388 | tEnv_processBlock(&p->env, &(p->inBuffer[i])); | ||
| 389 | |||
| 390 | tSNAC_ioSamples(&p->snac, &(p->inBuffer[i]), &(p->outBuffer[i]), p->frameSize); | ||
| 391 | p->period = tSNAC_getPeriod(&p->snac); | ||
| 392 | |||
| 393 | p->curBlock++; | ||
| 394 | if (p->curBlock >= p->framesPerBuffer) p->curBlock = 0; | ||
| 395 | p->lastBlock++; | ||
| 396 | if (p->lastBlock >= p->framesPerBuffer) p->lastBlock = 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | // changed from period to p->period | ||
| 400 | return p->period; | ||
| 401 | } | ||
| 402 | |||
| 403 | void tPeriod_setHopSize(tPeriod* p, int hs) | ||
| 404 | { | ||
| 405 | p->hopSize = hs; | ||
| 406 | } | ||
| 407 | |||
| 408 | void tPeriod_setWindowSize(tPeriod* p, int ws) | ||
| 409 | { | ||
| 410 | p->windowSize = ws; | ||
| 411 | } | ||
| 412 | |||
| 413 | void tPitchShift_setPitchFactor(tPitchShift* ps, float pf) | ||
| 414 | { | ||
| 415 | ps->pitchFactor = pf; | ||
| 416 | } | ||
| 417 | |||
| 418 | static int pitchshift_attackdetect(tPitchShift* ps) | ||
| 419 | { | ||
| 420 | float envout; | ||
| 421 | |||
| 422 | envout = tEnv_tick(&ps->p->env); | ||
| 423 | |||
| 424 | if (envout >= 1.0f) | ||
| 425 | { | ||
| 426 | ps->p->lastmax = ps->p->max; | ||
| 427 | if (envout > ps->p->max) | ||
| 428 | { | ||
| 429 | ps->p->max = envout; | ||
| 430 | } | ||
| 431 | else | ||
| 432 | { | ||
| 433 | ps->p->deltamax = envout - ps->p->max; | ||
| 434 | ps->p->max = ps->p->max * ps->radius; | ||
| 435 | } | ||
| 436 | ps->p->deltamax = ps->p->max - ps->p->lastmax; | ||
| 437 | } | ||
| 438 | |||
| 439 | ps->p->fba = ps->p->fba ? (ps->p->fba - 1) : 0; | ||
| 440 | |||
| 441 | return (ps->p->fba == 0 && (ps->p->max > 60 && ps->p->deltamax > 6)) ? 1 : 0; | ||
| 442 | } | ||
| 443 | |||
| 444 | void tPitchShift_init (tPitchShift* const ps, tPeriod* p, float* out, int bufSize) | ||
| 445 | { | ||
| 446 | ps->p = p; | ||
| 447 | |||
| 448 | ps->outBuffer = out; | ||
| 449 | ps->bufSize = bufSize; | ||
| 450 | ps->frameSize = p->frameSize; | ||
| 451 | ps->framesPerBuffer = ps->bufSize / ps->frameSize; | ||
| 452 | ps->curBlock = 1; | ||
| 453 | ps->lastBlock = 0; | ||
| 454 | ps->index = 0; | ||
| 455 | ps->pitchFactor = 1.0f; | ||
| 456 | |||
| 457 | tSOLAD_init(&ps->sola); | ||
| 458 | |||
| 459 | tHighpass_init(&ps->hp, HPFREQ); | ||
| 460 | |||
| 461 | tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO); | ||
| 462 | } | ||
| 463 | |||
| 464 | void tPitchShift_free(tPitchShift* const ps) | ||
| 465 | { | ||
| 466 | tSOLAD_free(&ps->sola); | ||
| 467 | tHighpass_free(&ps->hp); | ||
| 468 | } | ||
| 469 | |||
| 470 | float tPitchShift_shift (tPitchShift* ps) | ||
| 471 | { | ||
| 472 | float period, out; | ||
| 473 | int i, iLast; | ||
| 474 | |||
| 475 | i = ps->p->i; | ||
| 476 | iLast = ps->p->iLast; | ||
| 477 | |||
| 478 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 479 | |||
| 480 | if (ps->p->indexstore >= ps->frameSize) | ||
| 481 | { | ||
| 482 | period = ps->p->period; | ||
| 483 | |||
| 484 | if(pitchshift_attackdetect(ps) == 1) | ||
| 485 | { | ||
| 486 | ps->p->fba = 5; | ||
| 487 | tSOLAD_setReadLag(&ps->sola, ps->p->windowSize); | ||
| 488 | } | ||
| 489 | |||
| 490 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 491 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 492 | |||
| 493 | tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 494 | } | ||
| 495 | |||
| 496 | return out; | ||
| 497 | } | ||
| 498 | |||
| 499 | float tPitchShift_shiftToFreq (tPitchShift* ps, float freq) | ||
| 500 | { | ||
| 501 | float period, out; | ||
| 502 | int i, iLast; | ||
| 503 | |||
| 504 | i = ps->p->i; | ||
| 505 | iLast = ps->p->iLast; | ||
| 506 | |||
| 507 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 508 | |||
| 509 | if (ps->p->indexstore >= ps->frameSize) | ||
| 510 | { | ||
| 511 | period = ps->p->period; | ||
| 512 | |||
| 513 | if(pitchshift_attackdetect(ps) == 1) | ||
| 514 | { | ||
| 515 | ps->p->fba = 5; | ||
| 516 | tSOLAD_setReadLag(&ps->sola, ps->p->windowSize); | ||
| 517 | } | ||
| 518 | |||
| 519 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 520 | |||
| 521 | ps->pitchFactor = period*freq*leaf.invSampleRate; | ||
| 522 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 523 | |||
| 524 | tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 525 | } | ||
| 526 | return out; | ||
| 527 | } | ||
| 528 | |||
| 529 | float tPitchShift_shiftToFunc (tPitchShift* ps, float (*fun)(float)) | ||
| 530 | { | ||
| 531 | float period, out; | ||
| 532 | int i, iLast; | ||
| 533 | |||
| 534 | i = ps->p->i; | ||
| 535 | iLast = ps->p->iLast; | ||
| 536 | |||
| 537 | out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]); | ||
| 538 | |||
| 539 | if (ps->p->indexstore >= ps->frameSize) | ||
| 540 | { | ||
| 541 | period = ps->p->period; | ||
| 542 | |||
| 543 | if(pitchshift_attackdetect(ps) == 1) | ||
| 544 | { | ||
| 545 | ps->p->fba = 5; | ||
| 546 | tSOLAD_setReadLag(&ps->sola, ps->p->windowSize); | ||
| 547 | } | ||
| 548 | |||
| 549 | tSOLAD_setPeriod(&ps->sola, period); | ||
| 550 | |||
| 551 | ps->pitchFactor = period/fun(period); | ||
| 552 | tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor); | ||
| 553 | |||
| 554 | tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize); | ||
| 555 | |||
| 556 | ps->curBlock++; | ||
| 557 | if (ps->curBlock >= ps->p->framesPerBuffer) ps->curBlock = 0; | ||
| 558 | ps->lastBlock++; | ||
| 559 | if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0; | ||
| 560 | } | ||
| 561 | |||
| 562 | return out; | ||
| 563 | } | ||
| @@ -18,8 +18,8 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | #endif | 19 | #endif |
| 20 | 20 | ||
| 21 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | 21 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // |
| 22 | void tPRCRev_init(tPRCRev* const r, float t60) | 22 | void tPRCReverb_init(tPRCReverb* const r, float t60) |
| 23 | { | 23 | { |
| 24 | if (t60 <= 0.0f) t60 = 0.001f; | 24 | if (t60 <= 0.0f) t60 = 0.001f; |
| 25 | 25 | ||
| @@ -47,20 +47,20 @@ void tPRCRev_init(tPRCRev* const r, float t60) · 21 unmodified lines | |||
| 47 | tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2); | 47 | tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2); |
| 48 | tDelay_init(&r->combDelay, lengths[2], lengths[2] * 2); | 48 | tDelay_init(&r->combDelay, lengths[2], lengths[2] * 2); |
| 49 | 49 | ||
| 50 | tPRCRev_setT60(r, t60); | 50 | tPRCReverb_setT60(r, t60); |
| 51 | 51 | ||
| 52 | r->allpassCoeff = 0.7f; | 52 | r->allpassCoeff = 0.7f; |
| 53 | r->mix = 0.5f; | 53 | r->mix = 0.5f; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | void tPRCRev_free(tPRCRev* const r) | 56 | void tPRCReverb_free(tPRCReverb* const r) |
| 57 | { | 57 | { |
| 58 | tDelay_free(&r->allpassDelays[0]); | 58 | tDelay_free(&r->allpassDelays[0]); |
| 59 | tDelay_free(&r->allpassDelays[1]); | 59 | tDelay_free(&r->allpassDelays[1]); |
| 60 | tDelay_free(&r->combDelay); | 60 | tDelay_free(&r->combDelay); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | void tPRCRev_setT60(tPRCRev* const r, float t60) | 63 | void tPRCReverb_setT60(tPRCReverb* const r, float t60) |
| 64 | { | 64 | { |
| 65 | if ( t60 <= 0.0f ) t60 = 0.001f; | 65 | if ( t60 <= 0.0f ) t60 = 0.001f; |
| 66 | 66 | ||
| @@ -70,12 +70,12 @@ void tPRCRev_setT60(tPRCRev* const r, float t60) · 3 unmodified lines | |||
| 70 | 70 | ||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void tPRCRev_setMix(tPRCRev* const r, float mix) | 73 | void tPRCReverb_setMix(tPRCReverb* const r, float mix) |
| 74 | { | 74 | { |
| 75 | r->mix = mix; | 75 | r->mix = mix; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | float tPRCRev_tick(tPRCRev* const r, float input) | 78 | float tPRCReverb_tick(tPRCReverb* const r, float input) |
| 79 | { | 79 | { |
| 80 | float temp, temp0, temp1, temp2; | 80 | float temp, temp0, temp1, temp2; |
| 81 | float out; | 81 | float out; |
| @@ -107,13 +107,13 @@ float tPRCRev_tick(tPRCRev* const r, float input) · 25 unmodified lines | |||
| 107 | return out; | 107 | return out; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void tPRCRevSampleRateChanged (tPRCRev* const r) | 110 | void tPRCReverbSampleRateChanged (tPRCReverb* const r) |
| 111 | { | 111 | { |
| 112 | r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 )); | 112 | r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 )); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | 115 | /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ |
| 116 | void tNRev_init(tNRev* const r, float t60) | 116 | void tNReverb_init(tNReverb* const r, float t60) |
| 117 | { | 117 | { |
| 118 | if (t60 <= 0.0f) t60 = 0.001f; | 118 | if (t60 <= 0.0f) t60 = 0.001f; |
| 119 | 119 | ||
| @@ -150,12 +150,12 @@ void tNRev_init(tNRev* const r, float t60) · 30 unmodified lines | |||
| 150 | tDelay_setDelay(&r->combDelays[i], lengths[i+2]); | 150 | tDelay_setDelay(&r->combDelays[i], lengths[i+2]); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | tNRev_setT60(r, t60); | 153 | tNReverb_setT60(r, t60); |
| 154 | r->allpassCoeff = 0.7f; | 154 | r->allpassCoeff = 0.7f; |
| 155 | r->mix = 0.3f; | 155 | r->mix = 0.3f; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | void tNRev_free(tNRev* const r) | 158 | void tNReverb_free(tNReverb* const r) |
| 159 | { | 159 | { |
| 160 | for (int i = 0; i < 6; i++) | 160 | for (int i = 0; i < 6; i++) |
| 161 | { | 161 | { |
| @@ -168,7 +168,7 @@ void tNRev_free(tNRev* const r) · 6 unmodified lines | |||
| 168 | } | 168 | } |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | void tNRev_setT60(tNRev* const r, float t60) | 171 | void tNReverb_setT60(tNReverb* const r, float t60) |
| 172 | { | 172 | { |
| 173 | if (t60 <= 0.0f) t60 = 0.001f; | 173 | if (t60 <= 0.0f) t60 = 0.001f; |
| 174 | 174 | ||
| @@ -178,12 +178,12 @@ void tNRev_setT60(tNRev* const r, float t60) · 3 unmodified lines | |||
| 178 | 178 | ||
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | void tNRev_setMix(tNRev* const r, float mix) | 181 | void tNReverb_setMix(tNReverb* const r, float mix) |
| 182 | { | 182 | { |
| 183 | r->mix = mix; | 183 | r->mix = mix; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | float tNRev_tick(tNRev* const r, float input) | 186 | float tNReverb_tick(tNReverb* const r, float input) |
| 187 | { | 187 | { |
| 188 | r->lastIn = input; | 188 | r->lastIn = input; |
| 189 | 189 | ||
| @@ -221,10 +221,10 @@ float tNRev_tick(tNRev* const r, float input) · 31 unmodified lines | |||
| 221 | out = r->mix * ( -( r->allpassCoeff * temp2 ) + temp ); | 221 | out = r->mix * ( -( r->allpassCoeff * temp2 ) + temp ); |
| 222 | 222 | ||
| 223 | /* | 223 | /* |
| 224 | temp = tDelayLGetLastOut(&r->allpassDelays[5]); | 224 | temp = tLinearDelayGetLastOut(&r->allpassDelays[5]); |
| 225 | temp3 = r->allpassCoeff * temp; | 225 | temp3 = r->allpassCoeff * temp; |
| 226 | temp3 += temp1; | 226 | temp3 += temp1; |
| 227 | tDelayLTick(&r->allpassDelays[5], temp3 ); | 227 | tLinearDelayTick(&r->allpassDelays[5], temp3 ); |
| 228 | lastFrame_[1] = effectMix_*( - ( r->allpassCoeff * temp3 ) + temp ); | 228 | lastFrame_[1] = effectMix_*( - ( r->allpassCoeff * temp3 ) + temp ); |
| 229 | */ | 229 | */ |
| 230 | 230 | ||
| @@ -237,7 +237,7 @@ float tNRev_tick(tNRev* const r, float input) · 6 unmodified lines | |||
| 237 | return out; | 237 | return out; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | void tNRevSampleRateChanged (tNRev* const r) | 240 | void tNReverbSampleRateChanged (tNReverb* const r) |
| 241 | { | 241 | { |
| 242 | for (int i=0; i<6; i++) r->combCoeffs[i] = pow(10.0, (-3.0 * tDelay_getDelay(&r->combDelays[i]) * leaf.invSampleRate / r->t60 )); | 242 | for (int i=0; i<6; i++) r->combCoeffs[i] = pow(10.0, (-3.0 * tDelay_getDelay(&r->combDelays[i]) * leaf.invSampleRate / r->t60 )); |
| 243 | } | 243 | } |
| @@ -250,7 +250,7 @@ float in_allpass_delays[4] = { 4.771f, 3.595f, 12.73f, 9.307f }; · 6 unmodified lines | |||
| 250 | float in_allpass_gains[4] = { 0.75f, 0.75f, 0.625f, 0.625f }; | 250 | float in_allpass_gains[4] = { 0.75f, 0.75f, 0.625f, 0.625f }; |
| 251 | 251 | ||
| 252 | 252 | ||
| 253 | void tDattorro_init (tDattorro* const r) | 253 | void tDattorroReverb_init (tDattorroReverb* const r) |
| 254 | { | 254 | { |
| 255 | r->size_max = 2.0f; | 255 | r->size_max = 2.0f; |
| 256 | r->size = 1.f; | 256 | r->size = 1.f; |
| @@ -298,20 +298,20 @@ void tDattorro_init (tDattorro* const r) · 41 unmodified lines | |||
| 298 | 298 | ||
| 299 | 299 | ||
| 300 | // PARAMETERS | 300 | // PARAMETERS |
| 301 | tDattorro_setMix(r, 0.5f); | 301 | tDattorroReverb_setMix(r, 0.5f); |
| 302 | 302 | ||
| 303 | tDattorro_setInputDelay(r, 0.f); | 303 | tDattorroReverb_setInputDelay(r, 0.f); |
| 304 | 304 | ||
| 305 | tDattorro_setInputFilter(r, 10000.f); | 305 | tDattorroReverb_setInputFilter(r, 10000.f); |
| 306 | 306 | ||
| 307 | tDattorro_setFeedbackFilter(r, 5000.f); | 307 | tDattorroReverb_setFeedbackFilter(r, 5000.f); |
| 308 | 308 | ||
| 309 | tDattorro_setFeedbackGain(r, 0.4f); | 309 | tDattorroReverb_setFeedbackGain(r, 0.4f); |
| 310 | 310 | ||
| 311 | 311 | ||
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | void tDattorro_free (tDattorro* const r) | 314 | void tDattorroReverb_free (tDattorroReverb* const r) |
| 315 | { | 315 | { |
| 316 | // INPUT | 316 | // INPUT |
| 317 | tTapeDelay_free(&r->in_delay); | 317 | tTapeDelay_free(&r->in_delay); |
| @@ -349,7 +349,7 @@ void tDattorro_free (tDattorro* const r) · 31 unmodified lines | |||
| 349 | tCycle_free(&r->f2_lfo); | 349 | tCycle_free(&r->f2_lfo); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | float tDattorro_tick (tDattorro* const r, float input) | 352 | float tDattorroReverb_tick (tDattorroReverb* const r, float input) |
| 353 | { | 353 | { |
| 354 | // INPUT | 354 | // INPUT |
| 355 | float in_sample = tTapeDelay_tick(&r->in_delay, input); | 355 | float in_sample = tTapeDelay_tick(&r->in_delay, input); |
| @@ -449,12 +449,12 @@ float tDattorro_tick (tDattorro* const r, float input) · 93 unmodified lines | |||
| 449 | return (input * (1.0f - r->mix) + sample * r->mix); | 449 | return (input * (1.0f - r->mix) + sample * r->mix); |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | void tDattorro_setMix (tDattorro* const r, float mix) | 452 | void tDattorroReverb_setMix (tDattorroReverb* const r, float mix) |
| 453 | { | 453 | { |
| 454 | r->mix = LEAF_clip(0.0f, mix, 1.0f); | 454 | r->mix = LEAF_clip(0.0f, mix, 1.0f); |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | void tDattorro_setSize (tDattorro* const r, float size) | 457 | void tDattorroReverb_setSize (tDattorroReverb* const r, float size) |
| 458 | { | 458 | { |
| 459 | r->size = LEAF_clip(0.01f, size*r->size_max, r->size_max); | 459 | r->size = LEAF_clip(0.01f, size*r->size_max, r->size_max); |
| 460 | r->t = r->size * leaf.sampleRate * 0.001f; | 460 | r->t = r->size * leaf.sampleRate * 0.001f; |
| @@ -483,21 +483,21 @@ void tDattorro_setSize (tDattorro* const r, float size) · 22 unmodified lines | |||
| 483 | tTapeDelay_setDelay(&r->f2_delay_3, SAMP(106.28f)); | 483 | tTapeDelay_setDelay(&r->f2_delay_3, SAMP(106.28f)); |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | void tDattorro_setInputDelay (tDattorro* const r, float preDelay) | 486 | void tDattorroReverb_setInputDelay (tDattorroReverb* const r, float preDelay) |
| 487 | { | 487 | { |
| 488 | r->predelay = LEAF_clip(0.0f, preDelay, 200.0f); | 488 | r->predelay = LEAF_clip(0.0f, preDelay, 200.0f); |
| 489 | 489 | ||
| 490 | tTapeDelay_setDelay(&r->in_delay, SAMP(r->predelay)); | 490 | tTapeDelay_setDelay(&r->in_delay, SAMP(r->predelay)); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | void tDattorro_setInputFilter (tDattorro* const r, float freq) | 493 | void tDattorroReverb_setInputFilter (tDattorroReverb* const r, float freq) |
| 494 | { | 494 | { |
| 495 | r->input_filter = LEAF_clip(0.0f, freq, 20000.0f); | 495 | r->input_filter = LEAF_clip(0.0f, freq, 20000.0f); |
| 496 | 496 | ||
| 497 | tOnePole_setFreq(&r->in_filter, r->input_filter); | 497 | tOnePole_setFreq(&r->in_filter, r->input_filter); |
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | void tDattorro_setFeedbackFilter (tDattorro* const r, float freq) | 500 | void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const r, float freq) |
| 501 | { | 501 | { |
| 502 | r->feedback_filter = LEAF_clip(0.0f, freq, 20000.0f); | 502 | r->feedback_filter = LEAF_clip(0.0f, freq, 20000.0f); |
| 503 | 503 | ||
| @@ -505,7 +505,7 @@ void tDattorro_setFeedbackFilter (tDattorro* const r, float freq) · 1 unmodified line | |||
| 505 | tOnePole_setFreq(&r->f2_filter, r->feedback_filter); | 505 | tOnePole_setFreq(&r->f2_filter, r->feedback_filter); |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | void tDattorro_setFeedbackGain (tDattorro* const r, float gain) | 508 | void tDattorroReverb_setFeedbackGain (tDattorroReverb* const r, float gain) |
| 509 | { | 509 | { |
| 510 | r->feedback_gain = gain; | 510 | r->feedback_gain = gain; |
| 511 | } | 511 | } |
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ============================================================================== | 2 | ============================================================================== |
| 3 | 3 | ||
| 4 | leaf-sample.c | 4 | leaf-sampling.c |
| 5 | Created: 20 Jan 2017 12:02:17pm | 5 | Created: 20 Jan 2017 12:02:17pm |
| 6 | Author: Michael R Mulshine | 6 | Author: Michael R Mulshine |
| 7 | 7 | ||
| @@ -11,12 +11,12 @@ · 3 unmodified lines | |||
| 11 | 11 | ||
| 12 | #if _WIN32 || _WIN64 | 12 | #if _WIN32 || _WIN64 |
| 13 | 13 | ||
| 14 | #include "..\Inc\leaf-sample.h" | 14 | #include "..\Inc\leaf-sampling.h" |
| 15 | #include "..\leaf.h" | 15 | #include "..\leaf.h" |
| 16 | 16 | ||
| 17 | #else | 17 | #else |
| 18 | 18 | ||
| 19 | #include "../Inc/leaf-sample.h" | 19 | #include "../Inc/leaf-sampling.h" |
| 20 | #include "../leaf.h" | 20 | #include "../leaf.h" |
| 21 | 21 | ||
| 22 | #endif | 22 | #endif |
| @@ -1,289 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-string.c | ||
| 4 | Created: 30 Nov 2018 10:41:42am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-string.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include "../Inc/leaf-string.h" | ||
| 16 | |||
| 17 | #endif | ||
| 18 | |||
| 19 | /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tPluck ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | ||
| 20 | void tPluck_init (tPluck* const p, float lowestFrequency) | ||
| 21 | { | ||
| 22 | if ( lowestFrequency <= 0.0f ) lowestFrequency = 10.0f; | ||
| 23 | |||
| 24 | tNoise_init(&p->noise, WhiteNoise); | ||
| 25 | |||
| 26 | tOnePole_init(&p->pickFilter, 0.0f); | ||
| 27 | |||
| 28 | tOneZero_init(&p->loopFilter, 0.0f); | ||
| 29 | |||
| 30 | tDelayA_init(&p->delayLine, 0.0f, leaf.sampleRate * 2); | ||
| 31 | |||
| 32 | tPluck_setFrequency(p, 220.0f); | ||
| 33 | } | ||
| 34 | |||
| 35 | void tPluck_free (tPluck* const p) | ||
| 36 | { | ||
| 37 | tNoise_free(&p->noise); | ||
| 38 | tOnePole_free(&p->pickFilter); | ||
| 39 | tOneZero_free(&p->loopFilter); | ||
| 40 | tDelayA_free(&p->delayLine); | ||
| 41 | } | ||
| 42 | |||
| 43 | float tPluck_getLastOut (tPluck *p) | ||
| 44 | { | ||
| 45 | return p->lastOut; | ||
| 46 | } | ||
| 47 | |||
| 48 | float tPluck_tick (tPluck *p) | ||
| 49 | { | ||
| 50 | return (p->lastOut = 3.0f * tDelayA_tick(&p->delayLine, tOneZero_tick(&p->loopFilter, tDelayA_getLastOut(&p->delayLine) * p->loopGain ) )); | ||
| 51 | } | ||
| 52 | |||
| 53 | void tPluck_pluck (tPluck* const p, float amplitude) | ||
| 54 | { | ||
| 55 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 56 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 57 | |||
| 58 | tOnePole_setPole(&p->pickFilter, 0.999f - (amplitude * 0.15f)); | ||
| 59 | tOnePole_setGain(&p->pickFilter, amplitude * 0.5f ); | ||
| 60 | |||
| 61 | // Fill delay with noise additively with current contents. | ||
| 62 | for ( uint32_t i = 0; i < (uint32_t)tDelayA_getDelay(&p->delayLine); i++ ) | ||
| 63 | tDelayA_tick(&p->delayLine, 0.6f * tDelayA_getLastOut(&p->delayLine) + tOnePole_tick(&p->pickFilter, tNoise_tick(&p->noise) ) ); | ||
| 64 | } | ||
| 65 | |||
| 66 | // Start a note with the given frequency and amplitude.; | ||
| 67 | void tPluck_noteOn (tPluck* const p, float frequency, float amplitude ) | ||
| 68 | { | ||
| 69 | p->lastFreq = frequency; | ||
| 70 | tPluck_setFrequency( p, frequency ); | ||
| 71 | tPluck_pluck( p, amplitude ); | ||
| 72 | } | ||
| 73 | |||
| 74 | // Stop a note with the given amplitude (speed of decay). | ||
| 75 | void tPluck_noteOff (tPluck* const p, float amplitude ) | ||
| 76 | { | ||
| 77 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 78 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 79 | |||
| 80 | p->loopGain = 1.0f - amplitude; | ||
| 81 | } | ||
| 82 | |||
| 83 | // Set instrument parameters for a particular frequency. | ||
| 84 | void tPluck_setFrequency (tPluck* const p, float frequency ) | ||
| 85 | { | ||
| 86 | if ( frequency <= 0.0f ) frequency = 0.001f; | ||
| 87 | |||
| 88 | // Delay = length - filter delay. | ||
| 89 | float delay = ( leaf.sampleRate / frequency ) - tOneZero_getPhaseDelay(&p->loopFilter, frequency ); | ||
| 90 | |||
| 91 | tDelayA_setDelay(&p->delayLine, delay ); | ||
| 92 | |||
| 93 | p->loopGain = 0.99f + (frequency * 0.000005f); | ||
| 94 | |||
| 95 | if ( p->loopGain >= 0.999f ) p->loopGain = 0.999f; | ||
| 96 | |||
| 97 | } | ||
| 98 | |||
| 99 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 100 | void tPluck_controlChange (tPluck* const p, int number, float value) | ||
| 101 | { | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | void tPluckSampleRateChanged(tPluck* const p) | ||
| 106 | { | ||
| 107 | //tPluckSetFrequency(p, p->lastFreq); | ||
| 108 | } | ||
| 109 | |||
| 110 | /* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tStifKarp ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | ||
| 111 | void tStifKarp_init (tStifKarp* const p, float lowestFrequency) | ||
| 112 | { | ||
| 113 | if ( lowestFrequency <= 0.0f ) lowestFrequency = 8.0f; | ||
| 114 | |||
| 115 | tDelayA_init(&p->delayLine, 0.0f, leaf.sampleRate * 2); | ||
| 116 | |||
| 117 | tDelayL_init(&p->combDelay, 0.0f, leaf.sampleRate * 2); | ||
| 118 | |||
| 119 | tOneZero_init(&p->filter, 0.0f); | ||
| 120 | |||
| 121 | tNoise_init(&p->noise, WhiteNoise); | ||
| 122 | |||
| 123 | for (int i = 0; i < 4; i++) | ||
| 124 | { | ||
| 125 | tBiQuad_init(&p->biquad[i]); | ||
| 126 | } | ||
| 127 | |||
| 128 | p->pluckAmplitude = 0.3f; | ||
| 129 | p->pickupPosition = 0.4f; | ||
| 130 | |||
| 131 | p->stretching = 0.9999f; | ||
| 132 | p->baseLoopGain = 0.995f; | ||
| 133 | p->loopGain = 0.999f; | ||
| 134 | |||
| 135 | tStifKarp_setFrequency( p, 220.0f ); | ||
| 136 | |||
| 137 | } | ||
| 138 | |||
| 139 | void tStifKarp_free (tStifKarp* const p) | ||
| 140 | { | ||
| 141 | tDelayA_free(&p->delayLine); | ||
| 142 | tDelayL_free(&p->combDelay); | ||
| 143 | tOneZero_free(&p->filter); | ||
| 144 | tNoise_free(&p->noise); | ||
| 145 | |||
| 146 | for (int i = 0; i < 4; i++) | ||
| 147 | { | ||
| 148 | tBiQuad_free(&p->biquad[i]); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | float tStifKarp_getLastOut (tStifKarp* const p) | ||
| 153 | { | ||
| 154 | return p->lastOut; | ||
| 155 | } | ||
| 156 | |||
| 157 | float tStifKarp_tick (tStifKarp* const p) | ||
| 158 | { | ||
| 159 | float temp = tDelayA_getLastOut(&p->delayLine) * p->loopGain; | ||
| 160 | |||
| 161 | // Calculate allpass stretching. | ||
| 162 | for (int i=0; i<4; i++) temp = tBiQuad_tick(&p->biquad[i],temp); | ||
| 163 | |||
| 164 | // Moving average filter. | ||
| 165 | temp = tOneZero_tick(&p->filter, temp); | ||
| 166 | |||
| 167 | float out = tDelayA_tick(&p->delayLine, temp); | ||
| 168 | out = out - tDelayL_tick(&p->combDelay, out); | ||
| 169 | p->lastOut = out; | ||
| 170 | |||
| 171 | return p->lastOut; | ||
| 172 | } | ||
| 173 | |||
| 174 | void tStifKarp_pluck (tStifKarp* const p, float amplitude) | ||
| 175 | { | ||
| 176 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 177 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 178 | |||
| 179 | p->pluckAmplitude = amplitude; | ||
| 180 | |||
| 181 | for ( uint32_t i=0; i < (uint32_t)tDelayA_getDelay(&p->delayLine); i++ ) | ||
| 182 | { | ||
| 183 | // Fill delay with noise additively with current contents. | ||
| 184 | tDelayA_tick(&p->delayLine, (tDelayA_getLastOut(&p->delayLine) * 0.6f) + 0.4f * tNoise_tick(&p->noise) * p->pluckAmplitude ); | ||
| 185 | //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) ); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | // Start a note with the given frequency and amplitude.; | ||
| 190 | void tStifKarp_noteOn (tStifKarp* const p, float frequency, float amplitude ) | ||
| 191 | { | ||
| 192 | tStifKarp_setFrequency( p, frequency ); | ||
| 193 | tStifKarp_pluck( p, amplitude ); | ||
| 194 | } | ||
| 195 | |||
| 196 | // Stop a note with the given amplitude (speed of decay). | ||
| 197 | void tStifKarp_noteOff (tStifKarp* const p, float amplitude ) | ||
| 198 | { | ||
| 199 | if ( amplitude < 0.0f) amplitude = 0.0f; | ||
| 200 | else if (amplitude > 1.0f) amplitude = 1.0f; | ||
| 201 | |||
| 202 | p->loopGain = 1.0f - amplitude; | ||
| 203 | } | ||
| 204 | |||
| 205 | // Set instrument parameters for a particular frequency. | ||
| 206 | void tStifKarp_setFrequency (tStifKarp* const p, float frequency ) | ||
| 207 | { | ||
| 208 | if ( frequency <= 0.0f ) frequency = 0.001f; | ||
| 209 | |||
| 210 | p->lastFrequency = frequency; | ||
| 211 | p->lastLength = leaf.sampleRate / p->lastFrequency; | ||
| 212 | float delay = p->lastLength - 0.5f; | ||
| 213 | tDelayA_setDelay(&p->delayLine, delay); | ||
| 214 | |||
| 215 | // MAYBE MODIFY LOOP GAINS | ||
| 216 | p->loopGain = p->baseLoopGain + (frequency * 0.000005f); | ||
| 217 | if (p->loopGain >= 1.0f) p->loopGain = 0.99999f; | ||
| 218 | |||
| 219 | tStifKarp_setStretch(p, p->stretching); | ||
| 220 | |||
| 221 | tDelayL_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength ); | ||
| 222 | |||
| 223 | } | ||
| 224 | |||
| 225 | // Set the stretch "factor" of the string (0.0 - 1.0). | ||
| 226 | void tStifKarp_setStretch (tStifKarp* const p, float stretch ) | ||
| 227 | { | ||
| 228 | p->stretching = stretch; | ||
| 229 | float coefficient; | ||
| 230 | float freq = p->lastFrequency * 2.0f; | ||
| 231 | float dFreq = ( (0.5f * leaf.sampleRate) - freq ) * 0.25f; | ||
| 232 | float temp = 0.5f + (stretch * 0.5f); | ||
| 233 | if ( temp > 0.9999f ) temp = 0.9999f; | ||
| 234 | |||
| 235 | for ( int i=0; i<4; i++ ) | ||
| 236 | { | ||
| 237 | coefficient = temp * temp; | ||
| 238 | tBiQuad_setA2(&p->biquad[i], coefficient); | ||
| 239 | tBiQuad_setB0(&p->biquad[i], coefficient); | ||
| 240 | tBiQuad_setB2(&p->biquad[i], 1.0f); | ||
| 241 | |||
| 242 | coefficient = -2.0f * temp * cos(TWO_PI * freq / leaf.sampleRate); | ||
| 243 | tBiQuad_setA1(&p->biquad[i], coefficient); | ||
| 244 | tBiQuad_setB1(&p->biquad[i], coefficient); | ||
| 245 | |||
| 246 | freq += dFreq; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | // Set the pluck or "excitation" position along the string (0.0 - 1.0). | ||
| 251 | void tStifKarp_setPickupPosition (tStifKarp* const p, float position ) | ||
| 252 | { | ||
| 253 | if (position < 0.0f) p->pickupPosition = 0.0f; | ||
| 254 | else if (position <= 1.0f) p->pickupPosition = position; | ||
| 255 | else p->pickupPosition = 1.0f; | ||
| 256 | |||
| 257 | tDelayL_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength); | ||
| 258 | } | ||
| 259 | |||
| 260 | // Set the base loop gain. | ||
| 261 | void tStifKarp_setBaseLoopGain (tStifKarp* const p, float aGain ) | ||
| 262 | { | ||
| 263 | p->baseLoopGain = aGain; | ||
| 264 | p->loopGain = p->baseLoopGain + (p->lastFrequency * 0.000005f); | ||
| 265 | if ( p->loopGain > 0.99999f ) p->loopGain = 0.99999f; | ||
| 266 | } | ||
| 267 | |||
| 268 | // Perform the control change specified by \e number and \e value (0.0 - 128.0). | ||
| 269 | void tStifKarp_controlChange (tStifKarp* const p, SKControlType type, float value) | ||
| 270 | { | ||
| 271 | if ( value < 0.0f ) value = 0.0f; | ||
| 272 | else if (value > 128.0f) value = 128.0f; | ||
| 273 | |||
| 274 | float normalizedValue = value * INV_128; | ||
| 275 | |||
| 276 | if (type == SKPickPosition) // 4 | ||
| 277 | tStifKarp_setPickupPosition( p, normalizedValue ); | ||
| 278 | else if (type == SKStringDamping) // 11 | ||
| 279 | tStifKarp_setBaseLoopGain( p, 0.97f + (normalizedValue * 0.03f) ); | ||
| 280 | else if (type == SKDetune) // 1 | ||
| 281 | tStifKarp_setStretch( p, 0.91f + (0.09f * (1.0f - normalizedValue)) ); | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | void tStifKarpSampleRateChanged (tStifKarp* const c) | ||
| 286 | { | ||
| 287 | tStifKarp_setFrequency(c, c->lastFrequency); | ||
| 288 | tStifKarp_setStretch(c, c->stretching); | ||
| 289 | } | ||
| @@ -1,2227 +0,0 @@ | |||
| 1 | /* | ||
| 2 | ============================================================================== | ||
| 3 | |||
| 4 | LEAFUtilities.c | ||
| 5 | Created: 20 Jan 2017 12:02:17pm | ||
| 6 | Author: Michael R Mulshine | ||
| 7 | |||
| 8 | ============================================================================== | ||
| 9 | */ | ||
| 10 | |||
| 11 | |||
| 12 | #if _WIN32 || _WIN64 | ||
| 13 | |||
| 14 | #include "..\Inc\leaf-utilities.h" | ||
| 15 | #include "..\Inc\leaf-tables.h" | ||
| 16 | #include "..\leaf.h" | ||
| 17 | #include "..\Inc\d_fft_mayer.h" | ||
| 18 | |||
| 19 | #else | ||
| 20 | |||
| 21 | #include "../Inc/leaf-utilities.h" | ||
| 22 | #include "../Inc/leaf-tables.h" | ||
| 23 | #include "../leaf.h" | ||
| 24 | #include "../Externals/d_fft_mayer.h" | ||
| 25 | |||
| 26 | #endif | ||
| 27 | |||
| 28 | #define LOGTEN 2.302585092994 | ||
| 29 | |||
| 30 | float mtof(float f) | ||
| 31 | { | ||
| 32 | if (f <= -1500.0f) return(0); | ||
| 33 | else if (f > 1499.0f) return(mtof(1499.0f)); | ||
| 34 | else return (8.17579891564f * expf(0.0577622650f * f)); | ||
| 35 | } | ||
| 36 | |||
| 37 | float ftom(float f) | ||
| 38 | { | ||
| 39 | return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f); | ||
| 40 | } | ||
| 41 | |||
| 42 | float powtodb(float f) | ||
| 43 | { | ||
| 44 | if (f <= 0) return (0); | ||
| 45 | else | ||
| 46 | { | ||
| 47 | float val = 100 + 10.f/LOGTEN * logf(f); | ||
| 48 | return (val < 0 ? 0 : val); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | float rmstodb(float f) | ||
| 53 | { | ||
| 54 | if (f <= 0) return (0); | ||
| 55 | else | ||
| 56 | { | ||
| 57 | float val = 100 + 20.f/LOGTEN * log(f); | ||
| 58 | return (val < 0 ? 0 : val); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | float dbtopow(float f) | ||
| 63 | { | ||
| 64 | if (f <= 0) | ||
| 65 | return(0); | ||
| 66 | else | ||
| 67 | { | ||
| 68 | if (f > 870.0f) | ||
| 69 | f = 870.0f; | ||
| 70 | return (expf((LOGTEN * 0.1f) * (f-100.0f))); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | float dbtorms(float f) | ||
| 75 | { | ||
| 76 | if (f <= 0) | ||
| 77 | return(0); | ||
| 78 | else | ||
| 79 | { | ||
| 80 | if (f > 485.0f) | ||
| 81 | f = 485.0f; | ||
| 82 | } | ||
| 83 | return (expf((LOGTEN * 0.05f) * (f-100.0f))); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* ---------------- env~ - simple envelope follower. ----------------- */ | ||
| 87 | void tEnv_init(tEnv* const x, int ws, int hs, int bs) | ||
| 88 | { | ||
| 89 | int period = hs, npoints = ws; | ||
| 90 | |||
| 91 | int i; | ||
| 92 | |||
| 93 | if (npoints < 1) npoints = 1024; | ||
| 94 | if (period < 1) period = npoints/2; | ||
| 95 | if (period < npoints / MAXOVERLAP + 1) | ||
| 96 | period = npoints / MAXOVERLAP + 1; | ||
| 97 | |||
| 98 | x->x_npoints = npoints; | ||
| 99 | x->x_phase = 0; | ||
| 100 | x->x_period = period; | ||
| 101 | |||
| 102 | x->windowSize = npoints; | ||
| 103 | x->hopSize = period; | ||
| 104 | x->blockSize = bs; | ||
| 105 | |||
| 106 | for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0; | ||
| 107 | for (i = 0; i < npoints; i++) | ||
| 108 | x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints; | ||
| 109 | for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0; | ||
| 110 | |||
| 111 | x->x_f = 0; | ||
| 112 | |||
| 113 | x->x_allocforvs = INITVSTAKEN; | ||
| 114 | |||
| 115 | // ~ ~ ~ dsp ~ ~ ~ | ||
| 116 | if (x->x_period % x->blockSize) | ||
| 117 | { | ||
| 118 | x->x_realperiod = x->x_period + x->blockSize - (x->x_period % x->blockSize); | ||
| 119 | } | ||
| 120 | else | ||
| 121 | { | ||
| 122 | x->x_realperiod = x->x_period; | ||
| 123 | } | ||
| 124 | // ~ ~ ~ ~ ~ ~ ~ ~ | ||
| 125 | } | ||
| 126 | |||
| 127 | void tEnv_free (tEnv* const x) | ||
| 128 | { | ||
| 129 | |||
| 130 | } | ||
| 131 | |||
| 132 | float tEnv_tick (tEnv* const x) | ||
| 133 | { | ||
| 134 | return powtodb(x->x_result); | ||
| 135 | } | ||
| 136 | |||
| 137 | void tEnv_processBlock(tEnv* const x, float* in) | ||
| 138 | { | ||
| 139 | int n = x->blockSize; | ||
| 140 | |||
| 141 | int count; | ||
| 142 | t_sample *sump; | ||
| 143 | in += n; | ||
| 144 | for (count = x->x_phase, sump = x->x_sumbuf; | ||
| 145 | count < x->x_npoints; count += x->x_realperiod, sump++) | ||
| 146 | { | ||
| 147 | t_sample *hp = x->buf + count; | ||
| 148 | t_sample *fp = in; | ||
| 149 | t_sample sum = *sump; | ||
| 150 | int i; | ||
| 151 | |||
| 152 | for (i = 0; i < n; i++) | ||
| 153 | { | ||
| 154 | fp--; | ||
| 155 | sum += *hp++ * (*fp * *fp); | ||
| 156 | } | ||
| 157 | *sump = sum; | ||
| 158 | } | ||
| 159 | sump[0] = 0; | ||
| 160 | x->x_phase -= n; | ||
| 161 | if (x->x_phase < 0) | ||
| 162 | { | ||
| 163 | x->x_result = x->x_sumbuf[0]; | ||
| 164 | for (count = x->x_realperiod, sump = x->x_sumbuf; | ||
| 165 | count < x->x_npoints; count += x->x_realperiod, sump++) | ||
| 166 | sump[0] = sump[1]; | ||
| 167 | sump[0] = 0; | ||
| 168 | x->x_phase = x->x_realperiod - n; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compressor ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | ||
| 172 | |||
| 173 | /* | ||
| 174 | tCompressor* tCompressorInit(int tauAttack, int tauRelease) | ||
| 175 | { | ||
| 176 | tCompressor* c = &leaf.tCompressorRegistry[leaf.registryIndex[T_COMPRESSOR]++]; | ||
| 177 | |||
| 178 | c->tauAttack = tauAttack; | ||
| 179 | c->tauRelease = tauRelease; | ||
| 180 | |||
| 181 | c->x_G[0] = 0.0f, c->x_G[1] = 0.0f, | ||
| 182 | c->y_G[0] = 0.0f, c->y_G[1] = 0.0f, | ||
| 183 | c->x_T[0] = 0.0f, c->x_T[1] = 0.0f, | ||
| 184 | c->y_T[0] = 0.0f, c->y_T[1] = 0.0f; | ||
| 185 | |||
| 186 | c->T = 0.0f; // Threshold | ||
| 187 | c->R = 1.0f; // compression Ratio | ||
| 188 | c->M = 0.0f; // decibel Make-up gain | ||
| 189 | c->W = 0.0f; // decibel Width of knee transition | ||
| 190 | |||
| 191 | return c; | ||
| 192 | } | ||
| 193 | */ | ||
| 194 | void tCompressor_init(tCompressor* const c) | ||
| 195 | { | ||
| 196 | c->tauAttack = 100; | ||
| 197 | c->tauRelease = 100; | ||
| 198 | |||
| 199 | c->isActive = OFALSE; | ||
| 200 | |||
| 201 | c->T = 0.0f; // Threshold | ||
| 202 | c->R = 0.5f; // compression Ratio | ||
| 203 | c->M = 3.0f; // decibel Width of knee transition | ||
| 204 | c->W = 1.0f; // decibel Make-up gain | ||
| 205 | } | ||
| 206 | |||
| 207 | void tCompressor_free(tCompressor* const c) | ||
| 208 | { | ||
| 209 | |||
| 210 | } | ||
| 211 | |||
| 212 | int ccount = 0; | ||
| 213 | float tCompressor_tick(tCompressor* const c, float in) | ||
| 214 | { | ||
| 215 | float slope, overshoot; | ||
| 216 | float alphaAtt, alphaRel; | ||
| 217 | |||
| 218 | float in_db = 20.0f * log10f( fmaxf( fabsf( in), 0.000001f)), out_db = 0.0f; | ||
| 219 | |||
| 220 | c->y_T[1] = c->y_T[0]; | ||
| 221 | |||
| 222 | slope = c->R - 1.0f; // feed-forward topology; was 1/C->R - 1 | ||
| 223 | |||
| 224 | overshoot = in_db - c->T; | ||
| 225 | |||
| 226 | |||
| 227 | if (overshoot <= -(c->W * 0.5f)) | ||
| 228 | { | ||
| 229 | out_db = in_db; | ||
| 230 | c->isActive = OFALSE; | ||
| 231 | } | ||
| 232 | else if ((overshoot > -(c->W * 0.5f)) && (overshoot < (c->W * 0.5f))) | ||
| 233 | { | ||
| 234 | out_db = in_db + slope * (powf((overshoot + c->W*0.5f),2) / (2.0f * c->W)); // .^ 2 ??? | ||
| 235 | c->isActive = OTRUE; | ||
| 236 | } | ||
| 237 | else if (overshoot >= (c->W * 0.5f)) | ||
| 238 | { | ||
| 239 | out_db = in_db + slope * overshoot; | ||
| 240 | c->isActive = OTRUE; | ||
| 241 | } | ||
| 242 | |||
| 243 | |||
| 244 | |||
| 245 | c->x_T[0] = out_db - in_db; | ||
| 246 | |||
| 247 | alphaAtt = expf(-1.0f/(0.001f * c->tauAttack * leaf.sampleRate)); | ||
| 248 | alphaRel = expf(-1.0f/(0.001f * c->tauRelease * leaf.sampleRate)); | ||
| 249 | |||
| 250 | if (c->x_T[0] > c->y_T[1]) | ||
| 251 | c->y_T[0] = alphaAtt * c->y_T[1] + (1-alphaAtt) * c->x_T[0]; | ||
| 252 | else | ||
| 253 | c->y_T[0] = alphaRel * c->y_T[1] + (1-alphaRel) * c->x_T[0]; | ||
| 254 | |||
| 255 | float attenuation = powf(10.0f, ((c->M - c->y_T[0])/20.0f)); | ||
| 256 | |||
| 257 | /* | ||
| 258 | if (++ccount > 5000) | ||
| 259 | { | ||
| 260 | |||
| 261 | ccount = 0; | ||
| 262 | DBG(".5width: " + String(c->W * 0.5f)); | ||
| 263 | DBG("slope: " + String(slope) + " overshoot: " + String(overshoot)); | ||
| 264 | DBG("attenuation: " + String(attenuation)); | ||
| 265 | } | ||
| 266 | */ | ||
| 267 | return attenuation * in; | ||
| 268 | |||
| 269 | |||
| 270 | } | ||
| 271 | |||
| 272 | // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Envelope ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | ||
| 273 | void tEnvelope_init(tEnvelope* const env, float attack, float decay, oBool loop) | ||
| 274 | { | ||
| 275 | env->exp_buff = exp_decay; | ||
| 276 | env->inc_buff = attack_decay_inc; | ||
| 277 | env->buff_size = sizeof(exp_decay); | ||
| 278 | |||
| 279 | env->loop = loop; | ||
| 280 | |||
| 281 | if (attack > 8192.0f) | ||
| 282 | attack = 8192.0f; | ||
| 283 | if (attack < 0.0f) | ||
| 284 | attack = 0.0f; | ||
| 285 | |||
| 286 | if (decay > 8192.0f) | ||
| 287 | decay = 8192.0f; | ||
| 288 | if (decay < 0.0f) | ||
| 289 | decay = 0.0f; | ||
| 290 | |||
| 291 | int16_t attackIndex = ((int16_t)(attack * 8.0f))-1; | ||
| 292 | int16_t decayIndex = ((int16_t)(decay * 8.0f))-1; | ||
| 293 | int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1; | ||
| 294 | |||
| 295 | if (attackIndex < 0) | ||
| 296 | attackIndex = 0; | ||
| 297 | if (decayIndex < 0) | ||
| 298 | decayIndex = 0; | ||
| 299 | if (rampIndex < 0) | ||
| 300 | rampIndex = 0; | ||
| 301 | |||
| 302 | env->inRamp = OFALSE; | ||
| 303 | env->inAttack = OFALSE; | ||
| 304 | env->inDecay = OFALSE; | ||
| 305 | |||
| 306 | env->attackInc = env->inc_buff[attackIndex]; | ||
| 307 | env->decayInc = env->inc_buff[decayIndex]; | ||
| 308 | env->rampInc = env->inc_buff[rampIndex]; | ||
| 309 | |||
| 310 | } | ||
| 311 | |||
| 312 | void tEnvelope_free(tEnvelope* const env) | ||
| 313 | { | ||
| 314 | |||
| 315 | } | ||
| 316 | |||
| 317 | int tEnvelope_setAttack(tEnvelope* const env, float attack) | ||
| 318 | { | ||
| 319 | int32_t attackIndex; | ||
| 320 | |||
| 321 | if (attack < 0.0f) { | ||
| 322 | attackIndex = 0.0f; | ||
| 323 | } else if (attack < 8192.0f) { | ||
| 324 | attackIndex = ((int32_t)(attack * 8.0f))-1; | ||
| 325 | } else { | ||
| 326 | attackIndex = ((int32_t)(8192.0f * 8.0f))-1; | ||
| 327 | } | ||
| 328 | |||
| 329 | env->attackInc = env->inc_buff[attackIndex]; | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | int tEnvelope_setDecay(tEnvelope* const env, float decay) | ||
| 335 | { | ||
| 336 | int32_t decayIndex; | ||
| 337 | |||
| 338 | if (decay < 0.0f) { | ||
| 339 | decayIndex = 0.0f; | ||
| 340 | } else if (decay < 8192.0f) { | ||
| 341 | decayIndex = ((int32_t)(decay * 8.0f)) - 1; | ||
| 342 | } else { | ||
| 343 | decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1; | ||
| 344 | } | ||
| 345 | |||
| 346 | env->decayInc = env->inc_buff[decayIndex]; | ||
| 347 | |||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | int tEnvelope_loop(tEnvelope* const env, oBool loop) | ||
| 352 | { | ||
| 353 | env->loop = loop; | ||
| 354 | |||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | int tEnvelope_on(tEnvelope* const env, float velocity) | ||
| 360 | { | ||
| 361 | if (env->inAttack || env->inDecay) // In case envelope retriggered while it is still happening. | ||
| 362 | { | ||
| 363 | env->rampPhase = 0; | ||
| 364 | env->inRamp = OTRUE; | ||
| 365 | env->rampPeak = env->next; | ||
| 366 | } | ||
| 367 | else // Normal start. | ||
| 368 | { | ||
| 369 | env->inAttack = OTRUE; | ||
| 370 | } | ||
| 371 | |||
| 372 | |||
| 373 | env->attackPhase = 0; | ||
| 374 | env->decayPhase = 0; | ||
| 375 | env->inDecay = OFALSE; | ||
| 376 | env->gain = velocity; | ||
| 377 | |||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | float tEnvelope_tick(tEnvelope* const env) | ||
| 382 | { | ||
| 383 | if (env->inRamp) | ||
| 384 | { | ||
| 385 | if (env->rampPhase > UINT16_MAX) | ||
| 386 | { | ||
| 387 | env->inRamp = OFALSE; | ||
| 388 | env->inAttack = OTRUE; | ||
| 389 | env->next = 0.0f; | ||
| 390 | } | ||
| 391 | else | ||
| 392 | { | ||
| 393 | env->next = env->rampPeak * env->exp_buff[(uint32_t)env->rampPhase]; | ||
| 394 | } | ||
| 395 | |||
| 396 | env->rampPhase += env->rampInc; | ||
| 397 | } | ||
| 398 | |||
| 399 | if (env->inAttack) | ||
| 400 | { | ||
| 401 | |||
| 402 | // If attack done, time to turn around. | ||
| 403 | if (env->attackPhase > UINT16_MAX) | ||
| 404 | { | ||
| 405 | env->inDecay = OTRUE; | ||
| 406 | env->inAttack = OFALSE; | ||
| 407 | env->next = env->gain * 1.0f; | ||
| 408 | } | ||
| 409 | else | ||
| 410 | { | ||
| 411 | // do interpolation ! | ||
| 412 | env->next = env->gain * env->exp_buff[UINT16_MAX - (uint32_t)env->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception | ||
| 413 | } | ||
| 414 | |||
| 415 | // Increment envelope attack. | ||
| 416 | env->attackPhase += env->attackInc; | ||
| 417 | |||
| 418 | } | ||
| 419 | |||
| 420 | if (env->inDecay) | ||
| 421 | { | ||
| 422 | |||
| 423 | // If decay done, finish. | ||
| 424 | if (env->decayPhase >= UINT16_MAX) | ||
| 425 | { | ||
| 426 | env->inDecay = OFALSE; | ||
| 427 | |||
| 428 | if (env->loop) | ||
| 429 | { | ||
| 430 | env->attackPhase = 0; | ||
| 431 | env->decayPhase = 0; | ||
| 432 | env->inAttack = OTRUE; | ||
| 433 | } | ||
| 434 | else | ||
| 435 | { | ||
| 436 | env->next = 0.0f; | ||
| 437 | } | ||
| 438 | |||
| 439 | } else { | ||
| 440 | |||
| 441 | env->next = env->gain * (env->exp_buff[(uint32_t)env->decayPhase]); // do interpolation ! | ||
| 442 | } | ||
| 443 | |||
| 444 | // Increment envelope decay; | ||
| 445 | env->decayPhase += env->decayInc; | ||
| 446 | } | ||
| 447 | |||
| 448 | return env->next; | ||
| 449 | } | ||
| 450 | |||
| 451 | /* ADSR */ | ||
| 452 | void tADSR_init(tADSR* const adsr, float attack, float decay, float sustain, float release) | ||
| 453 | { | ||
| 454 | adsr->exp_buff = exp_decay; | ||
| 455 | adsr->inc_buff = attack_decay_inc; | ||
| 456 | adsr->buff_size = sizeof(exp_decay); | ||
| 457 | |||
| 458 | if (attack > 8192.0f) | ||
| 459 | attack = 8192.0f; | ||
| 460 | if (attack < 0.0f) | ||
| 461 | attack = 0.0f; | ||
| 462 | |||
| 463 | if (decay > 8192.0f) | ||
| 464 | decay = 8192.0f; | ||
| 465 | if (decay < 0.0f) | ||
| 466 | decay = 0.0f; | ||
| 467 | |||
| 468 | if (sustain > 1.0f) | ||
| 469 | sustain = 1.0f; | ||
| 470 | if (sustain < 0.0f) | ||
| 471 | sustain = 0.0f; | ||
| 472 | |||
| 473 | if (release > 8192.0f) | ||
| 474 | release = 8192.0f; | ||
| 475 | if (release < 0.0f) | ||
| 476 | release = 0.0f; | ||
| 477 | |||
| 478 | int16_t attackIndex = ((int16_t)(attack * 8.0f))-1; | ||
| 479 | int16_t decayIndex = ((int16_t)(decay * 8.0f))-1; | ||
| 480 | int16_t releaseIndex = ((int16_t)(release * 8.0f))-1; | ||
| 481 | int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1; | ||
| 482 | |||
| 483 | if (attackIndex < 0) | ||
| 484 | attackIndex = 0; | ||
| 485 | if (decayIndex < 0) | ||
| 486 | decayIndex = 0; | ||
| 487 | if (releaseIndex < 0) | ||
| 488 | releaseIndex = 0; | ||
| 489 | if (rampIndex < 0) | ||
| 490 | rampIndex = 0; | ||
| 491 | |||
| 492 | adsr->inRamp = OFALSE; | ||
| 493 | adsr->inAttack = OFALSE; | ||
| 494 | adsr->inDecay = OFALSE; | ||
| 495 | adsr->inSustain = OFALSE; | ||
| 496 | adsr->inRelease = OFALSE; | ||
| 497 | |||
| 498 | adsr->sustain = sustain; | ||
| 499 | |||
| 500 | adsr->attackInc = adsr->inc_buff[attackIndex]; | ||
| 501 | adsr->decayInc = adsr->inc_buff[decayIndex]; | ||
| 502 | adsr->releaseInc = adsr->inc_buff[releaseIndex]; | ||
| 503 | adsr->rampInc = adsr->inc_buff[rampIndex]; | ||
| 504 | } | ||
| 505 | |||
| 506 | void tADSR_free(tADSR* const adsr) | ||
| 507 | { | ||
| 508 | |||
| 509 | } | ||
| 510 | |||
| 511 | int tADSR_setAttack(tADSR* const adsr, float attack) | ||
| 512 | { | ||
| 513 | int32_t attackIndex; | ||
| 514 | |||
| 515 | if (attack < 0.0f) { | ||
| 516 | attackIndex = 0.0f; | ||
| 517 | } else if (attack < 8192.0f) { | ||
| 518 | attackIndex = ((int32_t)(attack * 8.0f))-1; | ||
| 519 | } else { | ||
| 520 | attackIndex = ((int32_t)(8192.0f * 8.0f))-1; | ||
| 521 | } | ||
| 522 | |||
| 523 | adsr->attackInc = adsr->inc_buff[attackIndex]; | ||
| 524 | |||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | int tADSR_detDecay(tADSR* const adsr, float decay) | ||
| 529 | { | ||
| 530 | int32_t decayIndex; | ||
| 531 | |||
| 532 | if (decay < 0.0f) { | ||
| 533 | decayIndex = 0.0f; | ||
| 534 | } else if (decay < 8192.0f) { | ||
| 535 | decayIndex = ((int32_t)(decay * 8.0f)) - 1; | ||
| 536 | } else { | ||
| 537 | decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1; | ||
| 538 | } | ||
| 539 | |||
| 540 | adsr->decayInc = adsr->inc_buff[decayIndex]; | ||
| 541 | |||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 545 | int tADSR_setSustain(tADSR *const adsr, float sustain) | ||
| 546 | { | ||
| 547 | if (sustain > 1.0f) adsr->sustain = 1.0f; | ||
| 548 | else if (sustain < 0.0f) adsr->sustain = 0.0f; | ||
| 549 | else adsr->sustain = sustain; | ||
| 550 | |||
| 551 | return 0; | ||
| 552 | } | ||
| 553 | |||
| 554 | int tADSR_setRelease(tADSR* const adsr, float release) | ||
| 555 | { | ||
| 556 | int32_t releaseIndex; | ||
| 557 | |||
| 558 | if (release < 0.0f) { | ||
| 559 | releaseIndex = 0.0f; | ||
| 560 | } else if (release < 8192.0f) { | ||
| 561 | releaseIndex = ((int32_t)(release * 8.0f)) - 1; | ||
| 562 | } else { | ||
| 563 | releaseIndex = ((int32_t)(8192.0f * 8.0f)) - 1; | ||
| 564 | } | ||
| 565 | |||
| 566 | adsr->releaseInc = adsr->inc_buff[releaseIndex]; | ||
| 567 | |||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | int tADSR_on(tADSR* const adsr, float velocity) | ||
| 572 | { | ||
| 573 | if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening. | ||
| 574 | { | ||
| 575 | adsr->rampPhase = 0; | ||
| 576 | adsr->inRamp = OTRUE; | ||
| 577 | adsr->rampPeak = adsr->next; | ||
| 578 | } | ||
| 579 | else // Normal start. | ||
| 580 | { | ||
| 581 | adsr->inAttack = OTRUE; | ||
| 582 | } | ||
| 583 | |||
| 584 | adsr->attackPhase = 0; | ||
| 585 | adsr->decayPhase = 0; | ||
| 586 | adsr->releasePhase = 0; | ||
| 587 | adsr->inDecay = OFALSE; | ||
| 588 | adsr->inSustain = OFALSE; | ||
| 589 | adsr->inRelease = OFALSE; | ||
| 590 | adsr->gain = velocity; | ||
| 591 | |||
| 592 | return 0; | ||
| 593 | } | ||
| 594 | |||
| 595 | int tADSR_off(tADSR* const adsr) | ||
| 596 | { | ||
| 597 | if (adsr->inRelease) return 0; | ||
| 598 | |||
| 599 | adsr->inAttack = OFALSE; | ||
| 600 | adsr->inDecay = OFALSE; | ||
| 601 | adsr->inSustain = OFALSE; | ||
| 602 | adsr->inRelease = OTRUE; | ||
| 603 | |||
| 604 | adsr->releasePeak = adsr->next; | ||
| 605 | |||
| 606 | return 0; | ||
| 607 | } | ||
| 608 | |||
| 609 | float tADSR_tick(tADSR* const adsr) | ||
| 610 | { | ||
| 611 | if (adsr->inRamp) | ||
| 612 | { | ||
| 613 | if (adsr->rampPhase > UINT16_MAX) | ||
| 614 | { | ||
| 615 | adsr->inRamp = OFALSE; | ||
| 616 | adsr->inAttack = OTRUE; | ||
| 617 | adsr->next = 0.0f; | ||
| 618 | } | ||
| 619 | else | ||
| 620 | { | ||
| 621 | adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase]; | ||
| 622 | } | ||
| 623 | |||
| 624 | adsr->rampPhase += adsr->rampInc; | ||
| 625 | } | ||
| 626 | |||
| 627 | if (adsr->inAttack) | ||
| 628 | { | ||
| 629 | |||
| 630 | // If attack done, time to turn around. | ||
| 631 | if (adsr->attackPhase > UINT16_MAX) | ||
| 632 | { | ||
| 633 | adsr->inDecay = OTRUE; | ||
| 634 | adsr->inAttack = OFALSE; | ||
| 635 | adsr->next = adsr->gain * 1.0f; | ||
| 636 | } | ||
| 637 | else | ||
| 638 | { | ||
| 639 | // do interpolation ! | ||
| 640 | adsr->next = adsr->gain * adsr->exp_buff[UINT16_MAX - (uint32_t)adsr->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception | ||
| 641 | } | ||
| 642 | |||
| 643 | // Increment ADSR attack. | ||
| 644 | adsr->attackPhase += adsr->attackInc; | ||
| 645 | |||
| 646 | } | ||
| 647 | |||
| 648 | if (adsr->inDecay) | ||
| 649 | { | ||
| 650 | |||
| 651 | // If decay done, sustain. | ||
| 652 | if (adsr->decayPhase >= UINT16_MAX) | ||
| 653 | { | ||
| 654 | adsr->inDecay = OFALSE; | ||
| 655 | adsr->inSustain = OTRUE; | ||
| 656 | adsr->next = adsr->gain * adsr->sustain; | ||
| 657 | } | ||
| 658 | |||
| 659 | else | ||
| 660 | { | ||
| 661 | adsr->next = adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)adsr->decayPhase]) * (1 - adsr->sustain))); // do interpolation ! | ||
| 662 | } | ||
| 663 | |||
| 664 | // Increment ADSR decay. | ||
| 665 | adsr->decayPhase += adsr->decayInc; | ||
| 666 | } | ||
| 667 | |||
| 668 | if (adsr->inRelease) | ||
| 669 | { | ||
| 670 | // If release done, finish. | ||
| 671 | if (adsr->releasePhase >= UINT16_MAX) | ||
| 672 | { | ||
| 673 | adsr->inRelease = OFALSE; | ||
| 674 | adsr->next = 0.0f; | ||
| 675 | } | ||
| 676 | else { | ||
| 677 | |||
| 678 | adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)adsr->releasePhase]); // do interpolation ! | ||
| 679 | } | ||
| 680 | |||
| 681 | // Increment envelope release; | ||
| 682 | adsr->releasePhase += adsr->releaseInc; | ||
| 683 | } | ||
| 684 | |||
| 685 | return adsr->next; | ||
| 686 | } | ||
| 687 | |||
| 688 | /* Envelope Follower */ | ||
| 689 | void tEnvelopeFollower_init(tEnvelopeFollower* const e, float attackThreshold, float decayCoeff) | ||
| 690 | { | ||
| 691 | e->y = 0.0f; | ||
| 692 | e->a_thresh = attackThreshold; | ||
| 693 | e->d_coeff = decayCoeff; | ||
| 694 | } | ||
| 695 | |||
| 696 | void tEnvelopeFollower_free(tEnvelopeFollower* const e) | ||
| 697 | { | ||
| 698 | |||
| 699 | } | ||
| 700 | |||
| 701 | float tEnvelopeFollower_tick(tEnvelopeFollower* const ef, float x) | ||
| 702 | { | ||
| 703 | if (x < 0.0f ) x = -x; /* Absolute value. */ | ||
| 704 | |||
| 705 | if ((x >= ef->y) && (x > ef->a_thresh)) ef->y = x; /* If we hit a peak, ride the peak to the top. */ | ||
| 706 | else ef->y = ef->y * ef->d_coeff; /* Else, exponential decay of output. */ | ||
| 707 | |||
| 708 | //ef->y = envelope_pow[(uint16_t)(ef->y * (float)UINT16_MAX)] * ef->d_coeff; //not quite the right behavior - too much loss of precision? | ||
| 709 | //ef->y = powf(ef->y, 1.000009f) * ef->d_coeff; // too expensive | ||
| 710 | |||
| 711 | if( ef->y < VSF) ef->y = 0.0f; | ||
| 712 | |||
| 713 | return ef->y; | ||
| 714 | } | ||
| 715 | |||
| 716 | int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff) | ||
| 717 | { | ||
| 718 | return ef->d_coeff = decayCoeff; | ||
| 719 | } | ||
| 720 | |||
| 721 | int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attackThresh) | ||
| 722 | { | ||
| 723 | return ef->a_thresh = attackThresh; | ||
| 724 | } | ||
| 725 | |||
| 726 | /* Ramp */ | ||
| 727 | void tRamp_init(tRamp* const ramp, float time, int samples_per_tick) | ||
| 728 | { | ||
| 729 | ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f); | ||
| 730 | ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick; | ||
| 731 | ramp->curr = 0.0f; | ||
| 732 | ramp->dest = 0.0f; | ||
| 733 | |||
| 734 | if (time < ramp->minimum_time) | ||
| 735 | { | ||
| 736 | ramp->time = ramp->minimum_time; | ||
| 737 | } | ||
| 738 | else | ||
| 739 | { | ||
| 740 | ramp->time = time; | ||
| 741 | } | ||
| 742 | |||
| 743 | ramp->samples_per_tick = samples_per_tick; | ||
| 744 | ramp->inc = ((ramp->dest - ramp->curr) / ramp->time * ramp->inv_sr_ms) * (float)ramp->samples_per_tick; | ||
| 745 | } | ||
| 746 | |||
| 747 | void tRamp_free(tRamp* const ramp) | ||
| 748 | { | ||
| 749 | |||
| 750 | } | ||
| 751 | |||
| 752 | int tRamp_setTime(tRamp* const r, float time) | ||
| 753 | { | ||
| 754 | if (time < r->minimum_time) | ||
| 755 | { | ||
| 756 | r->time = r->minimum_time; | ||
| 757 | } | ||
| 758 | else | ||
| 759 | { | ||
| 760 | r->time = time; | ||
| 761 | } | ||
| 762 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick); | ||
| 763 | return 0; | ||
| 764 | } | ||
| 765 | |||
| 766 | int tRamp_setDest(tRamp* const r, float dest) | ||
| 767 | { | ||
| 768 | r->dest = dest; | ||
| 769 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick); | ||
| 770 | return 0; | ||
| 771 | } | ||
| 772 | |||
| 773 | int tRamp_setVal(tRamp* const r, float val) | ||
| 774 | { | ||
| 775 | r->curr = val; | ||
| 776 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick); | ||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | float tRamp_tick(tRamp* const r) { | ||
| 781 | |||
| 782 | r->curr += r->inc; | ||
| 783 | |||
| 784 | if (((r->curr >= r->dest) && (r->inc > 0.0f)) || ((r->curr <= r->dest) && (r->inc < 0.0f))) r->inc = 0.0f; | ||
| 785 | // Palle: There is a slight risk that you overshoot here and stay on dest+inc, which with a large inc value could be a real problem | ||
| 786 | // I suggest you add: r->curr=r->dest in the true if case | ||
| 787 | |||
| 788 | return r->curr; | ||
| 789 | } | ||
| 790 | |||
| 791 | float tRamp_sample(tRamp* const r) { | ||
| 792 | |||
| 793 | return r->curr; | ||
| 794 | } | ||
| 795 | |||
| 796 | void tRampSampleRateChanged(tRamp* const r) | ||
| 797 | { | ||
| 798 | r->inv_sr_ms = 1.0f / (leaf.sampleRate * 0.001f); | ||
| 799 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms)*((float)r->samples_per_tick); | ||
| 800 | } | ||
| 801 | |||
| 802 | |||
| 803 | /* Exponential Smoother */ | ||
| 804 | void tExpSmooth_init(tExpSmooth* const smooth, float val, float factor) | ||
| 805 | { // factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms | ||
| 806 | smooth->curr=val; | ||
| 807 | smooth->dest=val; | ||
| 808 | if (factor<0) factor=0; | ||
| 809 | if (factor>1) factor=1; | ||
| 810 | smooth->factor=factor; | ||
| 811 | smooth->oneminusfactor=1.0f-factor; | ||
| 812 | } | ||
| 813 | |||
| 814 | void tExpSmooth_free(tExpSmooth* const smooth) | ||
| 815 | { | ||
| 816 | |||
| 817 | } | ||
| 818 | |||
| 819 | int tExpSmooth_setFactor(tExpSmooth* const smooth, float factor) | ||
| 820 | { // factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms | ||
| 821 | if (factor<0) | ||
| 822 | factor=0; | ||
| 823 | else | ||
| 824 | if (factor>1) factor=1; | ||
| 825 | smooth->factor=factor; | ||
| 826 | smooth->oneminusfactor=1.0f-factor; | ||
| 827 | return 0; | ||
| 828 | } | ||
| 829 | |||
| 830 | int tExpSmooth_setDest(tExpSmooth* const smooth, float dest) | ||
| 831 | { | ||
| 832 | smooth->dest=dest; | ||
| 833 | return 0; | ||
| 834 | } | ||
| 835 | |||
| 836 | int tExpSmooth_setVal(tExpSmooth* const smooth, float val) | ||
| 837 | { | ||
| 838 | smooth->curr=val; | ||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 842 | float tExpSmooth_tick(tExpSmooth* const smooth) | ||
| 843 | { | ||
| 844 | smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr; | ||
| 845 | return smooth->curr; | ||
| 846 | } | ||
| 847 | |||
| 848 | float tExpSmooth_sample(tExpSmooth* const smooth) | ||
| 849 | { | ||
| 850 | return smooth->curr; | ||
| 851 | } | ||
| 852 | |||
| 853 | |||
| 854 | /* Power Follower */ | ||
| 855 | |||
| 856 | void tPwrFollow_init(tPwrFollow* const p, float factor) | ||
| 857 | { | ||
| 858 | p->curr=0.0f; | ||
| 859 | p->factor=factor; | ||
| 860 | p->oneminusfactor=1.0f-factor; | ||
| 861 | } | ||
| 862 | |||
| 863 | void tPwrFollow_free(tPwrFollow* const p) | ||
| 864 | { | ||
| 865 | |||
| 866 | } | ||
| 867 | |||
| 868 | int tPwrFollow_setFactor(tPwrFollow* const p, float factor) | ||
| 869 | { | ||
| 870 | if (factor<0) factor=0; | ||
| 871 | if (factor>1) factor=1; | ||
| 872 | p->factor=factor; | ||
| 873 | p->oneminusfactor=1.0f-factor; | ||
| 874 | return 0; | ||
| 875 | } | ||
| 876 | |||
| 877 | float tPwrFollow_tick(tPwrFollow* const p, float input) | ||
| 878 | { | ||
| 879 | p->curr = p->factor*input*input+p->oneminusfactor*p->curr; | ||
| 880 | return p->curr; | ||
| 881 | } | ||
| 882 | |||
| 883 | float tPwrFollow_sample(tPwrFollow* const p) | ||
| 884 | { | ||
| 885 | return p->curr; | ||
| 886 | } | ||
| 887 | |||
| 888 | /* Feedback Leveler */ | ||
| 889 | |||
| 890 | void tFBleveller_init(tFBleveller* const p, float targetLevel, float factor, float strength, int mode) | ||
| 891 | { | ||
| 892 | p->curr=0.0f; | ||
| 893 | p->targetLevel=targetLevel; | ||
| 894 | tPwrFollow_init(&p->pwrFlw,factor); | ||
| 895 | p->mode=mode; | ||
| 896 | p->strength=strength; | ||
| 897 | } | ||
| 898 | |||
| 899 | void tFBleveller_free(tFBleveller* const p) | ||
| 900 | { | ||
| 901 | tPwrFollow_free(&p->pwrFlw); | ||
| 902 | } | ||
| 903 | |||
| 904 | int tFBleveller_setStrength(tFBleveller* const p, float strength) | ||
| 905 | { // strength is how strongly level diff is affecting the amp ratio | ||
| 906 | // try 0.125 for a start | ||
| 907 | p->strength=strength; | ||
| 908 | return 0; | ||
| 909 | } | ||
| 910 | |||
| 911 | int tFBleveller_setFactor(tFBleveller* const p, float factor) | ||
| 912 | { | ||
| 913 | tPwrFollow_setFactor(&p->pwrFlw,factor); | ||
| 914 | return 0; | ||
| 915 | } | ||
| 916 | |||
| 917 | int tFBleveller_setMode(tFBleveller* const p, int mode) | ||
| 918 | { // 0 for decaying with upwards lev limiting, 1 for constrained absolute level (also downwards limiting) | ||
| 919 | p->mode=mode; | ||
| 920 | return 0; | ||
| 921 | } | ||
| 922 | |||
| 923 | float tFBleveller_tick(tFBleveller* const p, float input) | ||
| 924 | { | ||
| 925 | float levdiff=(tPwrFollow_tick(&p->pwrFlw, input)-p->targetLevel); | ||
| 926 | if (p->mode==0 && levdiff<0) levdiff=0; | ||
| 927 | p->curr=input*(1-p->strength*levdiff); | ||
| 928 | return p->curr; | ||
| 929 | } | ||
| 930 | |||
| 931 | float tFBleveller_sample(tFBleveller* const p) | ||
| 932 | { | ||
| 933 | return p->curr; | ||
| 934 | } | ||
| 935 | |||
| 936 | |||
| 937 | int tFBleveller_setTargetLevel (tFBleveller* const p, float TargetLevel) | ||
| 938 | { | ||
| 939 | p->targetLevel=TargetLevel; | ||
| 940 | } | ||
| 941 | |||
| 942 | ///Reed Table model | ||
| 943 | //default values from STK are 0.6 offset and -0.8 slope | ||
| 944 | |||
| 945 | void tReedTable_init (tReedTable* const p, float offset, float slope) | ||
| 946 | { | ||
| 947 | p->offset = offset; | ||
| 948 | p->slope = slope; | ||
| 949 | } | ||
| 950 | |||
| 951 | void tReedTable_free (tReedTable* const p) | ||
| 952 | { | ||
| 953 | ; | ||
| 954 | } | ||
| 955 | |||
| 956 | float tReedTable_tick (tReedTable* const p, float input) | ||
| 957 | { | ||
| 958 | // The input is differential pressure across the reed. | ||
| 959 | float output = p->offset + (p->slope * input); | ||
| 960 | |||
| 961 | // If output is > 1, the reed has slammed shut and the | ||
| 962 | // reflection function value saturates at 1.0. | ||
| 963 | if ( output > 1.0f) output = 1.0f; | ||
| 964 | |||
| 965 | // This is nearly impossible in a physical system, but | ||
| 966 | // a reflection function value of -1.0 corresponds to | ||
| 967 | // an open end (and no discontinuity in bore profile). | ||
| 968 | if ( output < -1.0f) output = -1.0f; | ||
| 969 | |||
| 970 | return output; | ||
| 971 | } | ||
| 972 | |||
| 973 | float tReedTable_tanh_tick (tReedTable* const p, float input) | ||
| 974 | { | ||
| 975 | // The input is differential pressure across the reed. | ||
| 976 | float output = p->offset + (p->slope * input); | ||
| 977 | |||
| 978 | // If output is > 1, the reed has slammed shut and the | ||
| 979 | // reflection function value saturates at 1.0. | ||
| 980 | return tanhf(output); | ||
| 981 | } | ||
| 982 | |||
| 983 | void tReedTable_setOffset (tReedTable* const p, float offset) | ||
| 984 | { | ||
| 985 | p->offset = offset; | ||
| 986 | } | ||
| 987 | |||
| 988 | void tReedTable_setSlope (tReedTable* const p, float slope) | ||
| 989 | { | ||
| 990 | p->slope = slope; | ||
| 991 | } | ||
| 992 | |||
| 993 | |||
| 994 | |||
| 995 | /* Simple Living String*/ | ||
| 996 | |||
| 997 | void tSimpleLivingString_init(tSimpleLivingString* const p, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode) | ||
| 998 | { | ||
| 999 | p->curr=0.0f; | ||
| 1000 | tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions) | ||
| 1001 | tSimpleLivingString_setFreq(p, freq); | ||
| 1002 | tDelayL_init(&p->delayLine,p->waveLengthInSamples, 2400); | ||
| 1003 | tOnePole_init(&p->bridgeFilter, dampFreq); | ||
| 1004 | tHighpass_init(&p->DCblocker,13); | ||
| 1005 | p->decay=decay; | ||
| 1006 | tFBleveller_init(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode); | ||
| 1007 | p->levMode=levMode; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | void tSimpleLivingString_free(tSimpleLivingString* const p) | ||
| 1011 | { | ||
| 1012 | tExpSmooth_free(&p->wlSmooth); | ||
| 1013 | tDelayL_free(&p->delayLine); | ||
| 1014 | tOnePole_free(&p->bridgeFilter); | ||
| 1015 | tHighpass_free(&p->DCblocker); | ||
| 1016 | tFBleveller_free(&p->fbLev); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | int tSimpleLivingString_setFreq(tSimpleLivingString* const p, float freq) | ||
| 1020 | { | ||
| 1021 | if (freq<20) freq=20; | ||
| 1022 | else if (freq>10000) freq=10000; | ||
| 1023 | p->waveLengthInSamples = leaf.sampleRate/freq; | ||
| 1024 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 1025 | return 0; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | int tSimpleLivingString_setWaveLength(tSimpleLivingString* const p, float waveLength) | ||
| 1029 | { | ||
| 1030 | if (waveLength<4.8) waveLength=4.8; | ||
| 1031 | else if (waveLength>2400) waveLength=2400; | ||
| 1032 | p->waveLengthInSamples = waveLength; | ||
| 1033 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 1034 | return 0; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | int tSimpleLivingString_setDampFreq(tSimpleLivingString* const p, float dampFreq) | ||
| 1038 | { | ||
| 1039 | tOnePole_setFreq(&p->bridgeFilter, dampFreq); | ||
| 1040 | return 0; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | int tSimpleLivingString_setDecay(tSimpleLivingString* const p, float decay) | ||
| 1044 | { | ||
| 1045 | p->decay=decay; | ||
| 1046 | return 0; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | int tSimpleLivingString_setTargetLev(tSimpleLivingString* const p, float targetLev) | ||
| 1050 | { | ||
| 1051 | tFBleveller_setTargetLevel(&p->fbLev, targetLev); | ||
| 1052 | return 0; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | int tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor) | ||
| 1056 | { | ||
| 1057 | tFBleveller_setFactor(&p->fbLev, levSmoothFactor); | ||
| 1058 | return 0; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | int tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength) | ||
| 1062 | { | ||
| 1063 | tFBleveller_setStrength(&p->fbLev, levStrength); | ||
| 1064 | return 0; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | int tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode) | ||
| 1068 | { | ||
| 1069 | tFBleveller_setMode(&p->fbLev, levMode); | ||
| 1070 | p->levMode=levMode; | ||
| 1071 | return 0; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | float tSimpleLivingString_tick(tSimpleLivingString* const p, float input) | ||
| 1075 | { | ||
| 1076 | float stringOut=tOnePole_tick(&p->bridgeFilter,tDelayL_tickOut(&p->delayLine)); | ||
| 1077 | float stringInput=tHighpass_tick(&p->DCblocker, tFBleveller_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input)); | ||
| 1078 | tDelayL_tickIn(&p->delayLine, stringInput); | ||
| 1079 | tDelayL_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth)); | ||
| 1080 | p->curr = stringOut; | ||
| 1081 | return p->curr; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | float tSimpleLivingString_sample(tSimpleLivingString* const p) | ||
| 1085 | { | ||
| 1086 | return p->curr; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | /* Living String*/ | ||
| 1090 | |||
| 1091 | void tLivingString_init(tLivingString* const p, float freq, float pickPos, float prepIndex, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode) | ||
| 1092 | { | ||
| 1093 | p->curr=0.0f; | ||
| 1094 | tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions) | ||
| 1095 | tLivingString_setFreq(p, freq); | ||
| 1096 | tExpSmooth_init(&p->ppSmooth, pickPos, 0.01); // smoother for pick position | ||
| 1097 | tLivingString_setPickPos(p, pickPos); | ||
| 1098 | p->prepIndex=prepIndex; | ||
| 1099 | tDelayL_init(&p->delLF,p->waveLengthInSamples, 2400); | ||
| 1100 | tDelayL_init(&p->delUF,p->waveLengthInSamples, 2400); | ||
| 1101 | tDelayL_init(&p->delUB,p->waveLengthInSamples, 2400); | ||
| 1102 | tDelayL_init(&p->delLB,p->waveLengthInSamples, 2400); | ||
| 1103 | tOnePole_init(&p->bridgeFilter, dampFreq); | ||
| 1104 | tOnePole_init(&p->nutFilter, dampFreq); | ||
| 1105 | tOnePole_init(&p->prepFilterU, dampFreq); | ||
| 1106 | tOnePole_init(&p->prepFilterL, dampFreq); | ||
| 1107 | tHighpass_init(&p->DCblockerU,13); | ||
| 1108 | tHighpass_init(&p->DCblockerL,13); | ||
| 1109 | p->decay=decay; | ||
| 1110 | tFBleveller_init(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode); | ||
| 1111 | tFBleveller_init(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode); | ||
| 1112 | p->levMode=levMode; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | void tLivingString_free(tLivingString* const p) | ||
| 1116 | { | ||
| 1117 | tExpSmooth_free(&p->wlSmooth); | ||
| 1118 | tExpSmooth_free(&p->ppSmooth); | ||
| 1119 | tDelayL_free(&p->delLF); | ||
| 1120 | tDelayL_free(&p->delUF); | ||
| 1121 | tDelayL_free(&p->delUB); | ||
| 1122 | tDelayL_free(&p->delLB); | ||
| 1123 | tOnePole_free(&p->bridgeFilter); | ||
| 1124 | tOnePole_free(&p->nutFilter); | ||
| 1125 | tOnePole_free(&p->prepFilterU); | ||
| 1126 | tOnePole_free(&p->prepFilterL); | ||
| 1127 | tHighpass_free(&p->DCblockerU); | ||
| 1128 | tHighpass_free(&p->DCblockerL); | ||
| 1129 | tFBleveller_free(&p->fbLevU); | ||
| 1130 | tFBleveller_free(&p->fbLevL); | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | int tLivingString_setFreq(tLivingString* const p, float freq) | ||
| 1134 | { // NOTE: It is faster to set wavelength in samples directly | ||
| 1135 | if (freq<20) freq=20; | ||
| 1136 | else if (freq>10000) freq=10000; | ||
| 1137 | p->waveLengthInSamples = leaf.sampleRate/freq; | ||
| 1138 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 1139 | return 0; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | int tLivingString_setWaveLength(tLivingString* const p, float waveLength) | ||
| 1143 | { | ||
| 1144 | if (waveLength<4.8) waveLength=4.8; | ||
| 1145 | else if (waveLength>2400) waveLength=2400; | ||
| 1146 | p->waveLengthInSamples = waveLength; | ||
| 1147 | tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | ||
| 1148 | return 0; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | int tLivingString_setPickPos(tLivingString* const p, float pickPos) | ||
| 1152 | { // between 0 and 1 | ||
| 1153 | if (pickPos<0.f) pickPos=0.f; | ||
| 1154 | else if (pickPos>1.f) pickPos=1.f; | ||
| 1155 | p->pickPos = pickPos; | ||
| 1156 | tExpSmooth_setDest(&p->ppSmooth, p->pickPos); | ||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | int tLivingString_setPrepIndex(tLivingString* const p, float prepIndex) | ||
| 1161 | { // between 0 and 1 | ||
| 1162 | if (prepIndex<0.f) prepIndex=0.f; | ||
| 1163 | else if (prepIndex>1.f) prepIndex=1.f; | ||
| 1164 | p->prepIndex = prepIndex; | ||
| 1165 | return 0; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | int tLivingString_setDampFreq(tLivingString* const p, float dampFreq) | ||
| 1169 | { | ||
| 1170 | tOnePole_setFreq(&p->bridgeFilter, dampFreq); | ||
| 1171 | tOnePole_setFreq(&p->nutFilter, dampFreq); | ||
| 1172 | tOnePole_setFreq(&p->prepFilterU, dampFreq); | ||
| 1173 | tOnePole_setFreq(&p->prepFilterL, dampFreq); | ||
| 1174 | return 0; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | int tLivingString_setDecay(tLivingString* const p, float decay) | ||
| 1178 | { | ||
| 1179 | p->decay=decay; | ||
| 1180 | return 0; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | int tLivingString_setTargetLev(tLivingString* const p, float targetLev) | ||
| 1184 | { | ||
| 1185 | tFBleveller_setTargetLevel(&p->fbLevU, targetLev); | ||
| 1186 | tFBleveller_setTargetLevel(&p->fbLevL, targetLev); | ||
| 1187 | return 0; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | int tLivingString_setLevSmoothFactor(tLivingString* const p, float levSmoothFactor) | ||
| 1191 | { | ||
| 1192 | tFBleveller_setFactor(&p->fbLevU, levSmoothFactor); | ||
| 1193 | tFBleveller_setFactor(&p->fbLevL, levSmoothFactor); | ||
| 1194 | return 0; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | int tLivingString_setLevStrength(tLivingString* const p, float levStrength) | ||
| 1198 | { | ||
| 1199 | tFBleveller_setStrength(&p->fbLevU, levStrength); | ||
| 1200 | tFBleveller_setStrength(&p->fbLevL, levStrength); | ||
| 1201 | return 0; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | int tLivingString_setLevMode(tLivingString* const p, int levMode) | ||
| 1205 | { | ||
| 1206 | tFBleveller_setMode(&p->fbLevU, levMode); | ||
| 1207 | tFBleveller_setMode(&p->fbLevL, levMode); | ||
| 1208 | p->levMode=levMode; | ||
| 1209 | return 0; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | float tLivingString_tick(tLivingString* const p, float input) | ||
| 1213 | { | ||
| 1214 | // from pickPos upwards=forwards | ||
| 1215 | float fromLF=tDelayL_tickOut(&p->delLF); | ||
| 1216 | float fromUF=tDelayL_tickOut(&p->delUF); | ||
| 1217 | float fromUB=tDelayL_tickOut(&p->delUB); | ||
| 1218 | float fromLB=tDelayL_tickOut(&p->delLB); | ||
| 1219 | // into upper half of string, from nut, going backwards | ||
| 1220 | float fromNut=-tFBleveller_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->nutFilter, fromUF))); | ||
| 1221 | tDelayL_tickIn(&p->delUB, fromNut); | ||
| 1222 | // into lower half of string, from pickpoint, going backwards | ||
| 1223 | float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF); | ||
| 1224 | float intoLower=p->prepIndex*fromLowerPrep+(1-p->prepIndex)*fromUB+input; | ||
| 1225 | tDelayL_tickIn(&p->delLB, intoLower); | ||
| 1226 | // into lower half of string, from bridge | ||
| 1227 | float fromBridge=-tFBleveller_tick(&p->fbLevL, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->bridgeFilter, fromLB))); | ||
| 1228 | tDelayL_tickIn(&p->delLF, fromBridge); | ||
| 1229 | // into upper half of string, from pickpoint, going forwards/upwards | ||
| 1230 | float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB); | ||
| 1231 | float intoUpper=p->prepIndex*fromUpperPrep+(1-p->prepIndex)*fromLF+input; | ||
| 1232 | tDelayL_tickIn(&p->delUF, intoUpper); | ||
| 1233 | // update all delay lengths | ||
| 1234 | float pickP=tExpSmooth_tick(&p->ppSmooth); | ||
| 1235 | float wLen=tExpSmooth_tick(&p->wlSmooth); | ||
| 1236 | float lowLen=pickP*wLen; | ||
| 1237 | float upLen=(1-pickP)*wLen; | ||
| 1238 | tDelayL_setDelay(&p->delLF, lowLen); | ||
| 1239 | tDelayL_setDelay(&p->delLB, lowLen); | ||
| 1240 | tDelayL_setDelay(&p->delUF, upLen); | ||
| 1241 | tDelayL_setDelay(&p->delUB, upLen); | ||
| 1242 | p->curr = fromBridge; | ||
| 1243 | return p->curr; | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | float tLivingString_sample(tLivingString* const p) | ||
| 1247 | { | ||
| 1248 | return p->curr; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | |||
| 1252 | /* Stack */ | ||
| 1253 | |||
| 1254 | void tStack_init(tStack* const ns) | ||
| 1255 | { | ||
| 1256 | ns->ordered = OFALSE; | ||
| 1257 | ns->size = 0; | ||
| 1258 | ns->pos = 0; | ||
| 1259 | ns->capacity = STACK_SIZE; | ||
| 1260 | |||
| 1261 | for (int i = 0; i < STACK_SIZE; i++) ns->data[i] = -1; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | void tStack_free(tStack* const ns) | ||
| 1265 | { | ||
| 1266 | |||
| 1267 | } | ||
| 1268 | |||
| 1269 | // If stack contains note, returns index. Else returns -1; | ||
| 1270 | int tStack_contains(tStack* const ns, uint16_t noteVal) | ||
| 1271 | { | ||
| 1272 | for (int i = 0; i < ns->size; i++) | ||
| 1273 | { | ||
| 1274 | if (ns->data[i] == noteVal) return i; | ||
| 1275 | } | ||
| 1276 | return -1; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | void tStack_add(tStack* const ns, uint16_t noteVal) | ||
| 1280 | { | ||
| 1281 | uint8_t j; | ||
| 1282 | |||
| 1283 | int whereToInsert = 0; | ||
| 1284 | if (ns->ordered) | ||
| 1285 | { | ||
| 1286 | for (j = 0; j < ns->size; j++) | ||
| 1287 | { | ||
| 1288 | if (noteVal > ns->data[j]) | ||
| 1289 | { | ||
| 1290 | if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1)) | ||
| 1291 | { | ||
| 1292 | whereToInsert = j+1; | ||
| 1293 | break; | ||
| 1294 | } | ||
| 1295 | } | ||
| 1296 | } | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | //first move notes that are already in the stack one position to the right | ||
| 1300 | for (j = ns->size; j > whereToInsert; j--) | ||
| 1301 | { | ||
| 1302 | ns->data[j] = ns->data[(j - 1)]; | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | //then, insert the new note into the front of the stack | ||
| 1306 | ns->data[whereToInsert] = noteVal; | ||
| 1307 | |||
| 1308 | ns->size++; | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | int tStack_addIfNotAlreadyThere(tStack* const ns, uint16_t noteVal) | ||
| 1312 | { | ||
| 1313 | uint8_t j; | ||
| 1314 | |||
| 1315 | int added = 0; | ||
| 1316 | |||
| 1317 | if (tStack_contains(ns, noteVal) == -1) | ||
| 1318 | { | ||
| 1319 | int whereToInsert = 0; | ||
| 1320 | if (ns->ordered) | ||
| 1321 | { | ||
| 1322 | for (j = 0; j < ns->size; j++) | ||
| 1323 | { | ||
| 1324 | if (noteVal > ns->data[j]) | ||
| 1325 | { | ||
| 1326 | if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1)) | ||
| 1327 | { | ||
| 1328 | whereToInsert = j+1; | ||
| 1329 | break; | ||
| 1330 | } | ||
| 1331 | } | ||
| 1332 | } | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | //first move notes that are already in the stack one position to the right | ||
| 1336 | for (j = ns->size; j > whereToInsert; j--) | ||
| 1337 | { | ||
| 1338 | ns->data[j] = ns->data[(j - 1)]; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | //then, insert the new note into the front of the stack | ||
| 1342 | ns->data[whereToInsert] = noteVal; | ||
| 1343 | |||
| 1344 | ns->size++; | ||
| 1345 | |||
| 1346 | added = 1; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | return added; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | |||
| 1353 | // Remove noteVal. return 1 if removed, 0 if not | ||
| 1354 | int tStack_remove(tStack* const ns, uint16_t noteVal) | ||
| 1355 | { | ||
| 1356 | uint8_t k; | ||
| 1357 | int foundIndex = tStack_contains(ns, noteVal); | ||
| 1358 | int removed = 0; | ||
| 1359 | |||
| 1360 | if (foundIndex >= 0) | ||
| 1361 | { | ||
| 1362 | for (k = 0; k < (ns->size - foundIndex); k++) | ||
| 1363 | { | ||
| 1364 | if ((k+foundIndex) >= (ns->capacity - 1)) | ||
| 1365 | { | ||
| 1366 | ns->data[k + foundIndex] = -1; | ||
| 1367 | } | ||
| 1368 | else | ||
| 1369 | { | ||
| 1370 | ns->data[k + foundIndex] = ns->data[k + foundIndex + 1]; | ||
| 1371 | if ((k + foundIndex) == (ns->size - 1)) | ||
| 1372 | { | ||
| 1373 | ns->data[k + foundIndex + 1] = -1; | ||
| 1374 | } | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | } | ||
| 1378 | // in case it got put on the stack multiple times | ||
| 1379 | foundIndex--; | ||
| 1380 | ns->size--; | ||
| 1381 | removed = 1; | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | |||
| 1385 | |||
| 1386 | return removed; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | // Doesn't change size of data types | ||
| 1390 | void tStack_setCapacity(tStack* const ns, uint16_t cap) | ||
| 1391 | { | ||
| 1392 | if (cap <= 0) | ||
| 1393 | ns->capacity = 1; | ||
| 1394 | else if (cap <= STACK_SIZE) | ||
| 1395 | ns->capacity = cap; | ||
| 1396 | else | ||
| 1397 | ns->capacity = STACK_SIZE; | ||
| 1398 | |||
| 1399 | for (int i = cap; i < STACK_SIZE; i++) | ||
| 1400 | { | ||
| 1401 | if ((int)ns->data[i] != -1) | ||
| 1402 | { | ||
| 1403 | ns->data[i] = -1; | ||
| 1404 | ns->size -= 1; | ||
| 1405 | } | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | if (ns->pos >= cap) | ||
| 1409 | { | ||
| 1410 | ns->pos = 0; | ||
| 1411 | } | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | int tStack_getSize(tStack* const ns) | ||
| 1415 | { | ||
| 1416 | return ns->size; | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | void tStack_clear(tStack* const ns) | ||
| 1420 | { | ||
| 1421 | for (int i = 0; i < STACK_SIZE; i++) | ||
| 1422 | { | ||
| 1423 | ns->data[i] = -1; | ||
| 1424 | } | ||
| 1425 | ns->pos = 0; | ||
| 1426 | ns->size = 0; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | // Next item in order of addition to stack. Return 0-31 if there is a next item to move to. Returns -1 otherwise. | ||
| 1430 | int tStack_next(tStack* const ns) | ||
| 1431 | { | ||
| 1432 | int step = 0; | ||
| 1433 | if (ns->size != 0) // if there is at least one note in the stack | ||
| 1434 | { | ||
| 1435 | if (ns->pos > 0) // if you're not at the most recent note (first one), then go backward in the array (moving from earliest to latest) | ||
| 1436 | { | ||
| 1437 | ns->pos--; | ||
| 1438 | } | ||
| 1439 | else | ||
| 1440 | { | ||
| 1441 | ns->pos = (ns->size - 1); // if you are the most recent note, go back to the earliest note in the array | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | step = ns->data[ns->pos]; | ||
| 1445 | return step; | ||
| 1446 | } | ||
| 1447 | else | ||
| 1448 | { | ||
| 1449 | return -1; | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | int tStack_get(tStack* const ns, int which) | ||
| 1454 | { | ||
| 1455 | return ns->data[which]; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | int tStack_first(tStack* const ns) | ||
| 1459 | { | ||
| 1460 | return ns->data[0]; | ||
| 1461 | } | ||
| 1462 | /******************************************************************************/ | ||
| 1463 | /***************** static function declarations *******************************/ | ||
| 1464 | /******************************************************************************/ | ||
| 1465 | |||
| 1466 | static void solad_init(tSOLAD *w); | ||
| 1467 | static inline float read_sample(tSOLAD *w, float floatindex); | ||
| 1468 | static void pitchdown(tSOLAD *w, float *out); | ||
| 1469 | static void pitchup(tSOLAD *w, float *out); | ||
| 1470 | |||
| 1471 | /******************************************************************************/ | ||
| 1472 | /***************** public access functions ************************************/ | ||
| 1473 | /******************************************************************************/ | ||
| 1474 | |||
| 1475 | // init | ||
| 1476 | void tSOLAD_init(tSOLAD* const w) | ||
| 1477 | { | ||
| 1478 | w->pitchfactor = 1.; | ||
| 1479 | w->delaybuf = (float*) leaf_alloc(sizeof(float) * (LOOPSIZE+16)); | ||
| 1480 | solad_init(w); | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | void tSOLAD_free(tSOLAD* const w) | ||
| 1484 | { | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | // send one block of input samples, receive one block of output samples | ||
| 1488 | void tSOLAD_ioSamples(tSOLAD* const w, float* in, float* out, int blocksize) | ||
| 1489 | { | ||
| 1490 | int i = w->timeindex; | ||
| 1491 | int n = w->blocksize = blocksize; | ||
| 1492 | |||
| 1493 | if(!i) w->delaybuf[LOOPSIZE] = in[0]; // copy one sample for interpolation | ||
| 1494 | while(n--) w->delaybuf[i++] = *in++; // copy one input block to delay buffer | ||
| 1495 | |||
| 1496 | if(w->pitchfactor > 1) pitchup(w, out); | ||
| 1497 | else pitchdown(w, out); | ||
| 1498 | |||
| 1499 | w->timeindex += blocksize; | ||
| 1500 | w->timeindex &= LOOPMASK; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | // set periodicity analysis data | ||
| 1504 | void tSOLAD_setPeriod(tSOLAD* const w, float period) | ||
| 1505 | { | ||
| 1506 | if(period > MAXPERIOD) period = MAXPERIOD; | ||
| 1507 | if(period > MINPERIOD) w->period = period; // ignore period when too small | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | // set pitch factor between 0.25 and 4 | ||
| 1511 | void tSOLAD_setPitchFactor(tSOLAD* const w, float pitchfactor) | ||
| 1512 | { | ||
| 1513 | if(pitchfactor < 0.25) pitchfactor = 0.25; | ||
| 1514 | else if(pitchfactor > 4.) pitchfactor = 4.; | ||
| 1515 | w->pitchfactor = pitchfactor; | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | // force readpointer lag | ||
| 1519 | void tSOLAD_setReadLag(tSOLAD* const w, float readlag) | ||
| 1520 | { | ||
| 1521 | if(readlag < 0) readlag = 0; | ||
| 1522 | if(readlag < w->readlag) // do not jump backward, only forward | ||
| 1523 | { | ||
| 1524 | w->jump = w->readlag - readlag; | ||
| 1525 | w->readlag = readlag; | ||
| 1526 | w->xfadelength = readlag; | ||
| 1527 | w->xfadevalue = 1; | ||
| 1528 | } | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | // reset state variables | ||
| 1532 | void tSOLAD_resetState(tSOLAD* const w) | ||
| 1533 | { | ||
| 1534 | int n = LOOPSIZE + 1; | ||
| 1535 | float *buf = w->delaybuf; | ||
| 1536 | |||
| 1537 | while(n--) *buf++ = 0; | ||
| 1538 | solad_init(w); | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /******************************************************************************/ | ||
| 1542 | /******************** private procedures **************************************/ | ||
| 1543 | /******************************************************************************/ | ||
| 1544 | |||
| 1545 | /* | ||
| 1546 | Function pitchdown() is called to read samples from the delay buffer when pitch | ||
| 1547 | factor is between 0.25 and 1. The read pointer lags behind because of the slowed | ||
| 1548 | down speed, and it must jump forward towards the write pointer soon as there is | ||
| 1549 | sufficient space to jump. That is, if there is at least one period of the input | ||
| 1550 | signal between read pointer and write pointer. When short periods follow up on | ||
| 1551 | long periods, the read pointer may have space to jump over more than one period | ||
| 1552 | lenghts. Jump length must be [periodlength ^ 2] in any case. | ||
| 1553 | |||
| 1554 | A linear crossfade function joins the jump-from point with the jump-to point. | ||
| 1555 | The crossfade must be completed before another read pointer jump is allowed. | ||
| 1556 | Length of the crossfade function is stored as a number of samples in terms of | ||
| 1557 | the input sample rate. This length is dynamically translated | ||
| 1558 | to a crossfade length expressed in output reading rate, according to pitch | ||
| 1559 | factor which can change before the crossfade is completed. Crossfade length does | ||
| 1560 | not cover an invariable length in periods for all pitch transposition factors. | ||
| 1561 | For pitch factors from 0.5 till 1, crossfade length is stretched in the | ||
| 1562 | output just as much as the signal itself, as crossfade speed is set to equal | ||
| 1563 | pitch factor. For pitch factors below 0.5, the read pointer wants to jump | ||
| 1564 | forward before one period is read, therefore the crossfade length as expressed | ||
| 1565 | in output periods must be shorter. Crossfade speed is set to [1 - pitchfactor] | ||
| 1566 | for those cases. Pitch factor 0.5 is the natural switch point between crossfade | ||
| 1567 | speeds [pitchfactor] and [1 - pitchfactor] because 0.5 == 1 - 0.5. The crossfade | ||
| 1568 | speed modification for pitch factors below 0.5 also means that much of the | ||
| 1569 | original signal content will be skipped. | ||
| 1570 | */ | ||
| 1571 | |||
| 1572 | |||
| 1573 | static void pitchdown(tSOLAD* const w, float *out) | ||
| 1574 | { | ||
| 1575 | int n = w->blocksize; | ||
| 1576 | float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values! | ||
| 1577 | float pitchfactor = w->pitchfactor; | ||
| 1578 | float period = w->period; | ||
| 1579 | float readlag = w->readlag; | ||
| 1580 | float readlagstep = 1 - pitchfactor; | ||
| 1581 | float jump = w->jump; | ||
| 1582 | float xfadevalue = w->xfadevalue; | ||
| 1583 | float xfadelength = w->xfadelength; | ||
| 1584 | float xfadespeed, xfadestep, readindex, outputsample; | ||
| 1585 | |||
| 1586 | if(pitchfactor > 0.5) xfadespeed = pitchfactor; | ||
| 1587 | else xfadespeed = 1 - pitchfactor; | ||
| 1588 | xfadestep = xfadespeed / xfadelength; | ||
| 1589 | |||
| 1590 | while(n--) | ||
| 1591 | { | ||
| 1592 | if(readlag > period) // check if read pointer may jump forward... | ||
| 1593 | { | ||
| 1594 | if(xfadevalue <= 0) // ...but do not interrupt crossfade | ||
| 1595 | { | ||
| 1596 | jump = period; // jump forward | ||
| 1597 | while((jump * 2) < readlag) jump *= 2; // use available space | ||
| 1598 | readlag -= jump; // reduce read pointer lag | ||
| 1599 | xfadevalue = 1; // start crossfade | ||
| 1600 | xfadelength = period - 1; | ||
| 1601 | xfadestep = xfadespeed / xfadelength; | ||
| 1602 | } | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | readindex = refindex - readlag; | ||
| 1606 | outputsample = read_sample(w, readindex); | ||
| 1607 | |||
| 1608 | if(xfadevalue > 0) | ||
| 1609 | { | ||
| 1610 | outputsample *= (1 - xfadevalue); // fadein | ||
| 1611 | outputsample += read_sample(w, readindex - jump) * xfadevalue; // fadeout | ||
| 1612 | xfadevalue -= xfadestep; | ||
| 1613 | } | ||
| 1614 | |||
| 1615 | *out++ = outputsample; | ||
| 1616 | refindex += 1; | ||
| 1617 | readlag += readlagstep; | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | w->jump = jump; // state variables | ||
| 1621 | w->readlag = readlag; | ||
| 1622 | w->xfadevalue = xfadevalue; | ||
| 1623 | w->xfadelength = xfadelength; | ||
| 1624 | } | ||
| 1625 | |||
| 1626 | |||
| 1627 | /* | ||
| 1628 | Function pitchup() for pitch factors above 1 is more complicated than | ||
| 1629 | pitchdown(). The read pointer increments faster than the write pointer and a | ||
| 1630 | backward jump must happen in time, reckoning with the crossfade region. The read | ||
| 1631 | pointer backward jump length is always one period. In order to minimize the area | ||
| 1632 | of signal duplicates, crossfade length is aimed at [period / pitchfactor]. | ||
| 1633 | This leads to a crossfade speed of [pitchfactor * pitchfactor]. | ||
| 1634 | |||
| 1635 | Some samples for the fade out (but not all of them) must already be in the | ||
| 1636 | buffer, otherwise we will run out of input samples before the crossfade is | ||
| 1637 | completed. The ratio of past samples and future samples for a crossfade of any | ||
| 1638 | length is as follows: | ||
| 1639 | |||
| 1640 | past samples: xfadelength * (1 - 1 / pitchfactor) | ||
| 1641 | future samples: xfadelength * (1 / pitchfactor) | ||
| 1642 | |||
| 1643 | For example in the case of pitch factor 1.5 this would be: | ||
| 1644 | |||
| 1645 | past samples: xfadelength * (1 - 1 / 1.5) = xfadelength * 1 / 3 | ||
| 1646 | future samples: xfadelength * (1 / 1.5) = xfadelength * 2 / 3 | ||
| 1647 | |||
| 1648 | In the case of pitch factor 4 this would be: | ||
| 1649 | |||
| 1650 | past samples: xfadelength * (1 - 1 / 4) = xfadelength * 3 / 4 | ||
| 1651 | future samples: xfadelength * (1 / 4) = xfadelength * 1 / 4 | ||
| 1652 | |||
| 1653 | The read pointer lag must therefore preserve a minimum dependent on pitch | ||
| 1654 | factor. The minimum is called 'limit' here: | ||
| 1655 | |||
| 1656 | limit = period * (pitchfactor - 1) / pitchfactor * pitchfactor | ||
| 1657 | |||
| 1658 | Components of this expression are combined to reuse them in operations, while | ||
| 1659 | (pitchfactor - 1) is changed to (pitchfactor - 0.99) to avoid numerical | ||
| 1660 | resolution issues for pitch factors slightly above 1: | ||
| 1661 | |||
| 1662 | xfadespeed = pitchfactor * pitchfactor | ||
| 1663 | limitfactor = (pitchfactor - 0.99) / xfadespeed | ||
| 1664 | limit = period * limitfactor | ||
| 1665 | |||
| 1666 | When read lag is smaller than this limit, the read pointer must preferably | ||
| 1667 | jump backward, unless a previous crossfade is not yet completed. Crossfades must | ||
| 1668 | preferably be completed, unless the read pointer lag becomes smaller than zero. | ||
| 1669 | With fluctuating period lengths and pitch factors, the readpointer lag limit may | ||
| 1670 | change from one input block to the next in such a way that the actual lag is | ||
| 1671 | suddenly much smaller than the limit, and the intended crossfade length can not | ||
| 1672 | be applied. Therefore the crossfade length is simply calculated from the | ||
| 1673 | available amount of samples for all cases, like so: | ||
| 1674 | |||
| 1675 | xfadelength = readlag / limitfactor | ||
| 1676 | |||
| 1677 | For most occurrences, this will amount to a crossfade length reduced to | ||
| 1678 | [period / pitchfactor] in the output for pitch factors above 1, while in some | ||
| 1679 | cases it will be considerably shorter. Fortunately, an incidental aberration of | ||
| 1680 | the intended crossfade length hardly ever creates an audible artifact. The | ||
| 1681 | reason to specify preferred crossfade length according to pitch factor is to | ||
| 1682 | minimize the impression of echoes without sacrificing too much of the signal | ||
| 1683 | content. The readpointer jump length remains one period in any case. | ||
| 1684 | |||
| 1685 | Sometimes, the input signal periodicity may decrease substantially between one | ||
| 1686 | signal block and the next. In such cases it may be possible for the read pointer | ||
| 1687 | to jump forward and reduce latency. For every signal block, a check on this | ||
| 1688 | possibility is done. A previous crossfade must be completed before a forward | ||
| 1689 | jump is allowed. | ||
| 1690 | */ | ||
| 1691 | static void pitchup(tSOLAD* const w, float *out) | ||
| 1692 | { | ||
| 1693 | int n = w->blocksize; | ||
| 1694 | float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values | ||
| 1695 | float pitchfactor = w->pitchfactor; | ||
| 1696 | float period = w->period; | ||
| 1697 | float readlag = w->readlag; | ||
| 1698 | float jump = w->jump; | ||
| 1699 | float xfadevalue = w->xfadevalue; | ||
| 1700 | float xfadelength = w->xfadelength; | ||
| 1701 | |||
| 1702 | float readlagstep = pitchfactor - 1; | ||
| 1703 | float xfadespeed = pitchfactor * pitchfactor; | ||
| 1704 | float xfadestep = xfadespeed / xfadelength; | ||
| 1705 | float limitfactor = (pitchfactor - (float)0.99) / xfadespeed; | ||
| 1706 | float limit = period * limitfactor; | ||
| 1707 | float readindex, outputsample; | ||
| 1708 | |||
| 1709 | if((readlag > (period + 2 * limit)) & (xfadevalue < 0)) | ||
| 1710 | { | ||
| 1711 | jump = period; // jump forward | ||
| 1712 | while((jump * 2) < (readlag - 2 * limit)) jump *= 2; // use available space | ||
| 1713 | readlag -= jump; // reduce read pointer lag | ||
| 1714 | xfadevalue = 1; // start crossfade | ||
| 1715 | xfadelength = period - 1; | ||
| 1716 | xfadestep = xfadespeed / xfadelength; | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | while(n--) | ||
| 1720 | { | ||
| 1721 | if(readlag < limit) // check if read pointer should jump backward... | ||
| 1722 | { | ||
| 1723 | if((xfadevalue < 0) | (readlag < 0)) // ...but try not to interrupt crossfade | ||
| 1724 | { | ||
| 1725 | xfadelength = readlag / limitfactor; | ||
| 1726 | if(xfadelength < 1) xfadelength = 1; | ||
| 1727 | xfadestep = xfadespeed / xfadelength; | ||
| 1728 | |||
| 1729 | jump = -period; // jump backward | ||
| 1730 | readlag += period; // increase read pointer lag | ||
| 1731 | xfadevalue = 1; // start crossfade | ||
| 1732 | } | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | readindex = refindex - readlag; | ||
| 1736 | outputsample = read_sample(w, readindex); | ||
| 1737 | |||
| 1738 | if(xfadevalue > 0) | ||
| 1739 | { | ||
| 1740 | outputsample *= (1 - xfadevalue); | ||
| 1741 | outputsample += read_sample(w, readindex - jump) * xfadevalue; | ||
| 1742 | xfadevalue -= xfadestep; | ||
| 1743 | } | ||
| 1744 | |||
| 1745 | *out++ = outputsample; | ||
| 1746 | refindex += 1; | ||
| 1747 | readlag -= readlagstep; | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | w->readlag = readlag; // state variables | ||
| 1751 | w->jump = jump; | ||
| 1752 | w->xfadelength = xfadelength; | ||
| 1753 | w->xfadevalue = xfadevalue; | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | // read one sample from delay buffer, with linear interpolation | ||
| 1757 | static inline float read_sample(tSOLAD* const w, float floatindex) | ||
| 1758 | { | ||
| 1759 | int index = (int)floatindex; | ||
| 1760 | float fraction = floatindex - (float)index; | ||
| 1761 | float *buf = w->delaybuf; | ||
| 1762 | index &= LOOPMASK; | ||
| 1763 | |||
| 1764 | return (buf[index] + (fraction * (buf[index+1] - buf[index]))); | ||
| 1765 | } | ||
| 1766 | |||
| 1767 | static void solad_init(tSOLAD* const w) | ||
| 1768 | { | ||
| 1769 | w->timeindex = 0; | ||
| 1770 | w->xfadevalue = -1; | ||
| 1771 | w->period = INITPERIOD; | ||
| 1772 | w->readlag = INITPERIOD; | ||
| 1773 | w->blocksize = INITPERIOD; | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | /******************************************************************************/ | ||
| 1777 | /***************************** private procedures *****************************/ | ||
| 1778 | /******************************************************************************/ | ||
| 1779 | |||
| 1780 | #define REALFFT mayer_realfft | ||
| 1781 | #define REALIFFT mayer_realifft | ||
| 1782 | |||
| 1783 | static void snac_analyzeframe(tSNAC* const s); | ||
| 1784 | static void snac_autocorrelation(tSNAC* const s); | ||
| 1785 | static void snac_normalize(tSNAC* const s); | ||
| 1786 | static void snac_pickpeak(tSNAC* const s); | ||
| 1787 | static void snac_periodandfidelity(tSNAC* const s); | ||
| 1788 | static void snac_biasbuf(tSNAC* const s); | ||
| 1789 | static float snac_spectralpeak(tSNAC* const s, float periodlength); | ||
| 1790 | |||
| 1791 | |||
| 1792 | /******************************************************************************/ | ||
| 1793 | /******************************** constructor, destructor *********************/ | ||
| 1794 | /******************************************************************************/ | ||
| 1795 | |||
| 1796 | |||
| 1797 | void tSNAC_init(tSNAC* const s, int overlaparg) | ||
| 1798 | { | ||
| 1799 | s->biasfactor = DEFBIAS; | ||
| 1800 | s->timeindex = 0; | ||
| 1801 | s->periodindex = 0; | ||
| 1802 | s->periodlength = 0.; | ||
| 1803 | s->fidelity = 0.; | ||
| 1804 | s->minrms = DEFMINRMS; | ||
| 1805 | s->framesize = SNAC_FRAME_SIZE; | ||
| 1806 | |||
| 1807 | s->inputbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE); | ||
| 1808 | s->processbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE * 2)); | ||
| 1809 | s->spectrumbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE / 2)); | ||
| 1810 | s->biasbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE); | ||
| 1811 | |||
| 1812 | snac_biasbuf(s); | ||
| 1813 | tSNAC_setOverlap(s, overlaparg); | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | void tSNAC_free(tSNAC* const s) | ||
| 1817 | { | ||
| 1818 | leaf_free(s->inputbuf); | ||
| 1819 | leaf_free(s->processbuf); | ||
| 1820 | leaf_free(s->spectrumbuf); | ||
| 1821 | leaf_free(s->biasbuf); | ||
| 1822 | } | ||
| 1823 | /******************************************************************************/ | ||
| 1824 | /************************** public access functions****************************/ | ||
| 1825 | /******************************************************************************/ | ||
| 1826 | |||
| 1827 | |||
| 1828 | void tSNAC_ioSamples(tSNAC* const s, float *in, float *out, int size) | ||
| 1829 | { | ||
| 1830 | int timeindex = s->timeindex; | ||
| 1831 | int mask = s->framesize - 1; | ||
| 1832 | int outindex = 0; | ||
| 1833 | float *inputbuf = s->inputbuf; | ||
| 1834 | float *processbuf = s->processbuf; | ||
| 1835 | |||
| 1836 | // call analysis function when it is time | ||
| 1837 | if(!(timeindex & (s->framesize / s->overlap - 1))) snac_analyzeframe(s); | ||
| 1838 | |||
| 1839 | while(size--) | ||
| 1840 | { | ||
| 1841 | inputbuf[timeindex] = *in++; | ||
| 1842 | out[outindex++] = processbuf[timeindex++]; | ||
| 1843 | timeindex &= mask; | ||
| 1844 | } | ||
| 1845 | s->timeindex = timeindex; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | void tSNAC_setOverlap(tSNAC* const s, int lap) | ||
| 1849 | { | ||
| 1850 | if(!((lap==1)|(lap==2)|(lap==4)|(lap==8))) lap = DEFOVERLAP; | ||
| 1851 | s->overlap = lap; | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | |||
| 1855 | void tSNAC_setBias(tSNAC* const s, float bias) | ||
| 1856 | { | ||
| 1857 | if(bias > 1.) bias = 1.; | ||
| 1858 | if(bias < 0.) bias = 0.; | ||
| 1859 | s->biasfactor = bias; | ||
| 1860 | snac_biasbuf(s); | ||
| 1861 | return; | ||
| 1862 | } | ||
| 1863 | |||
| 1864 | |||
| 1865 | void tSNAC_setMinRMS(tSNAC* const s, float rms) | ||
| 1866 | { | ||
| 1867 | if(rms > 1.) rms = 1.; | ||
| 1868 | if(rms < 0.) rms = 0.; | ||
| 1869 | s->minrms = rms; | ||
| 1870 | return; | ||
| 1871 | } | ||
| 1872 | |||
| 1873 | |||
| 1874 | float tSNAC_getPeriod(tSNAC* const s) | ||
| 1875 | { | ||
| 1876 | return(s->periodlength); | ||
| 1877 | } | ||
| 1878 | |||
| 1879 | |||
| 1880 | float tSNAC_getFidelity(tSNAC* const s) | ||
| 1881 | { | ||
| 1882 | return(s->fidelity); | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | |||
| 1886 | /******************************************************************************/ | ||
| 1887 | /***************************** private procedures *****************************/ | ||
| 1888 | /******************************************************************************/ | ||
| 1889 | |||
| 1890 | |||
| 1891 | // main analysis function | ||
| 1892 | static void snac_analyzeframe(tSNAC* const s) | ||
| 1893 | { | ||
| 1894 | int n, tindex = s->timeindex; | ||
| 1895 | int framesize = s->framesize; | ||
| 1896 | int mask = framesize - 1; | ||
| 1897 | float norm = 1. / sqrt((float)(framesize * 2)); | ||
| 1898 | |||
| 1899 | float *inputbuf = s->inputbuf; | ||
| 1900 | float *processbuf = s->processbuf; | ||
| 1901 | |||
| 1902 | // copy input to processing buffers | ||
| 1903 | for(n=0; n<framesize; n++) | ||
| 1904 | { | ||
| 1905 | processbuf[n] = inputbuf[tindex] * norm; | ||
| 1906 | tindex++; | ||
| 1907 | tindex &= mask; | ||
| 1908 | } | ||
| 1909 | |||
| 1910 | // zeropadding | ||
| 1911 | for(n=framesize; n<(framesize<<1); n++) processbuf[n] = 0.; | ||
| 1912 | |||
| 1913 | // call analysis procedures | ||
| 1914 | snac_autocorrelation(s); | ||
| 1915 | snac_normalize(s); | ||
| 1916 | snac_pickpeak(s); | ||
| 1917 | snac_periodandfidelity(s); | ||
| 1918 | } | ||
| 1919 | |||
| 1920 | |||
| 1921 | static void snac_autocorrelation(tSNAC* const s) | ||
| 1922 | { | ||
| 1923 | int n, m; | ||
| 1924 | int framesize = s->framesize; | ||
| 1925 | int fftsize = framesize * 2; | ||
| 1926 | float *processbuf = s->processbuf; | ||
| 1927 | float *spectrumbuf = s->spectrumbuf; | ||
| 1928 | |||
| 1929 | REALFFT(fftsize, processbuf); | ||
| 1930 | |||
| 1931 | // compute power spectrum | ||
| 1932 | processbuf[0] *= processbuf[0]; // DC | ||
| 1933 | processbuf[framesize] *= processbuf[framesize]; // Nyquist | ||
| 1934 | |||
| 1935 | for(n=1; n<framesize; n++) | ||
| 1936 | { | ||
| 1937 | processbuf[n] = processbuf[n] * processbuf[n] | ||
| 1938 | + processbuf[fftsize-n] * processbuf[fftsize-n]; // imag coefficients appear reversed | ||
| 1939 | processbuf[fftsize-n] = 0.; | ||
| 1940 | } | ||
| 1941 | |||
| 1942 | // store power spectrum up to SR/4 for possible later use | ||
| 1943 | for(m=0; m<(framesize>>1); m++) | ||
| 1944 | { | ||
| 1945 | spectrumbuf[m] = processbuf[m]; | ||
| 1946 | } | ||
| 1947 | |||
| 1948 | // transform power spectrum to autocorrelation function | ||
| 1949 | REALIFFT(fftsize, processbuf); | ||
| 1950 | return; | ||
| 1951 | } | ||
| 1952 | |||
| 1953 | |||
| 1954 | static void snac_normalize(tSNAC* const s) | ||
| 1955 | { | ||
| 1956 | int framesize = s->framesize; | ||
| 1957 | int framesizeplustimeindex = s->framesize + s->timeindex; | ||
| 1958 | int timeindexminusone = s->timeindex - 1; | ||
| 1959 | int n, m; | ||
| 1960 | int mask = framesize - 1; | ||
| 1961 | int seek = framesize * SEEK; | ||
| 1962 | float *inputbuf = s->inputbuf; | ||
| 1963 | float *processbuf= s->processbuf; | ||
| 1964 | float signal1, signal2; | ||
| 1965 | |||
| 1966 | // minimum RMS implemented as minimum autocorrelation at index 0 | ||
| 1967 | // functionally equivalent to white noise floor | ||
| 1968 | float rms = s->minrms / sqrt(1.0f / (float)framesize); | ||
| 1969 | float minrzero = rms * rms; | ||
| 1970 | float rzero = processbuf[0]; | ||
| 1971 | if(rzero < minrzero) rzero = minrzero; | ||
| 1972 | double normintegral = (double)rzero * 2.; | ||
| 1973 | |||
| 1974 | // normalize biased autocorrelation function | ||
| 1975 | // inputbuf is circular buffer: timeindex may be non-zero when overlap > 1 | ||
| 1976 | processbuf[0] = 1; | ||
| 1977 | for(n=1, m=s->timeindex+1; n<seek; n++, m++) | ||
| 1978 | { | ||
| 1979 | signal1 = inputbuf[(n + timeindexminusone)&mask]; | ||
| 1980 | signal2 = inputbuf[(framesizeplustimeindex - n)&mask]; | ||
| 1981 | normintegral -= (double)(signal1 * signal1 + signal2 * signal2); | ||
| 1982 | processbuf[n] /= (float)normintegral * 0.5f; | ||
| 1983 | } | ||
| 1984 | |||
| 1985 | // flush instable function tail | ||
| 1986 | for(n = seek; n<framesize; n++) processbuf[n] = 0.; | ||
| 1987 | return; | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | |||
| 1991 | static void snac_periodandfidelity(tSNAC* const s) | ||
| 1992 | { | ||
| 1993 | float periodlength; | ||
| 1994 | |||
| 1995 | if(s->periodindex) | ||
| 1996 | { | ||
| 1997 | periodlength = (float)s->periodindex + | ||
| 1998 | interpolate3phase(s->processbuf, s->periodindex); | ||
| 1999 | if(periodlength < 8) periodlength = snac_spectralpeak(s, periodlength); | ||
| 2000 | s->periodlength = periodlength; | ||
| 2001 | s->fidelity = interpolate3max(s->processbuf, s->periodindex); | ||
| 2002 | } | ||
| 2003 | return; | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | // select the peak which most probably represents period length | ||
| 2007 | static void snac_pickpeak(tSNAC* const s) | ||
| 2008 | { | ||
| 2009 | int n, peakindex=0; | ||
| 2010 | int seek = s->framesize * SEEK; | ||
| 2011 | float *processbuf= s->processbuf; | ||
| 2012 | float maxvalue = 0.; | ||
| 2013 | float biasedpeak; | ||
| 2014 | float *biasbuf = s->biasbuf; | ||
| 2015 | |||
| 2016 | // skip main lobe | ||
| 2017 | for(n=1; n<seek; n++) | ||
| 2018 | { | ||
| 2019 | if(processbuf[n] < 0.) break; | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | // find interpolated / biased maximum in SNAC function | ||
| 2023 | // interpolation finds the 'real maximum' | ||
| 2024 | // biasing favours the first candidate | ||
| 2025 | for(; n<seek-1; n++) | ||
| 2026 | { | ||
| 2027 | if(processbuf[n] >= processbuf[n-1]) | ||
| 2028 | { | ||
| 2029 | if(processbuf[n] > processbuf[n+1]) // we have a local peak | ||
| 2030 | { | ||
| 2031 | biasedpeak = interpolate3max(processbuf, n) * biasbuf[n]; | ||
| 2032 | |||
| 2033 | if(biasedpeak > maxvalue) | ||
| 2034 | { | ||
| 2035 | maxvalue = biasedpeak; | ||
| 2036 | peakindex = n; | ||
| 2037 | } | ||
| 2038 | } | ||
| 2039 | } | ||
| 2040 | } | ||
| 2041 | s->periodindex = peakindex; | ||
| 2042 | return; | ||
| 2043 | } | ||
| 2044 | |||
| 2045 | |||
| 2046 | // verify period length via frequency domain (up till SR/4) | ||
| 2047 | // frequency domain is more precise than lag domain for period lengths < 8 | ||
| 2048 | // argument 'periodlength' is initial estimation from autocorrelation | ||
| 2049 | static float snac_spectralpeak(tSNAC* const s, float periodlength) | ||
| 2050 | { | ||
| 2051 | if(periodlength < 4.) return periodlength; | ||
| 2052 | |||
| 2053 | float max = 0.; | ||
| 2054 | int n, startbin, stopbin, peakbin = 0; | ||
| 2055 | int spectrumsize = s->framesize>>1; | ||
| 2056 | float *spectrumbuf = s->spectrumbuf; | ||
| 2057 | float peaklocation = (float)(s->framesize * 2.) / periodlength; | ||
| 2058 | |||
| 2059 | startbin = (int)(peaklocation * 0.8 + 0.5); | ||
| 2060 | if(startbin < 1) startbin = 1; | ||
| 2061 | stopbin = (int)(peaklocation * 1.25 + 0.5); | ||
| 2062 | if(stopbin >= spectrumsize - 1) stopbin = spectrumsize - 1; | ||
| 2063 | |||
| 2064 | for(n=startbin; n<stopbin; n++) | ||
| 2065 | { | ||
| 2066 | if(spectrumbuf[n] >= spectrumbuf[n-1]) | ||
| 2067 | { | ||
| 2068 | if(spectrumbuf[n] > spectrumbuf[n+1]) | ||
| 2069 | { | ||
| 2070 | if(spectrumbuf[n] > max) | ||
| 2071 | { | ||
| 2072 | max = spectrumbuf[n]; | ||
| 2073 | peakbin = n; | ||
| 2074 | } | ||
| 2075 | } | ||
| 2076 | } | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | // calculate amplitudes in peak region | ||
| 2080 | for(n=(peakbin-1); n<(peakbin+2); n++) | ||
| 2081 | { | ||
| 2082 | spectrumbuf[n] = sqrt(spectrumbuf[n]); | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | peaklocation = (float)peakbin + interpolate3phase(spectrumbuf, peakbin); | ||
| 2086 | periodlength = (float)(s->framesize * 2.0f) / peaklocation; | ||
| 2087 | |||
| 2088 | return periodlength; | ||
| 2089 | } | ||
| 2090 | |||
| 2091 | |||
| 2092 | // modified logarithmic bias function | ||
| 2093 | static void snac_biasbuf(tSNAC* const s) | ||
| 2094 | { | ||
| 2095 | int n; | ||
| 2096 | int maxperiod = (int)(s->framesize * (float)SEEK); | ||
| 2097 | float bias = s->biasfactor / log((float)(maxperiod - 4)); | ||
| 2098 | float *biasbuf = s->biasbuf; | ||
| 2099 | |||
| 2100 | for(n=0; n<5; n++) // periods < 5 samples can't be tracked | ||
| 2101 | { | ||
| 2102 | biasbuf[n] = 0.; | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | for(n=5; n<maxperiod; n++) | ||
| 2106 | { | ||
| 2107 | biasbuf[n] = 1.0f - (float)log(n - 4) * bias; | ||
| 2108 | } | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | /********Private function prototypes**********/ | ||
| 2112 | static void atkdtk_init(tAtkDtk* const a, int blocksize, int atk, int rel); | ||
| 2113 | static void atkdtk_envelope(tAtkDtk* const a, float *in); | ||
| 2114 | |||
| 2115 | /********Constructor/Destructor***************/ | ||
| 2116 | |||
| 2117 | void tAtkDtk_init(tAtkDtk* const a, int blocksize) | ||
| 2118 | { | ||
| 2119 | atkdtk_init(a, blocksize, DEFATTACK, DEFRELEASE); | ||
| 2120 | } | ||
| 2121 | |||
| 2122 | void tAtkDtk_init_expanded(tAtkDtk* const a, int blocksize, int atk, int rel) | ||
| 2123 | { | ||
| 2124 | atkdtk_init(a, blocksize, atk, rel); | ||
| 2125 | } | ||
| 2126 | |||
| 2127 | void tAtkDtk_free(tAtkDtk *a) | ||
| 2128 | { | ||
| 2129 | |||
| 2130 | } | ||
| 2131 | |||
| 2132 | /*******Public Functions***********/ | ||
| 2133 | |||
| 2134 | |||
| 2135 | void tAtkDtk_setBlocksize(tAtkDtk* const a, int size) | ||
| 2136 | { | ||
| 2137 | |||
| 2138 | if(!((size==64)|(size==128)|(size==256)|(size==512)|(size==1024)|(size==2048))) | ||
| 2139 | size = DEFBLOCKSIZE; | ||
| 2140 | a->blocksize = size; | ||
| 2141 | |||
| 2142 | return; | ||
| 2143 | |||
| 2144 | } | ||
| 2145 | |||
| 2146 | void tAtkDtk_setSamplerate(tAtkDtk* const a, int inRate) | ||
| 2147 | { | ||
| 2148 | a->samplerate = inRate; | ||
| 2149 | |||
| 2150 | //Reset atk and rel to recalculate coeff | ||
| 2151 | tAtkDtk_setAtk(a, a->atk); | ||
| 2152 | tAtkDtk_setRel(a, a->rel); | ||
| 2153 | |||
| 2154 | return; | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | void tAtkDtk_setThreshold(tAtkDtk* const a, float thres) | ||
| 2158 | { | ||
| 2159 | a->threshold = thres; | ||
| 2160 | return; | ||
| 2161 | } | ||
| 2162 | |||
| 2163 | void tAtkDtk_setAtk(tAtkDtk* const a, int inAtk) | ||
| 2164 | { | ||
| 2165 | a->atk = inAtk; | ||
| 2166 | a->atk_coeff = pow(0.01, 1.0/(a->atk * a->samplerate * 0.001)); | ||
| 2167 | |||
| 2168 | return; | ||
| 2169 | } | ||
| 2170 | |||
| 2171 | void tAtkDtk_setRel(tAtkDtk* const a, int inRel) | ||
| 2172 | { | ||
| 2173 | a->rel = inRel; | ||
| 2174 | a->rel_coeff = pow(0.01, 1.0/(a->rel * a->samplerate * 0.001)); | ||
| 2175 | |||
| 2176 | return; | ||
| 2177 | } | ||
| 2178 | |||
| 2179 | |||
| 2180 | int tAtkDtk_detect(tAtkDtk* const a, float *in) | ||
| 2181 | { | ||
| 2182 | int result; | ||
| 2183 | |||
| 2184 | atkdtk_envelope(a, in); | ||
| 2185 | |||
| 2186 | if(a->env >= a->prevAmp*2) //2 times greater = 6dB increase | ||
| 2187 | result = 1; | ||
| 2188 | else | ||
| 2189 | result = 0; | ||
| 2190 | |||
| 2191 | a->prevAmp = a->env; | ||
| 2192 | |||
| 2193 | return result; | ||
| 2194 | |||
| 2195 | } | ||
| 2196 | |||
| 2197 | /*******Private Functions**********/ | ||
| 2198 | |||
| 2199 | static void atkdtk_init(tAtkDtk* const a, int blocksize, int atk, int rel) | ||
| 2200 | { | ||
| 2201 | a->env = 0; | ||
| 2202 | a->blocksize = blocksize; | ||
| 2203 | a->threshold = DEFTHRESHOLD; | ||
| 2204 | a->samplerate = leaf.sampleRate; | ||
| 2205 | a->prevAmp = 0; | ||
| 2206 | |||
| 2207 | a->env = 0; | ||
| 2208 | |||
| 2209 | tAtkDtk_setAtk(a, atk); | ||
| 2210 | tAtkDtk_setRel(a, rel); | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | static void atkdtk_envelope(tAtkDtk* const a, float *in) | ||
| 2214 | { | ||
| 2215 | int i = 0; | ||
| 2216 | float tmp; | ||
| 2217 | for(i = 0; i < a->blocksize; ++i){ | ||
| 2218 | tmp = fastabs(in[i]); | ||
| 2219 | |||
| 2220 | if(tmp > a->env) | ||
| 2221 | a->env = a->atk_coeff * (a->env - tmp) + tmp; | ||
| 2222 | else | ||
| 2223 | a->env = a->rel_coeff * (a->env - tmp) + tmp; | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | } | ||
| 2227 | |||
| @@ -1,400 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-vocoder.c | ||
| 4 | Created: 20 Jan 2017 12:01:54pm | ||
| 5 | Author: Michael R Mulshine | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-vocoder.h" | ||
| 12 | #include "..\leaf.h" | ||
| 13 | |||
| 14 | #else | ||
| 15 | |||
| 16 | #include "../Inc/leaf-vocoder.h" | ||
| 17 | #include "../leaf.h" | ||
| 18 | |||
| 19 | #endif | ||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 24 | * | ||
| 25 | * | ||
| 26 | * | ||
| 27 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 28 | |||
| 29 | void tTalkbox_init(tTalkbox* const v, int bufsize) | ||
| 30 | { | ||
| 31 | v->param[0] = 0.5f; //wet | ||
| 32 | v->param[1] = 0.0f; //dry | ||
| 33 | v->param[2] = 0; // Swap | ||
| 34 | v->param[3] = 1.0f; //quality | ||
| 35 | |||
| 36 | v->bufsize = bufsize; | ||
| 37 | |||
| 38 | v->car0 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 39 | v->car1 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 40 | v->window = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 41 | v->buf0 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 42 | v->buf1 = (float*) leaf_alloc(sizeof(float) * v->bufsize); | ||
| 43 | |||
| 44 | tTalkbox_update(v); | ||
| 45 | } | ||
| 46 | |||
| 47 | void tTalkbox_free(tTalkbox* const v) | ||
| 48 | { | ||
| 49 | leaf_free(v->car0); | ||
| 50 | leaf_free(v->car1); | ||
| 51 | leaf_free(v->window); | ||
| 52 | leaf_free(v->buf0); | ||
| 53 | leaf_free(v->buf1); | ||
| 54 | } | ||
| 55 | |||
| 56 | void tTalkbox_update(tTalkbox* const v) ///update internal parameters... | ||
| 57 | { | ||
| 58 | float fs = leaf.sampleRate; | ||
| 59 | if(fs < 8000.0f) fs = 8000.0f; | ||
| 60 | if(fs > 96000.0f) fs = 96000.0f; | ||
| 61 | |||
| 62 | int32_t n = (int32_t)(0.01633f * fs); | ||
| 63 | if(n > v->bufsize) n = v->bufsize; | ||
| 64 | |||
| 65 | //O = (VstInt32)(0.0005f * fs); | ||
| 66 | v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs); | ||
| 67 | |||
| 68 | if(n != v->N) //recalc hanning window | ||
| 69 | { | ||
| 70 | v->N = n; | ||
| 71 | float dp = TWO_PI / v->N; | ||
| 72 | float p = 0.0f; | ||
| 73 | for(n=0; n<v->N; n++) | ||
| 74 | { | ||
| 75 | v->window[n] = 0.5f - 0.5f * cosf(p); | ||
| 76 | p += dp; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | v->wet = 0.5f * v->param[0] * v->param[0]; | ||
| 80 | v->dry = 2.0f * v->param[1] * v->param[1]; | ||
| 81 | } | ||
| 82 | |||
| 83 | void tTalkbox_suspend(tTalkbox* const v) ///clear any buffers... | ||
| 84 | { | ||
| 85 | v->pos = v->K = 0; | ||
| 86 | v->emphasis = 0.0f; | ||
| 87 | v->FX = 0; | ||
| 88 | |||
| 89 | v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f; | ||
| 90 | v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f; | ||
| 91 | |||
| 92 | for (int32_t i = 0; i < v->bufsize; i++) | ||
| 93 | { | ||
| 94 | v->buf0[i] = 0; | ||
| 95 | v->buf1[i] = 0; | ||
| 96 | v->car0[i] = 0; | ||
| 97 | v->car1[i] = 0; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | |||
| 102 | #define ORD_MAX 100 // Was 50. Increasing this gets rid of glitchiness, lowering it breaks it; not sure how it affects performance | ||
| 103 | void tTalkbox_lpc(float *buf, float *car, int32_t n, int32_t o) | ||
| 104 | { | ||
| 105 | float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x; | ||
| 106 | int32_t i, j, nn=n; | ||
| 107 | |||
| 108 | for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed | ||
| 109 | { | ||
| 110 | z[j] = r[j] = 0.0f; | ||
| 111 | for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation | ||
| 112 | } | ||
| 113 | r[0] *= 1.001f; //stability fix | ||
| 114 | |||
| 115 | float min = 0.00001f; | ||
| 116 | if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; } | ||
| 117 | |||
| 118 | tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs | ||
| 119 | |||
| 120 | for(i=0; i<=o; i++) | ||
| 121 | { | ||
| 122 | if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f; | ||
| 123 | } | ||
| 124 | |||
| 125 | for(i=0; i<n; i++) | ||
| 126 | { | ||
| 127 | x = G * car[i]; | ||
| 128 | for(j=o; j>0; j--) //lattice filter | ||
| 129 | { | ||
| 130 | x -= k[j] * z[j-1]; | ||
| 131 | z[j] = z[j-1] + k[j] * x; | ||
| 132 | } | ||
| 133 | buf[i] = z[0] = x; //output buf[] will be windowed elsewhere | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | |||
| 138 | void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g) | ||
| 139 | { | ||
| 140 | int i, j; | ||
| 141 | float a[ORD_MAX], at[ORD_MAX], e=r[0]; | ||
| 142 | |||
| 143 | for(i=0; i<=p; i++) a[i] = at[i] = 0.0f; //probably don't need to clear at[] or k[] | ||
| 144 | |||
| 145 | for(i=1; i<=p; i++) | ||
| 146 | { | ||
| 147 | k[i] = -r[i]; | ||
| 148 | |||
| 149 | for(j=1; j<i; j++) | ||
| 150 | { | ||
| 151 | at[j] = a[j]; | ||
| 152 | k[i] -= a[j] * r[i-j]; | ||
| 153 | } | ||
| 154 | if(fabs(e) < 1.0e-20f) { e = 0.0f; break; } | ||
| 155 | k[i] /= e; // This might be costing us | ||
| 156 | |||
| 157 | a[i] = k[i]; | ||
| 158 | for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j]; | ||
| 159 | |||
| 160 | e *= 1.0f - k[i] * k[i]; | ||
| 161 | } | ||
| 162 | |||
| 163 | if(e < 1.0e-20f) e = 0.0f; | ||
| 164 | *g = sqrtf(e); | ||
| 165 | } | ||
| 166 | |||
| 167 | float tTalkbox_tick(tTalkbox* const v, float synth, float voice) | ||
| 168 | { | ||
| 169 | |||
| 170 | int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N; | ||
| 171 | float e=v->emphasis, w, o, x, dr, fx=v->FX; | ||
| 172 | float p, q, h0=0.3f, h1=0.77f; | ||
| 173 | |||
| 174 | o = voice; | ||
| 175 | x = synth; | ||
| 176 | |||
| 177 | dr = o; | ||
| 178 | |||
| 179 | p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p; | ||
| 180 | q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q; | ||
| 181 | v->d4 = x; | ||
| 182 | x = p + q; | ||
| 183 | |||
| 184 | if(v->K++) | ||
| 185 | { | ||
| 186 | v->K = 0; | ||
| 187 | |||
| 188 | v->car0[p0] = v->car1[p1] = x; //carrier input | ||
| 189 | |||
| 190 | x = o - e; e = o; //6dB/oct pre-emphasis | ||
| 191 | |||
| 192 | w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows | ||
| 193 | if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->N, v->O); p0 = 0; } | ||
| 194 | |||
| 195 | w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w; | ||
| 196 | if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->N, v->O); p1 = 0; } | ||
| 197 | } | ||
| 198 | |||
| 199 | p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p; | ||
| 200 | q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q; | ||
| 201 | v->u4 = fx; | ||
| 202 | x = p + q; | ||
| 203 | |||
| 204 | o = x; | ||
| 205 | |||
| 206 | v->emphasis = e; | ||
| 207 | v->pos = p0; | ||
| 208 | v->FX = fx; | ||
| 209 | |||
| 210 | float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]); | ||
| 211 | if(fabs(v->d0) < den) v->d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?) | ||
| 212 | if(fabs(v->d1) < den) v->d1 = 0.0f; | ||
| 213 | if(fabs(v->d2) < den) v->d2 = 0.0f; | ||
| 214 | if(fabs(v->d3) < den) v->d3 = 0.0f; | ||
| 215 | if(fabs(v->u0) < den) v->u0 = 0.0f; | ||
| 216 | if(fabs(v->u1) < den) v->u1 = 0.0f; | ||
| 217 | if(fabs(v->u2) < den) v->u2 = 0.0f; | ||
| 218 | if(fabs(v->u3) < den) v->u3 = 0.0f; | ||
| 219 | return o; | ||
| 220 | } | ||
| 221 | |||
| 222 | void tTalkbox_setQuality(tTalkbox* const v, float quality) | ||
| 223 | { | ||
| 224 | v->param[3] = quality; | ||
| 225 | v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate); | ||
| 226 | } | ||
| 227 | |||
| 228 | void tVocoder_init (tVocoder* const v) | ||
| 229 | { | ||
| 230 | v->param[0] = 0.33f; //input select | ||
| 231 | v->param[1] = 0.50f; //output dB | ||
| 232 | v->param[2] = 0.40f; //hi thru | ||
| 233 | v->param[3] = 0.40f; //hi band | ||
| 234 | v->param[4] = 0.16f; //envelope | ||
| 235 | v->param[5] = 0.55f; //filter q | ||
| 236 | v->param[6] = 0.6667f;//freq range | ||
| 237 | v->param[7] = 0.33f; //num bands | ||
| 238 | |||
| 239 | tVocoder_update(v); | ||
| 240 | } | ||
| 241 | |||
| 242 | void tVocoder_free (tVocoder* const v) | ||
| 243 | { | ||
| 244 | |||
| 245 | } | ||
| 246 | |||
| 247 | void tVocoder_update (tVocoder* const v) | ||
| 248 | { | ||
| 249 | float tpofs = 6.2831853f * leaf.invSampleRate; | ||
| 250 | |||
| 251 | float rr, th, re; | ||
| 252 | |||
| 253 | float sh; | ||
| 254 | |||
| 255 | int32_t i; | ||
| 256 | |||
| 257 | v->gain = (float)pow(10.0f, 2.0f * v->param[1] - 3.0f * v->param[5] - 2.0f); | ||
| 258 | |||
| 259 | v->thru = (float)pow(10.0f, 0.5f + 2.0f * v->param[1]); | ||
| 260 | v->high = v->param[3] * v->param[3] * v->param[3] * v->thru; | ||
| 261 | v->thru *= v->param[2] * v->param[2] * v->param[2]; | ||
| 262 | |||
| 263 | if(v->param[7]<0.5f) | ||
| 264 | { | ||
| 265 | v->nbnd=8; | ||
| 266 | re=0.003f; | ||
| 267 | v->f[1][2] = 3000.0f; | ||
| 268 | v->f[2][2] = 2200.0f; | ||
| 269 | v->f[3][2] = 1500.0f; | ||
| 270 | v->f[4][2] = 1080.0f; | ||
| 271 | v->f[5][2] = 700.0f; | ||
| 272 | v->f[6][2] = 390.0f; | ||
| 273 | v->f[7][2] = 190.0f; | ||
| 274 | } | ||
| 275 | else | ||
| 276 | { | ||
| 277 | v->nbnd=16; | ||
| 278 | re=0.0015f; | ||
| 279 | v->f[ 1][2] = 5000.0f; //+1000 | ||
| 280 | v->f[ 2][2] = 4000.0f; //+750 | ||
| 281 | v->f[ 3][2] = 3250.0f; //+500 | ||
| 282 | v->f[ 4][2] = 2750.0f; //+450 | ||
| 283 | v->f[ 5][2] = 2300.0f; //+300 | ||
| 284 | v->f[ 6][2] = 2000.0f; //+250 | ||
| 285 | v->f[ 7][2] = 1750.0f; //+250 | ||
| 286 | v->f[ 8][2] = 1500.0f; //+250 | ||
| 287 | v->f[ 9][2] = 1250.0f; //+250 | ||
| 288 | v->f[10][2] = 1000.0f; //+250 | ||
| 289 | v->f[11][2] = 750.0f; //+210 | ||
| 290 | v->f[12][2] = 540.0f; //+190 | ||
| 291 | v->f[13][2] = 350.0f; //+155 | ||
| 292 | v->f[14][2] = 195.0f; //+100 | ||
| 293 | v->f[15][2] = 95.0f; | ||
| 294 | } | ||
| 295 | |||
| 296 | if(v->param[4]<0.05f) //freeze | ||
| 297 | { | ||
| 298 | for(i=0;i<v->nbnd;i++) v->f[i][12]=0.0f; | ||
| 299 | } | ||
| 300 | else | ||
| 301 | { | ||
| 302 | v->f[0][12] = (float)pow(10.0, -1.7 - 2.7f * v->param[4]); //envelope speed | ||
| 303 | |||
| 304 | rr = 0.022f / (float)v->nbnd; //minimum proportional to frequency to stop distortion | ||
| 305 | for(i=1;i<v->nbnd;i++) | ||
| 306 | { | ||
| 307 | v->f[i][12] = (float)(0.025 - rr * (double)i); | ||
| 308 | if(v->f[0][12] < v->f[i][12]) v->f[i][12] = v->f[0][12]; | ||
| 309 | } | ||
| 310 | v->f[0][12] = 0.5f * v->f[0][12]; //only top band is at full rate | ||
| 311 | } | ||
| 312 | |||
| 313 | rr = 1.0 - pow(10.0f, -1.0f - 1.2f * v->param[5]); | ||
| 314 | sh = (float)pow(2.0f, 3.0f * v->param[6] - 1.0f); //filter bank range shift | ||
| 315 | |||
| 316 | for(i=1;i<v->nbnd;i++) | ||
| 317 | { | ||
| 318 | v->f[i][2] *= sh; | ||
| 319 | th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr)); | ||
| 320 | v->f[i][0] = (float)(2.0 * rr * cos(th)); //a0 | ||
| 321 | v->f[i][1] = (float)(-rr * rr); //a1 | ||
| 322 | //was .98 | ||
| 323 | v->f[i][2] *= 0.96f; //shift 2nd stage slightly to stop high resonance peaks | ||
| 324 | th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr)); | ||
| 325 | v->f[i][2] = (float)(2.0 * rr * cos(th)); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | float tVocoder_tick (tVocoder* const v, float synth, float voice) | ||
| 330 | { | ||
| 331 | float a, b, o=0.0f, aa, bb, oo = v->kout, g = v->gain, ht = v->thru, hh = v->high, tmp; | ||
| 332 | uint32_t i, k = v->kval, nb = v->nbnd; | ||
| 333 | |||
| 334 | a = voice; //speech | ||
| 335 | b = synth; //synth | ||
| 336 | |||
| 337 | tmp = a - v->f[0][7]; //integrate modulator for HF band and filter bank pre-emphasis | ||
| 338 | v->f[0][7] = a; | ||
| 339 | a = tmp; | ||
| 340 | |||
| 341 | if(tmp<0.0f) tmp = -tmp; | ||
| 342 | v->f[0][11] -= v->f[0][12] * (v->f[0][11] - tmp); //high band envelope | ||
| 343 | o = v->f[0][11] * (ht * a + hh * (b - v->f[0][3])); //high band + high thru | ||
| 344 | |||
| 345 | v->f[0][3] = b; //integrate carrier for HF band | ||
| 346 | |||
| 347 | if(++k & 0x1) //this block runs at half sample rate | ||
| 348 | { | ||
| 349 | oo = 0.0f; | ||
| 350 | aa = a + v->f[0][9] - v->f[0][8] - v->f[0][8]; //apply zeros here instead of in each reson | ||
| 351 | v->f[0][9] = v->f[0][8]; v->f[0][8] = a; | ||
| 352 | bb = b + v->f[0][5] - v->f[0][4] - v->f[0][4]; | ||
| 353 | v->f[0][5] = v->f[0][4]; v->f[0][4] = b; | ||
| 354 | |||
| 355 | for(i=1; i<nb; i++) //filter bank: 4th-order band pass | ||
| 356 | { | ||
| 357 | tmp = v->f[i][0] * v->f[i][3] + v->f[i][1] * v->f[i][4] + bb; | ||
| 358 | v->f[i][4] = v->f[i][3]; | ||
| 359 | v->f[i][3] = tmp; | ||
| 360 | tmp += v->f[i][2] * v->f[i][5] + v->f[i][1] * v->f[i][6]; | ||
| 361 | v->f[i][6] = v->f[i][5]; | ||
| 362 | v->f[i][5] = tmp; | ||
| 363 | |||
| 364 | tmp = v->f[i][0] * v->f[i][7] + v->f[i][1] * v->f[i][8] + aa; | ||
| 365 | v->f[i][8] = v->f[i][7]; | ||
| 366 | v->f[i][7] = tmp; | ||
| 367 | tmp += v->f[i][2] * v->f[i][9] + v->f[i][1] * v->f[i][10]; | ||
| 368 | v->f[i][10] = v->f[i][9]; | ||
| 369 | v->f[i][9] = tmp; | ||
| 370 | |||
| 371 | if(tmp<0.0f) tmp = -tmp; | ||
| 372 | v->f[i][11] -= v->f[i][12] * (v->f[i][11] - tmp); | ||
| 373 | oo += v->f[i][5] * v->f[i][11]; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | o += oo * g; //effect of interpolating back up to Fs would be minimal (aliasing >16kHz) | ||
| 377 | |||
| 378 | v->kout = oo; | ||
| 379 | v->kval = k & 0x1; | ||
| 380 | if(fabs(v->f[0][11])<1.0e-10) v->f[0][11] = 0.0f; //catch HF envelope denormal | ||
| 381 | |||
| 382 | for(i=1;i<nb;i++) | ||
| 383 | if(fabs(v->f[i][3])<1.0e-10 || fabs(v->f[i][7])<1.0e-10) | ||
| 384 | for(k=3; k<12; k++) v->f[i][k] = 0.0f; //catch reson & envelope denormals | ||
| 385 | |||
| 386 | if(fabs(o)>10.0f) tVocoder_suspend(v); //catch instability | ||
| 387 | |||
| 388 | return o; | ||
| 389 | |||
| 390 | } | ||
| 391 | |||
| 392 | void tVocoder_suspend (tVocoder* const v) | ||
| 393 | { | ||
| 394 | int32_t i, j; | ||
| 395 | |||
| 396 | for(i=0; i<v->nbnd; i++) for(j=3; j<12; j++) v->f[i][j] = 0.0f; //zero band filters and envelopes | ||
| 397 | v->kout = 0.0f; | ||
| 398 | v->kval = 0; | ||
| 399 | } | ||
| 400 | |||
| @@ -1,114 +0,0 @@ | |||
| 1 | /*============================================================================== | ||
| 2 | |||
| 3 | leaf-wavefolder.c | ||
| 4 | Created: 30 Nov 2018 11:56:49am | ||
| 5 | Author: airship | ||
| 6 | |||
| 7 | ==============================================================================*/ | ||
| 8 | |||
| 9 | #if _WIN32 || _WIN64 | ||
| 10 | |||
| 11 | #include "..\Inc\leaf-wavefolder.h" | ||
| 12 | |||
| 13 | #else | ||
| 14 | |||
| 15 | #include "../Inc/leaf-wavefolder.h" | ||
| 16 | |||
| 17 | #endif | ||
| 18 | |||
| 19 | void tLockhartWavefolder_init(tLockhartWavefolder* const w) | ||
| 20 | { | ||
| 21 | w->Ln1 = 0.0; | ||
| 22 | w->Fn1 = 0.0; | ||
| 23 | w->xn1 = 0.0f; | ||
| 24 | } | ||
| 25 | |||
| 26 | void tLockhardWavefolder_free(tLockhartWavefolder* const w) | ||
| 27 | { | ||
| 28 | |||
| 29 | } | ||
| 30 | |||
| 31 | double tLockhartWavefolderLambert(double x, double ln) | ||
| 32 | { | ||
| 33 | double thresh, w, expw, p, r, s, err; | ||
| 34 | // Error threshold | ||
| 35 | thresh = 10e-6; | ||
| 36 | // Initial guess (use previous value) | ||
| 37 | w = ln; | ||
| 38 | |||
| 39 | // Haley's method (Sec. 4.2 of the paper) | ||
| 40 | for(int i=0; i<100; i+=1) { | ||
| 41 | |||
| 42 | expw = exp(w); | ||
| 43 | |||
| 44 | p = w*expw - x; | ||
| 45 | r = (w+1.0)*expw; | ||
| 46 | s = (w+2.0)/(2.0*(w+1.0)); err = (p/(r-(p*s))); | ||
| 47 | |||
| 48 | if (fabs(err)<thresh) { | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | if (isnan(err)) | ||
| 52 | { | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | |||
| 56 | w = w - err; | ||
| 57 | } | ||
| 58 | return w; | ||
| 59 | } | ||
| 60 | |||
| 61 | float tLockhartWavefolder_tick(tLockhartWavefolder* const w, float samp) | ||
| 62 | { | ||
| 63 | |||
| 64 | float out = 0.0f; | ||
| 65 | // Constants | ||
| 66 | double RL = 7.5e3; | ||
| 67 | double R = 15e3; | ||
| 68 | double VT = 26e-3; | ||
| 69 | double Is = 10e-16; | ||
| 70 | |||
| 71 | double a = 2.0*RL/R; | ||
| 72 | double b = (R+2.0*RL)/(VT*R); | ||
| 73 | double d = (RL*Is)/VT; | ||
| 74 | |||
| 75 | // Antialiasing error threshold | ||
| 76 | double thresh = 10e-10; | ||
| 77 | |||
| 78 | // Compute Antiderivative | ||
| 79 | int l = (samp > 0) - (samp < 0); | ||
| 80 | double u = d*exp(l*b*samp); | ||
| 81 | double Ln = tLockhartWavefolderLambert(u,w->Ln1); | ||
| 82 | double Fn = (0.5*VT/b)*(Ln*(Ln + 2.0)) - 0.5*a*samp*samp; | ||
| 83 | |||
| 84 | // Check for ill-conditioning | ||
| 85 | if (fabs(samp-w->xn1)<thresh) { | ||
| 86 | |||
| 87 | // Compute Averaged Wavefolder Output | ||
| 88 | double xn = 0.5*(samp+w->xn1); | ||
| 89 | u = d*exp(l*b*xn); | ||
| 90 | Ln = tLockhartWavefolderLambert(u,w->Ln1); | ||
| 91 | out = (float) (l*VT*Ln - a*xn); | ||
| 92 | if (isnan(out)) | ||
| 93 | { | ||
| 94 | ; | ||
| 95 | } | ||
| 96 | |||
| 97 | } | ||
| 98 | else { | ||
| 99 | |||
| 100 | // Apply AA Form | ||
| 101 | out = (float) ((Fn-w->Fn1)/(samp-w->xn1)); | ||
| 102 | if (isnan(out)) | ||
| 103 | { | ||
| 104 | ; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | // Update States | ||
| 109 | w->Ln1 = Ln; | ||
| 110 | w->Fn1 = Fn; | ||
| 111 | w->xn1 = samp; | ||
| 112 | |||
| 113 | return out; | ||
| 114 | } | ||
| @@ -22,45 +22,42 @@ · 21 unmodified lines | |||
| 22 | #include ".\Inc\leaf-global.h" | 22 | #include ".\Inc\leaf-global.h" |
| 23 | #include ".\Inc\leaf-math.h" | 23 | #include ".\Inc\leaf-math.h" |
| 24 | #include ".\Inc\leaf-mempool.h" | 24 | #include ".\Inc\leaf-mempool.h" |
| 25 | #include ".\Inc\leaf-utilities.h" | 25 | #include ".\Inc\leaf-tables.h" |
| 26 | #include ".\Inc\leaf-tables.h" | ||
| 27 | #include ".\Inc\leaf-oscillators.h" | ||
| 28 | #include ".\Inc\leaf-filters.h" | ||
| 26 | #include ".\Inc\leaf-delay.h" | 29 | #include ".\Inc\leaf-delay.h" |
| 27 | #include ".\Inc\leaf-filter.h" | ||
| 28 | #include ".\Inc\leaf-oscillator.h" | ||
| 29 | #include ".\Inc\leaf-oversampler.h" | ||
| 30 | #include ".\Inc\leaf-reverb.h" | 30 | #include ".\Inc\leaf-reverb.h" |
| 31 | #include ".\Inc\leaf-vocoder.h" | 31 | #include ".\Inc\leaf-effects.h" |
| 32 | #include ".\Inc\leaf-808.h" | 32 | #include ".\Inc\leaf-envelopes.h" |
| 33 | #include ".\Inc\leaf-string.h" | 33 | #include ".\Inc\leaf-dynamics.h" |
| 34 | #include ".\Inc\leaf-pitch.h" | 34 | #include ".\Inc\leaf-analysis.h" |
| 35 | #include ".\Inc\leaf-formant.h" | 35 | #include ".\Inc\leaf-instruments.h" |
| 36 | #include ".\Inc\leaf-midi.h" | 36 | #include ".\Inc\leaf-midi.h" |
| 37 | #include ".\Inc\leaf-sample.h" | 37 | #include ".\Inc\leaf-sampling.h" |
| 38 | #include ".\Inc\leaf-crusher.h" | 38 | #include ".\Inc\leaf-physical.h" |
| 39 | #include ".\Inc\leaf-wavefolder.h" | 39 | #include ".\Inc\leaf-electrical.h" |
| 40 | #include ".\Inc\leaf-tables.h" | ||
| 41 | 40 | ||
| 42 | #else | 41 | #else |
| 43 | 42 | ||
| 44 | #include "./Inc/leaf-global.h" | 43 | #include "./Inc/leaf-global.h" |
| 45 | #include "./Inc/leaf-math.h" | 44 | #include "./Inc/leaf-math.h" |
| 46 | #include "./Inc/leaf-mempool.h" | 45 | #include "./Inc/leaf-mempool.h" |
| 47 | #include "./Inc/leaf-utilities.h" | 46 | #include "./Inc/leaf-tables.h" |
| 47 | #include "./Inc/leaf-tables.h" | ||
| 48 | #include "./Inc/leaf-oscillators.h" | ||
| 49 | #include "./Inc/leaf-filters.h" | ||
| 48 | #include "./Inc/leaf-delay.h" | 50 | #include "./Inc/leaf-delay.h" |
| 49 | #include "./Inc/leaf-filter.h" | ||
| 50 | #include "./Inc/leaf-oscillator.h" | ||
| 51 | #include "./Inc/leaf-oversampler.h" | ||
| 52 | #include "./Inc/leaf-reverb.h" | 51 | #include "./Inc/leaf-reverb.h" |
| 53 | #include "./Inc/leaf-vocoder.h" | 52 | #include "./Inc/leaf-effects.h" |
| 54 | #include "./Inc/leaf-808.h" | 53 | #include "./Inc/leaf-envelopes.h" |
| 55 | #include "./Inc/leaf-string.h" | 54 | #include "./Inc/leaf-dynamics.h" |
| 56 | #include "./Inc/leaf-pitch.h" | 55 | #include "./Inc/leaf-analysis.h" |
| 57 | #include "./Inc/leaf-formant.h" | 56 | #include "./Inc/leaf-instruments.h" |
| 58 | #include "./Inc/leaf-midi.h" | 57 | #include "./Inc/leaf-midi.h" |
| 59 | #include "./Inc/leaf-sample.h" | 58 | #include "./Inc/leaf-sampling.h" |
| 60 | #include "./Inc/leaf-crusher.h" | 59 | #include "./Inc/leaf-physical.h" |
| 61 | #include "./Inc/leaf-wavefolder.h" | 60 | #include "./Inc/leaf-electrical.h" |
| 62 | #include "./Inc/leaf-tables.h" | ||
| 63 | #include "./Inc/leaf-WDF.h" | ||
| 64 | 61 | ||
| 65 | #endif | 62 | #endif |
| 66 | 63 | ||
| @@ -26,53 +26,51 @@ · 25 unmodified lines | |||
| 26 | <FILE id="IwBoc4" name="leaf-global.h" compile="0" resource="0" file="../LEAF/Inc/leaf-global.h"/> | 26 | <FILE id="IwBoc4" name="leaf-global.h" compile="0" resource="0" file="../LEAF/Inc/leaf-global.h"/> |
| 27 | <FILE id="cmehFw" name="leaf-math.h" compile="0" resource="0" file="../LEAF/Inc/leaf-math.h"/> | 27 | <FILE id="cmehFw" name="leaf-math.h" compile="0" resource="0" file="../LEAF/Inc/leaf-math.h"/> |
| 28 | <FILE id="XQTGHV" name="leaf-mempool.h" compile="0" resource="0" file="../LEAF/Inc/leaf-mempool.h"/> | 28 | <FILE id="XQTGHV" name="leaf-mempool.h" compile="0" resource="0" file="../LEAF/Inc/leaf-mempool.h"/> |
| 29 | <FILE id="k0yQ8k" name="leaf-808.h" compile="0" resource="0" file="../LEAF/Inc/leaf-808.h"/> | 29 | <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/> |
| 30 | <FILE id="ZBcTKF" name="leaf-oscillators.h" compile="0" resource="0" | ||
| 31 | file="../LEAF/Inc/leaf-oscillators.h"/> | ||
| 32 | <FILE id="EnRmjE" name="leaf-filters.h" compile="0" resource="0" file="../LEAF/Inc/leaf-filters.h"/> | ||
| 30 | <FILE id="wn8tAr" name="leaf-delay.h" compile="0" resource="0" file="../LEAF/Inc/leaf-delay.h"/> | 33 | <FILE id="wn8tAr" name="leaf-delay.h" compile="0" resource="0" file="../LEAF/Inc/leaf-delay.h"/> |
| 31 | <FILE id="EnRmjE" name="leaf-filter.h" compile="0" resource="0" file="../LEAF/Inc/leaf-filter.h"/> | ||
| 32 | <FILE id="dWHebV" name="leaf-formant.h" compile="0" resource="0" file="../LEAF/Inc/leaf-formant.h"/> | ||
| 33 | <FILE id="pXe6b5" name="leaf-midi.h" compile="0" resource="0" file="../LEAF/Inc/leaf-midi.h"/> | ||
| 34 | <FILE id="ZBcTKF" name="leaf-oscillator.h" compile="0" resource="0" | ||
| 35 | file="../LEAF/Inc/leaf-oscillator.h"/> | ||
| 36 | <FILE id="LPMRGU" name="leaf-oversampler.h" compile="0" resource="0" | ||
| 37 | file="../LEAF/Inc/leaf-oversampler.h"/> | ||
| 38 | <FILE id="NekKkK" name="leaf-pitch.h" compile="0" resource="0" file="../LEAF/Inc/leaf-pitch.h"/> | ||
| 39 | <FILE id="XmL4ZE" name="leaf-reverb.h" compile="0" resource="0" file="../LEAF/Inc/leaf-reverb.h"/> | 34 | <FILE id="XmL4ZE" name="leaf-reverb.h" compile="0" resource="0" file="../LEAF/Inc/leaf-reverb.h"/> |
| 40 | <FILE id="KQca5l" name="leaf-string.h" compile="0" resource="0" file="../LEAF/Inc/leaf-string.h"/> | 35 | <FILE id="dWHebV" name="leaf-distortion.h" compile="0" resource="0" |
| 41 | <FILE id="OS2D83" name="leaf-utilities.h" compile="0" resource="0" | 36 | file="../LEAF/Inc/leaf-distortion.h"/> |
| 42 | file="../LEAF/Inc/leaf-utilities.h"/> | 37 | <FILE id="Szb5LP" name="leaf-effects.h" compile="0" resource="0" file="../LEAF/Inc/leaf-effects.h"/> |
| 43 | <FILE id="Szb5LP" name="leaf-vocoder.h" compile="0" resource="0" file="../LEAF/Inc/leaf-vocoder.h"/> | 38 | <FILE id="OS2D83" name="leaf-envelopes.h" compile="0" resource="0" |
| 44 | <FILE id="T6KXi7" name="leaf-sample.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sample.h"/> | 39 | file="../LEAF/Inc/leaf-envelopes.h"/> |
| 45 | <FILE id="bpUZCA" name="leaf-crusher.h" compile="0" resource="0" file="../LEAF/Inc/leaf-crusher.h"/> | 40 | <FILE id="PRkOp2" name="leaf-dynamics.h" compile="0" resource="0" file="../LEAF/Inc/leaf-dynamics.h"/> |
| 46 | <FILE id="PRkOp2" name="leaf-wavefolder.h" compile="0" resource="0" | 41 | <FILE id="LPMRGU" name="leaf-analysis.h" compile="0" resource="0" file="../LEAF/Inc/leaf-analysis.h"/> |
| 47 | file="../LEAF/Inc/leaf-wavefolder.h"/> | 42 | <FILE id="k0yQ8k" name="leaf-instruments.h" compile="0" resource="0" |
| 48 | <FILE id="lJdTFA" name="leaf-WDF.h" compile="0" resource="0" file="../LEAF/Inc/leaf-WDF.h"/> | 43 | file="../LEAF/Inc/leaf-instruments.h"/> |
| 49 | <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/> | 44 | <FILE id="pXe6b5" name="leaf-midi.h" compile="0" resource="0" file="../LEAF/Inc/leaf-midi.h"/> |
| 45 | <FILE id="T6KXi7" name="leaf-sampling.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sampling.h"/> | ||
| 46 | <FILE id="KQca5l" name="leaf-physical.h" compile="0" resource="0" file="../LEAF/Inc/leaf-physical.h"/> | ||
| 47 | <FILE id="lJdTFA" name="leaf-electrical.h" compile="0" resource="0" | ||
| 48 | file="../LEAF/Inc/leaf-electrical.h"/> | ||
| 50 | </GROUP> | 49 | </GROUP> |
| 51 | <GROUP id="{A3AE8C8C-29BA-ADB3-DD7D-EEDC2F7B58F3}" name="Src"> | 50 | <GROUP id="{A3AE8C8C-29BA-ADB3-DD7D-EEDC2F7B58F3}" name="Src"> |
| 52 | <FILE id="HbG7LO" name="leaf-808.c" compile="1" resource="0" file="../LEAF/Src/leaf-808.c"/> | 51 | <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/> |
| 53 | <FILE id="lLb7eq" name="leaf-delay.c" compile="1" resource="0" file="../LEAF/Src/leaf-delay.c"/> | ||
| 54 | <FILE id="nh9xAo" name="leaf-filter.c" compile="1" resource="0" file="../LEAF/Src/leaf-filter.c"/> | ||
| 55 | <FILE id="DPGZGc" name="leaf-formant.c" compile="1" resource="0" file="../LEAF/Src/leaf-formant.c"/> | ||
| 56 | <FILE id="g41P2E" name="leaf-math.c" compile="1" resource="0" file="../LEAF/Src/leaf-math.c"/> | 52 | <FILE id="g41P2E" name="leaf-math.c" compile="1" resource="0" file="../LEAF/Src/leaf-math.c"/> |
| 57 | <FILE id="Uc4jO6" name="leaf-mempool.c" compile="1" resource="0" file="../LEAF/Src/leaf-mempool.c"/> | 53 | <FILE id="Uc4jO6" name="leaf-mempool.c" compile="1" resource="0" file="../LEAF/Src/leaf-mempool.c"/> |
| 58 | <FILE id="LuoIDh" name="leaf-midi.c" compile="1" resource="0" file="../LEAF/Src/leaf-midi.c"/> | ||
| 59 | <FILE id="q5y59A" name="leaf-oscillator.c" compile="1" resource="0" | ||
| 60 | file="../LEAF/Src/leaf-oscillator.c"/> | ||
| 61 | <FILE id="E8JjWS" name="leaf-oversampler.c" compile="1" resource="0" | ||
| 62 | file="../LEAF/Src/leaf-oversampler.c"/> | ||
| 63 | <FILE id="eHUTvP" name="leaf-pitch.c" compile="1" resource="0" file="../LEAF/Src/leaf-pitch.c"/> | ||
| 64 | <FILE id="uyYwEd" name="leaf-reverb.c" compile="1" resource="0" file="../LEAF/Src/leaf-reverb.c"/> | ||
| 65 | <FILE id="dgAVr5" name="leaf-string.c" compile="1" resource="0" file="../LEAF/Src/leaf-string.c"/> | ||
| 66 | <FILE id="uKHzgz" name="leaf-utilities.c" compile="1" resource="0" | ||
| 67 | file="../LEAF/Src/leaf-utilities.c"/> | ||
| 68 | <FILE id="u1aLLR" name="leaf-vocoder.c" compile="1" resource="0" file="../LEAF/Src/leaf-vocoder.c"/> | ||
| 69 | <FILE id="nmtoFJ" name="leaf-sample.c" compile="1" resource="0" file="../LEAF/Src/leaf-sample.c"/> | ||
| 70 | <FILE id="Oymcac" name="leaf-crusher.c" compile="1" resource="0" file="../LEAF/Src/leaf-crusher.c"/> | ||
| 71 | <FILE id="LVoaGm" name="leaf-wavefolder.c" compile="1" resource="0" | ||
| 72 | file="../LEAF/Src/leaf-wavefolder.c"/> | ||
| 73 | <FILE id="Oh72PT" name="leaf-WDF.c" compile="1" resource="0" file="../LEAF/Src/leaf-WDF.c"/> | ||
| 74 | <FILE id="TxA1Gg" name="leaf-tables.c" compile="1" resource="0" file="../LEAF/Src/leaf-tables.c"/> | 54 | <FILE id="TxA1Gg" name="leaf-tables.c" compile="1" resource="0" file="../LEAF/Src/leaf-tables.c"/> |
| 75 | <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/> | 55 | <FILE id="q5y59A" name="leaf-oscillators.c" compile="1" resource="0" |
| 56 | file="../LEAF/Src/leaf-oscillators.c"/> | ||
| 57 | <FILE id="nh9xAo" name="leaf-filters.c" compile="1" resource="0" file="../LEAF/Src/leaf-filters.c"/> | ||
| 58 | <FILE id="lLb7eq" name="leaf-delay.c" compile="1" resource="0" file="../LEAF/Src/leaf-delay.c"/> | ||
| 59 | <FILE id="uyYwEd" name="leaf-reverb.c" compile="1" resource="0" file="../LEAF/Src/leaf-reverb.c"/> | ||
| 60 | <FILE id="E8JjWS" name="leaf-distortion.c" compile="1" resource="0" | ||
| 61 | file="../LEAF/Src/leaf-distortion.c"/> | ||
| 62 | <FILE id="u1aLLR" name="leaf-effects.c" compile="1" resource="0" file="../LEAF/Src/leaf-effects.c"/> | ||
| 63 | <FILE id="uKHzgz" name="leaf-envelopes.c" compile="1" resource="0" | ||
| 64 | file="../LEAF/Src/leaf-envelopes.c"/> | ||
| 65 | <FILE id="Oymcac" name="leaf-dynamics.c" compile="1" resource="0" file="../LEAF/Src/leaf-dynamics.c"/> | ||
| 66 | <FILE id="LVoaGm" name="leaf-analysis.c" compile="1" resource="0" file="../LEAF/Src/leaf-analysis.c"/> | ||
| 67 | <FILE id="HbG7LO" name="leaf-instruments.c" compile="1" resource="0" | ||
| 68 | file="../LEAF/Src/leaf-instruments.c"/> | ||
| 69 | <FILE id="LuoIDh" name="leaf-midi.c" compile="1" resource="0" file="../LEAF/Src/leaf-midi.c"/> | ||
| 70 | <FILE id="nmtoFJ" name="leaf-sampling.c" compile="1" resource="0" file="../LEAF/Src/leaf-sampling.c"/> | ||
| 71 | <FILE id="dgAVr5" name="leaf-physical.c" compile="1" resource="0" file="../LEAF/Src/leaf-physical.c"/> | ||
| 72 | <FILE id="Oh72PT" name="leaf-electrical.c" compile="1" resource="0" | ||
| 73 | file="../LEAF/Src/leaf-electrical.c"/> | ||
| 76 | </GROUP> | 74 | </GROUP> |
| 77 | <FILE id="dmljDQ" name="leaf.h" compile="0" resource="0" file="../LEAF/leaf.h"/> | 75 | <FILE id="dmljDQ" name="leaf.h" compile="0" resource="0" file="../LEAF/leaf.h"/> |
| 78 | </GROUP> | 76 | </GROUP> |
| @@ -37,6 +37,8 @@ void LEAFTest_init (float sampleRate, int blockSize) · 36 unmodified lines | |||
| 37 | tCycle_init(&sine); | 37 | tCycle_init(&sine); |
| 38 | tCycle_setFreq(&sine, 200); | 38 | tCycle_setFreq(&sine, 200); |
| 39 | tDelay_init(&delay, 44100, 44100); | 39 | tDelay_init(&delay, 44100, 44100); |
| 40 | tDelay_free(&delay); //most basic free test | ||
| 41 | tDelay_init(&delay, 44100, 44100); | ||
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | float LEAFTest_tick (float input) | 44 | float LEAFTest_tick (float input) |
| @@ -98,7 +100,7 @@ void leaf_pool_report(void) · 55 unmodified lines | |||
| 98 | void leaf_pool_dump(void) | 100 | void leaf_pool_dump(void) |
| 99 | { | 101 | { |
| 100 | float* buff = (float*)leaf_pool_get_pool(); | 102 | float* buff = (float*)leaf_pool_get_pool(); |
| 101 | int siz = leaf_pool_get_size(); | 103 | unsigned long siz = leaf_pool_get_size(); |
| 102 | siz /= sizeof(float); | 104 | siz /= sizeof(float); |
| 103 | for (int i = 0; i < siz; i++) | 105 | for (int i = 0; i < siz; i++) |
| 104 | { | 106 | { |