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 | 50 | /* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */ |
| 51 | −typedef struct _tDelayL | |
| 51 | +typedef struct _tLinearDelay | |
| 52 | 52 | { |
| 53 | 53 | float gain; |
| 54 | 54 | float* buff; |
| @@ -63,26 +63,26 @@ typedef struct _tDelayL · 8 unmodified lines | ||
| 63 | 63 | |
| 64 | 64 | float alpha, omAlpha; |
| 65 | 65 | |
| 66 | −} tDelayL; | |
| 66 | +} tLinearDelay; | |
| 67 | 67 | |
| 68 | −void tDelayL_init (tDelayL* const, float delay, uint32_t maxDelay); | |
| 69 | −void tDelayL_free (tDelayL* const); | |
| 68 | +void tLinearDelay_init (tLinearDelay* const, float delay, uint32_t maxDelay); | |
| 69 | +void tLinearDelay_free (tLinearDelay* const); | |
| 70 | 70 | |
| 71 | −int tDelayL_setDelay (tDelayL* const, float delay); | |
| 72 | −float tDelayL_getDelay (tDelayL* const); | |
| 73 | −void tDelayL_tapIn (tDelayL* const, float in, uint32_t tapDelay); | |
| 74 | −float tDelayL_tapOut (tDelayL* const, float tapDelay); | |
| 75 | −float tDelayL_addTo (tDelayL* const, float value, uint32_t tapDelay); | |
| 76 | −float tDelayL_tick (tDelayL* const, float sample); | |
| 77 | −void tDelayL_tickIn (tDelayL* const d, float input); | |
| 78 | −float tDelayL_tickOut (tDelayL* const d); | |
| 79 | −float tDelayL_getLastOut (tDelayL* const); | |
| 80 | −float tDelayL_getLastIn (tDelayL* const); | |
| 71 | +int tLinearDelay_setDelay (tLinearDelay* const, float delay); | |
| 72 | +float tLinearDelay_getDelay (tLinearDelay* const); | |
| 73 | +void tLinearDelay_tapIn (tLinearDelay* const, float in, uint32_t tapDelay); | |
| 74 | +float tLinearDelay_tapOut (tLinearDelay* const, float tapDelay); | |
| 75 | +float tLinearDelay_addTo (tLinearDelay* const, float value, uint32_t tapDelay); | |
| 76 | +float tLinearDelay_tick (tLinearDelay* const, float sample); | |
| 77 | +void tLinearDelay_tickIn (tLinearDelay* const d, float input); | |
| 78 | +float tLinearDelay_tickOut (tLinearDelay* const d); | |
| 79 | +float tLinearDelay_getLastOut (tLinearDelay* const); | |
| 80 | +float tLinearDelay_getLastIn (tLinearDelay* const); | |
| 81 | 81 | |
| 82 | 82 | //============================================================================== |
| 83 | 83 | |
| 84 | 84 | /* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */ |
| 85 | −typedef struct _tDelayA | |
| 85 | +typedef struct _tAllpassDelay | |
| 86 | 86 | { |
| 87 | 87 | float gain; |
| 88 | 88 | float* buff; |
| @@ -99,19 +99,19 @@ typedef struct _tDelayA · 10 unmodified lines | ||
| 99 | 99 | |
| 100 | 100 | float apInput; |
| 101 | 101 | |
| 102 | −} tDelayA; | |
| 102 | +} tAllpassDelay; | |
| 103 | 103 | |
| 104 | −void tDelayA_init (tDelayA* const, float delay, uint32_t maxDelay); | |
| 105 | −void tDelayA_free (tDelayA* const); | |
| 104 | +void tAllpassDelay_init (tAllpassDelay* const, float delay, uint32_t maxDelay); | |
| 105 | +void tAllpassDelay_free (tAllpassDelay* const); | |
| 106 | 106 | |
| 107 | −int tDelayA_setDelay (tDelayA* const, float delay); | |
| 108 | −float tDelayA_getDelay (tDelayA* const); | |
| 109 | −void tDelayA_tapIn (tDelayA* const, float in, uint32_t tapDelay); | |
| 110 | −float tDelayA_tapOut (tDelayA* const, uint32_t tapDelay); | |
| 111 | −float tDelayA_addTo (tDelayA* const, float value, uint32_t tapDelay); | |
| 112 | −float tDelayA_tick (tDelayA* const, float sample); | |
| 113 | −float tDelayA_getLastOut (tDelayA* const); | |
| 114 | −float tDelayA_getLastIn (tDelayA* const); | |
| 107 | +int tAllpassDelay_setDelay (tAllpassDelay* const, float delay); | |
| 108 | +float tAllpassDelay_getDelay (tAllpassDelay* const); | |
| 109 | +void tAllpassDelay_tapIn (tAllpassDelay* const, float in, uint32_t tapDelay); | |
| 110 | +float tAllpassDelay_tapOut (tAllpassDelay* const, uint32_t tapDelay); | |
| 111 | +float tAllpassDelay_addTo (tAllpassDelay* const, float value, uint32_t tapDelay); | |
| 112 | +float tAllpassDelay_tick (tAllpassDelay* const, float sample); | |
| 113 | +float tAllpassDelay_getLastOut (tAllpassDelay* 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 | 4 | * Created on: Sep 25, 2019 |
| 5 | 5 | * Author: jeffsnyder |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | −#ifndef LEAF_INC_LEAF_WDF_H_ | |
| 9 | −#define LEAF_INC_LEAF_WDF_H_ | |
| 8 | +#ifndef LEAF_INC_LEAF_ELECTRICAL_H_ | |
| 9 | +#define LEAF_INC_LEAF_ELECTRICAL_H_ | |
| 10 | 10 | |
| 11 | 11 | #ifdef __cplusplus |
| 12 | 12 | extern "C" { |
| @@ -86,4 +86,4 @@ float tWDF_getCurrent(tWDF* const r); · 73 unmodified lines | ||
| 86 | 86 | } |
| 87 | 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 | 4 | Created: 20 Jan 2017 12:01:10pm |
| 5 | 5 | Author: Michael R Mulshine |
| 6 | 6 | |
| 7 | 7 | ==============================================================================*/ |
| 8 | 8 | |
| 9 | −#ifndef LEAF_FILTER_H_INCLUDED | |
| 10 | −#define LEAF_FILTER_H_INCLUDED | |
| 9 | +#ifndef LEAF_FILTERS_H_INCLUDED | |
| 10 | +#define LEAF_FILTERS_H_INCLUDED | |
| 11 | 11 | |
| 12 | 12 | #ifdef __cplusplus |
| 13 | 13 | extern "C" { |
| @@ -26,7 +26,7 @@ typedef struct _tAllpass · 12 unmodified lines | ||
| 26 | 26 | { |
| 27 | 27 | float gain; |
| 28 | 28 | |
| 29 | − tDelayL delay; | |
| 29 | + tLinearDelay delay; | |
| 30 | 30 | |
| 31 | 31 | float lastOut; |
| 32 | 32 | |
| @@ -227,21 +227,21 @@ int tSVF_setQ (tSVF* const, float Q); · 194 unmodified lines | ||
| 227 | 227 | //============================================================================== |
| 228 | 228 | |
| 229 | 229 | /* Efficient State Variable Filter for 14-bit control input, [0, 4096). */ |
| 230 | −typedef struct _tSVFE | |
| 230 | +typedef struct _tEfficientSVF | |
| 231 | 231 | { |
| 232 | 232 | SVFType type; |
| 233 | 233 | float cutoff, Q; |
| 234 | 234 | float ic1eq,ic2eq; |
| 235 | 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); | |
| 240 | −void tSVFE_free (tSVFE* const); | |
| 239 | +void tEfficientSVF_init (tEfficientSVF* const, SVFType type, uint16_t controlFreq, float Q); | |
| 240 | +void tEfficientSVF_free (tEfficientSVF* const); | |
| 241 | 241 | |
| 242 | −float tSVFE_tick (tSVFE* const, float v0); | |
| 243 | −int tSVFE_setFreq (tSVFE* const, uint16_t controlFreq); | |
| 244 | −int tSVFE_setQ (tSVFE* const, float Q); | |
| 242 | +float tEfficientSVF_tick (tEfficientSVF* const, float v0); | |
| 243 | +int tEfficientSVF_setFreq (tEfficientSVF* const, uint16_t controlFreq); | |
| 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 | 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 | 4 | Created: 30 Nov 2018 10:24:44am |
| 5 | 5 | Author: airship |
| 6 | 6 | |
| 7 | 7 | ==============================================================================*/ |
| 8 | 8 | |
| 9 | −#ifndef LEAF_808_H_INCLUDED | |
| 10 | −#define LEAF_808_H_INCLUDED | |
| 9 | +#ifndef LEAF_INSTRUMENTS_H_INCLUDED | |
| 10 | +#define LEAF_INSTRUMENTS_H_INCLUDED | |
| 11 | 11 | |
| 12 | 12 | #ifdef __cplusplus |
| 13 | 13 | extern "C" { |
| @@ -16,9 +16,9 @@ extern "C" { · 2 unmodified lines | ||
| 16 | 16 | //============================================================================== |
| 17 | 17 | |
| 18 | 18 | #include "leaf-math.h" |
| 19 | −#include "leaf-oscillator.h" | |
| 20 | −#include "leaf-utilities.h" | |
| 21 | −#include "leaf-filter.h" | |
| 19 | +#include "leaf-oscillators.h" | |
| 20 | +#include "leaf-filters.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 | 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 | 18 | #include "leaf-global.h" |
| 19 | 19 | #include "leaf-mempool.h" |
| 20 | 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 | 53 | /* tPoly */ |
| 26 | 54 | typedef struct _tPoly |
| 27 | 55 | { |
| @@ -1,13 +1,13 @@ | ||
| 1 | 1 | /*============================================================================== |
| 2 | 2 | |
| 3 | − leaf-oscillator.h | |
| 3 | + leaf-oscillators.h | |
| 4 | 4 | Created: 20 Jan 2017 12:00:58pm |
| 5 | 5 | Author: Michael R Mulshine |
| 6 | 6 | |
| 7 | 7 | ==============================================================================*/ |
| 8 | 8 | |
| 9 | −#ifndef LEAF_OSCILLATOR_H_INCLUDED | |
| 10 | −#define LEAF_OSCILLATOR_H_INCLUDED | |
| 9 | +#ifndef LEAF_OSCILLATORS_H_INCLUDED | |
| 10 | +#define LEAF_OSCILLATORS_H_INCLUDED | |
| 11 | 11 | |
| 12 | 12 | #ifdef __cplusplus |
| 13 | 13 | extern "C" { |
| @@ -16,68 +16,7 @@ extern "C" { · 2 unmodified lines | ||
| 16 | 16 | //============================================================================== |
| 17 | 17 | |
| 18 | 18 | #include "leaf-math.h" |
| 19 | − | |
| 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); | |
| 19 | +#include "leaf-filters.h" | |
| 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 | 40 | /* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */ |
| 119 | 41 | typedef struct _tTriangle |
| 120 | 42 | { |
| @@ -146,6 +68,39 @@ void tSquare_free (tSquare* const); · 25 unmodified lines | ||
| 146 | 68 | |
| 147 | 69 | float tSquare_tick (tSquare* const); |
| 148 | 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 | 117 | NoiseType type; |
| 163 | 118 | float pinkb0, pinkb1, pinkb2; |
| 164 | − float(*rand)(); | |
| 119 | + float(*rand)(void); | |
| 165 | 120 | |
| 166 | 121 | } tNoise; |
| 167 | 122 | |
| @@ -169,6 +124,50 @@ void tNoise_init (tNoise* const, NoiseType type); · 1 unmodified line | ||
| 169 | 124 | void tNoise_free (tNoise* const); |
| 170 | 125 | |
| 171 | 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 | 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 | 18 | #include "leaf-global.h" |
| 19 | 19 | #include "leaf-math.h" |
| 20 | − | |
| 21 | 20 | #include "leaf-delay.h" |
| 22 | −#include "leaf-filter.h" | |
| 23 | −#include "leaf-oscillator.h" | |
| 21 | +#include "leaf-filters.h" | |
| 22 | +#include "leaf-oscillators.h" | |
| 24 | 23 | |
| 25 | 24 | //============================================================================== |
| 26 | 25 | |
| 27 | −/* PRCRev: Reverb, reimplemented from STK (Cook and Scavone). */ | |
| 28 | −typedef struct _tPRCRev | |
| 26 | +/* PRCReverb: Reverb, reimplemented from STK (Cook and Scavone). */ | |
| 27 | +typedef struct _tPRCReverb | |
| 29 | 28 | { |
| 30 | 29 | float mix, t60; |
| 31 | 30 | |
| @@ -38,23 +37,23 @@ typedef struct _tPRCRev · 6 unmodified lines | ||
| 38 | 37 | |
| 39 | 38 | float lastIn, lastOut; |
| 40 | 39 | |
| 41 | −} tPRCRev; | |
| 40 | +} tPRCReverb; | |
| 42 | 41 | |
| 43 | −void tPRCRev_init (tPRCRev* const, float t60); | |
| 44 | −void tPRCRev_free (tPRCRev* const); | |
| 42 | +void tPRCReverb_init (tPRCReverb* const, float t60); | |
| 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 | 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 | 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). */ | |
| 57 | −typedef struct _tNRev | |
| 55 | +/* NReverb: Reverb, reimplemented from STK (Cook and Scavone). */ | |
| 56 | +typedef struct _tNReverb | |
| 58 | 57 | { |
| 59 | 58 | float mix, t60; |
| 60 | 59 | |
| @@ -68,22 +67,22 @@ typedef struct _tNRev · 7 unmodified lines | ||
| 68 | 67 | |
| 69 | 68 | float lastIn, lastOut; |
| 70 | 69 | |
| 71 | −} tNRev; | |
| 70 | +} tNReverb; | |
| 72 | 71 | |
| 73 | −void tNRev_init (tNRev* const, float t60); | |
| 74 | −void tNRev_free (tNRev* const); | |
| 72 | +void tNReverb_init (tNReverb* const, float t60); | |
| 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 | 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 | 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 | 87 | float predelay; |
| 89 | 88 | float input_filter; |
| @@ -125,19 +124,19 @@ typedef struct _tDattorro · 35 unmodified lines | ||
| 125 | 124 | |
| 126 | 125 | tCycle f2_lfo; |
| 127 | 126 | |
| 128 | −} tDattorro; | |
| 127 | +} tDattorroReverb; | |
| 129 | 128 | |
| 130 | −void tDattorro_init (tDattorro* const); | |
| 131 | −void tDattorro_free (tDattorro* const); | |
| 129 | +void tDattorroReverb_init (tDattorroReverb* 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); | |
| 136 | −void tDattorro_setSize (tDattorro* const, float size); | |
| 137 | −void tDattorro_setInputDelay (tDattorro* const, float preDelay); | |
| 138 | −void tDattorro_setInputFilter (tDattorro* const, float freq); | |
| 139 | −void tDattorro_setFeedbackFilter (tDattorro* const, float freq); | |
| 140 | −void tDattorro_setFeedbackGain (tDattorro* const, float gain); | |
| 134 | +void tDattorroReverb_setMix (tDattorroReverb* const, float mix); | |
| 135 | +void tDattorroReverb_setSize (tDattorroReverb* const, float size); | |
| 136 | +void tDattorroReverb_setInputDelay (tDattorroReverb* const, float preDelay); | |
| 137 | +void tDattorroReverb_setInputFilter (tDattorroReverb* const, float freq); | |
| 138 | +void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const, float freq); | |
| 139 | +void tDattorroReverb_setFeedbackGain (tDattorroReverb* const, float gain); | |
| 141 | 140 | |
| 142 | 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 | |
| 10 | −#define LEAF_WAVETABLES_H_INCLUDED | |
| 9 | +#ifndef LEAF_TABLES_H_INCLUDED | |
| 10 | +#define LEAF_TABLES_H_INCLUDED | |
| 11 | 11 | |
| 12 | 12 | #ifdef __cplusplus |
| 13 | 13 | extern "C" { |
| @@ -95,6 +95,6 @@ extern const float squarewave[11][SQR_TABLE_SIZE]; · 81 unmodified lines | ||
| 95 | 95 | } |
| 96 | 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 | 127 | return d->gain; |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | −// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayL ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | |
| 131 | −void tDelayL_init (tDelayL* const d, float delay, uint32_t maxDelay) | |
| 130 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ LinearDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | |
| 131 | +void tLinearDelay_init (tLinearDelay* const d, float delay, uint32_t maxDelay) | |
| 132 | 132 | { |
| 133 | 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 | 146 | d->inPoint = 0; |
| 147 | 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 | 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 | 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 | 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 | 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 | 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 | 189 | uint32_t idx = (uint32_t) d->outPoint; |
| 190 | 190 | |
| @@ -200,7 +200,7 @@ float tDelayL_tickOut (tDelayL* const d) · 9 unmodified lines | ||
| 200 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 284 | if (gain < 0.0f) d->gain = 0.0f; |
| 285 | 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 | 290 | return d->gain; |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | −// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayA ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | |
| 294 | −void tDelayA_init (tDelayA* const d, float delay, uint32_t maxDelay) | |
| 293 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ AllpassDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | |
| 294 | +void tAllpassDelay_init (tAllpassDelay* const d, float delay, uint32_t maxDelay) | |
| 295 | 295 | { |
| 296 | 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 | 309 | d->inPoint = 0; |
| 310 | 310 | d->outPoint = 0; |
| 311 | 311 | |
| 312 | − tDelayA_setDelay(d, d->delay); | |
| 312 | + tAllpassDelay_setDelay(d, d->delay); | |
| 313 | 313 | |
| 314 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 424 | if (gain < 0.0f) d->gain = 0.0f; |
| 425 | 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 | 430 | return d->gain; |
| 431 | 431 | } |
| @@ -8,17 +8,188 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | |
| 11 | −#include "..\Inc\leaf-oversampler.h" | |
| 11 | +#include "..\Inc\leaf-distortion.h" | |
| 12 | 12 | #include "..\Inc\leaf-tables.h" |
| 13 | 13 | #else |
| 14 | 14 | |
| 15 | 15 | |
| 16 | −#include "../Inc/leaf-oversampler.h" | |
| 16 | +#include "../Inc/leaf-distortion.h" | |
| 17 | 17 | #include "../Inc/leaf-tables.h" |
| 18 | 18 | |
| 19 | 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 | 191 | // Oversampler |
| 192 | +//============================================================================================================ | |
| 22 | 193 | // Latency is equal to the phase length (numTaps / ratio) |
| 23 | 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 | 4 | * Created on: Sep 25, 2019 |
| 5 | 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 | 22 | static float get_port_resistance_for_resistor(tWDF* const r); |
| 12 | 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 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | |
| 11 | −#include "..\Inc\leaf-filter.h" | |
| 11 | +#include "..\Inc\leaf-filters.h" | |
| 12 | 12 | #include "..\Inc\leaf-tables.h" |
| 13 | 13 | #include "..\leaf.h" |
| 14 | 14 | |
| 15 | 15 | #else |
| 16 | 16 | |
| 17 | −#include "../Inc/leaf-filter.h" | |
| 17 | +#include "../Inc/leaf-filters.h" | |
| 18 | 18 | #include "../Inc/leaf-tables.h" |
| 19 | 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 | 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 | 33 | void tAllpass_free(tAllpass* const f) |
| 34 | 34 | { |
| 35 | − tDelayL_free(&f->delay); | |
| 35 | + tLinearDelay_free(&f->delay); | |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 789 | float v1,v2,v3; |
| 790 | 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 | 807 | svf->g = filtertan[input]; |
| 808 | 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 | 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 | 817 | svf->k = 1.0f/Q; |
| 818 | 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 | 4 | Created: 30 Nov 2018 10:24:21am |
| 5 | 5 | Author: airship |
| 6 | 6 | |
| @@ -8,11 +8,11 @@ · 1 unmodified line | ||
| 8 | 8 | |
| 9 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | |
| 11 | −#include "..\Inc\leaf-808.h" | |
| 11 | +#include "..\Inc\leaf-instruments.h" | |
| 12 | 12 | |
| 13 | 13 | #else |
| 14 | 14 | |
| 15 | −#include "../Inc/leaf-808.h" | |
| 15 | +#include "../Inc/leaf-instruments.h" | |
| 16 | 16 | |
| 17 | 17 | #endif |
| 18 | 18 | |
| @@ -355,3 +355,5 @@ float LEAF_interpolation_linear (float A, float B, float alpha) · 354 unmodified lines | ||
| 355 | 355 | |
| 356 | 356 | return out; |
| 357 | 357 | } |
| 358 | + | |
| 359 | + | |
| @@ -305,3 +305,216 @@ int tPoly_isOn(tPoly* const poly, uint8_t voice) · 304 unmodified lines | ||
| 305 | 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 | 4 | Created: 20 Jan 2017 12:00:58pm |
| 5 | 5 | Author: Michael R Mulshine |
| 6 | 6 | |
| @@ -9,212 +9,17 @@ · 2 unmodified lines | ||
| 9 | 9 | #if _WIN32 || _WIN64 |
| 10 | 10 | |
| 11 | 11 | #include "..\Inc\leaf-tables.h" |
| 12 | −#include "..\Inc\leaf-oscillator.h" | |
| 12 | +#include "..\Inc\leaf-oscillators.h" | |
| 13 | 13 | #include "..\leaf.h" |
| 14 | 14 | |
| 15 | 15 | #else |
| 16 | 16 | |
| 17 | 17 | #include "../Inc/leaf-tables.h" |
| 18 | −#include "../Inc/leaf-oscillator.h" | |
| 18 | +#include "../Inc/leaf-oscillators.h" | |
| 19 | 19 | #include "../leaf.h" |
| 20 | 20 | |
| 21 | 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 | 23 | // Cycle |
| 219 | 24 | void tCycle_init(tCycle* const c) |
| 220 | 25 | { |
| @@ -258,56 +63,25 @@ void tCycleSampleRateChanged (tCycle* const c) · 37 unmodified lines | ||
| 258 | 63 | c->inc = c->freq * leaf.invSampleRate; |
| 259 | 64 | } |
| 260 | 65 | |
| 261 | −/* Phasor */ | |
| 262 | −void tPhasorSampleRateChanged (tPhasor* const p) | |
| 263 | −{ | |
| 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) | |
| 66 | +//======================================================================== | |
| 67 | +/* Triangle */ | |
| 68 | +void tTriangle_start(tTriangle* const c) | |
| 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; | |
| 281 | − | |
| 282 | − p->freq = freq; | |
| 283 | − p->inc = freq * leaf.invSampleRate; | |
| 284 | − | |
| 285 | − return 0; | |
| 75 | + c->inc = 0.0f; | |
| 76 | + c->phase = 0.0f; | |
| 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 | − | |
| 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) | |
| 84 | +int tTriangle_setFreq(tTriangle* const c, float freq) | |
| 311 | 85 | { |
| 312 | 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 | 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 | 97 | // Phasor increment |
| 323 | 98 | c->phase += c->inc; |
| @@ -332,89 +107,85 @@ float tSawtooth_tick(tSawtooth* const c) · 8 unmodified lines | ||
| 332 | 107 | |
| 333 | 108 | if (c->freq <= 20.0f) |
| 334 | 109 | { |
| 335 | − out = sawtooth[T20][idx]; | |
| 110 | + out = triangle[T20][idx]; | |
| 336 | 111 | } |
| 337 | 112 | else if (c->freq <= 40.0f) |
| 338 | 113 | { |
| 339 | 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 | 117 | else if (c->freq <= 80.0f) |
| 343 | 118 | { |
| 344 | 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 | 122 | else if (c->freq <= 160.0f) |
| 348 | 123 | { |
| 349 | 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 | 127 | else if (c->freq <= 320.0f) |
| 353 | 128 | { |
| 354 | 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 | 132 | else if (c->freq <= 640.0f) |
| 358 | 133 | { |
| 359 | 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 | 137 | else if (c->freq <= 1280.0f) |
| 363 | 138 | { |
| 364 | 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 | 142 | else if (c->freq <= 2560.0f) |
| 368 | 143 | { |
| 369 | 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 | 147 | else if (c->freq <= 5120.0f) |
| 373 | 148 | { |
| 374 | 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 | 152 | else if (c->freq <= 10240.0f) |
| 378 | 153 | { |
| 379 | 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 | 157 | else if (c->freq <= 20480.0f) |
| 383 | 158 | { |
| 384 | 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 | 162 | else |
| 388 | 163 | { |
| 389 | − out = sawtooth[T20480][idx]; | |
| 164 | + out = triangle[T20480][idx]; | |
| 390 | 165 | } |
| 391 | 166 | |
| 392 | 167 | return out; |
| 393 | 168 | } |
| 394 | 169 | |
| 395 | −void tSawtoothSampleRateChanged (tSawtooth* const c) | |
| 170 | +void tTriangleSampleRateChanged (tTriangle* const c) | |
| 396 | 171 | { |
| 397 | 172 | c->inc = c->freq * leaf.invSampleRate; |
| 398 | 173 | } |
| 399 | 174 | |
| 400 | −/* Triangle */ | |
| 401 | −void tTriangle_start(tTriangle* const c) | |
| 402 | −{ | |
| 403 | − | |
| 404 | −} | |
| 405 | − | |
| 406 | −void tTriangle_init(tTriangle* const c) | |
| 175 | +//======================================================================== | |
| 176 | +/* Square */ | |
| 177 | +void tSquare_init(tSquare* const c) | |
| 407 | 178 | { |
| 408 | 179 | c->inc = 0.0f; |
| 409 | 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 | 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 | 195 | return 0; |
| 425 | 196 | } |
| 426 | 197 | |
| 427 | − | |
| 428 | −float tTriangle_tick(tTriangle* const c) | |
| 198 | +float tSquare_tick(tSquare* const c) | |
| 429 | 199 | { |
| 430 | 200 | // Phasor increment |
| 431 | 201 | c->phase += c->inc; |
| 432 | 202 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 433 | 203 | |
| 434 | 204 | float out = 0.0f; |
| 435 | − float w; | |
| 436 | − | |
| 205 | + float w = 0.0f; | |
| 437 | 206 | int idx = (int)(c->phase * TRI_TABLE_SIZE); |
| 438 | 207 | |
| 439 | 208 | // Wavetable synthesis |
| 440 | 209 | |
| 441 | 210 | if (c->freq <= 20.0f) |
| 442 | 211 | { |
| 443 | − out = triangle[T20][idx]; | |
| 212 | + out = squarewave[T20][idx]; | |
| 444 | 213 | } |
| 445 | 214 | else if (c->freq <= 40.0f) |
| 446 | 215 | { |
| 447 | 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 | 219 | else if (c->freq <= 80.0f) |
| 451 | 220 | { |
| 452 | 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 | 224 | else if (c->freq <= 160.0f) |
| 456 | 225 | { |
| 457 | 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 | 229 | else if (c->freq <= 320.0f) |
| 461 | 230 | { |
| 462 | 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 | 234 | else if (c->freq <= 640.0f) |
| 466 | 235 | { |
| 467 | 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 | 239 | else if (c->freq <= 1280.0f) |
| 471 | 240 | { |
| 472 | 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 | 244 | else if (c->freq <= 2560.0f) |
| 476 | 245 | { |
| 477 | 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 | 249 | else if (c->freq <= 5120.0f) |
| 481 | 250 | { |
| 482 | 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 | 254 | else if (c->freq <= 10240.0f) |
| 486 | 255 | { |
| 487 | 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 | 259 | else if (c->freq <= 20480.0f) |
| 491 | 260 | { |
| 492 | 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 | 264 | else |
| 496 | 265 | { |
| 497 | − out = triangle[T20480][idx]; | |
| 266 | + out = squarewave[T20480][idx]; | |
| 498 | 267 | } |
| 499 | 268 | |
| 500 | 269 | return out; |
| 501 | 270 | } |
| 502 | 271 | |
| 503 | −void tTriangleSampleRateChanged (tTriangle* const c) | |
| 272 | +void tSquareSampleRateChanged (tSquare* const c) | |
| 504 | 273 | { |
| 505 | 274 | c->inc = c->freq * leaf.invSampleRate; |
| 506 | 275 | } |
| 507 | 276 | |
| 508 | −/* Square */ | |
| 509 | −void tSquare_init(tSquare* const c) | |
| 277 | +//===================================================================== | |
| 278 | +// Sawtooth | |
| 279 | +void tSawtooth_init(tSawtooth* const c) | |
| 510 | 280 | { |
| 511 | − c->inc = 0.0f; | |
| 512 | − c->phase = 0.0f; | |
| 281 | + c->inc = 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 | 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 | 297 | return 0; |
| 528 | 298 | } |
| 529 | 299 | |
| 530 | −float tSquare_tick(tSquare* const c) | |
| 300 | +float tSawtooth_tick(tSawtooth* const c) | |
| 531 | 301 | { |
| 532 | 302 | // Phasor increment |
| 533 | 303 | c->phase += c->inc; |
| 534 | 304 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 535 | 305 | |
| 536 | 306 | float out = 0.0f; |
| 537 | − float w = 0.0f; | |
| 307 | + float w; | |
| 308 | + | |
| 538 | 309 | int idx = (int)(c->phase * TRI_TABLE_SIZE); |
| 539 | 310 | |
| 540 | 311 | // Wavetable synthesis |
| 541 | 312 | |
| 542 | 313 | if (c->freq <= 20.0f) |
| 543 | 314 | { |
| 544 | − out = squarewave[T20][idx]; | |
| 315 | + out = sawtooth[T20][idx]; | |
| 545 | 316 | } |
| 546 | 317 | else if (c->freq <= 40.0f) |
| 547 | 318 | { |
| 548 | 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 | 322 | else if (c->freq <= 80.0f) |
| 552 | 323 | { |
| 553 | 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 | 327 | else if (c->freq <= 160.0f) |
| 557 | 328 | { |
| 558 | 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 | 332 | else if (c->freq <= 320.0f) |
| 562 | 333 | { |
| 563 | 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 | 337 | else if (c->freq <= 640.0f) |
| 567 | 338 | { |
| 568 | 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 | 342 | else if (c->freq <= 1280.0f) |
| 572 | 343 | { |
| 573 | 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 | 347 | else if (c->freq <= 2560.0f) |
| 577 | 348 | { |
| 578 | 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 | 352 | else if (c->freq <= 5120.0f) |
| 582 | 353 | { |
| 583 | 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 | 357 | else if (c->freq <= 10240.0f) |
| 587 | 358 | { |
| 588 | 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 | 362 | else if (c->freq <= 20480.0f) |
| 592 | 363 | { |
| 593 | 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 | 367 | else |
| 597 | 368 | { |
| 598 | − out = squarewave[T20480][idx]; | |
| 369 | + out = sawtooth[T20480][idx]; | |
| 599 | 370 | } |
| 600 | 371 | |
| 601 | 372 | return out; |
| 602 | 373 | } |
| 603 | 374 | |
| 604 | −void tSquareSampleRateChanged (tSquare* const c) | |
| 375 | +void tSawtoothSampleRateChanged (tSawtooth* const c) | |
| 605 | 376 | { |
| 606 | 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 | 417 | /* Noise */ |
| 610 | 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 | 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 | 19 | #endif |
| 20 | 20 | |
| 21 | −// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | |
| 22 | −void tPRCRev_init(tPRCRev* const r, float t60) | |
| 21 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ // | |
| 22 | +void tPRCReverb_init(tPRCReverb* const r, float t60) | |
| 23 | 23 | { |
| 24 | 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 | 47 | tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2); |
| 48 | 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 | 52 | r->allpassCoeff = 0.7f; |
| 53 | 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 | 58 | tDelay_free(&r->allpassDelays[0]); |
| 59 | 59 | tDelay_free(&r->allpassDelays[1]); |
| 60 | 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 | 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 | 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 | 80 | float temp, temp0, temp1, temp2; |
| 81 | 81 | float out; |
| @@ -107,13 +107,13 @@ float tPRCRev_tick(tPRCRev* const r, float input) · 25 unmodified lines | ||
| 107 | 107 | return out; |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | −void tPRCRevSampleRateChanged (tPRCRev* const r) | |
| 110 | +void tPRCReverbSampleRateChanged (tPRCReverb* const r) | |
| 111 | 111 | { |
| 112 | 112 | r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 )); |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | −/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | |
| 116 | −void tNRev_init(tNRev* const r, float t60) | |
| 115 | +/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */ | |
| 116 | +void tNReverb_init(tNReverb* const r, float t60) | |
| 117 | 117 | { |
| 118 | 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 | 150 | tDelay_setDelay(&r->combDelays[i], lengths[i+2]); |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | − tNRev_setT60(r, t60); | |
| 153 | + tNReverb_setT60(r, t60); | |
| 154 | 154 | r->allpassCoeff = 0.7f; |
| 155 | 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 | 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 | 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 | 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 | 188 | r->lastIn = input; |
| 189 | 189 | |
| @@ -221,10 +221,10 @@ float tNRev_tick(tNRev* const r, float input) · 31 unmodified lines | ||
| 221 | 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 | 225 | temp3 = r->allpassCoeff * temp; |
| 226 | 226 | temp3 += temp1; |
| 227 | − tDelayLTick(&r->allpassDelays[5], temp3 ); | |
| 227 | + tLinearDelayTick(&r->allpassDelays[5], temp3 ); | |
| 228 | 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 | 237 | return out; |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | −void tNRevSampleRateChanged (tNRev* const r) | |
| 240 | +void tNReverbSampleRateChanged (tNReverb* const r) | |
| 241 | 241 | { |
| 242 | 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 | 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 | 255 | r->size_max = 2.0f; |
| 256 | 256 | r->size = 1.f; |
| @@ -298,20 +298,20 @@ void tDattorro_init (tDattorro* const r) · 41 unmodified lines | ||
| 298 | 298 | |
| 299 | 299 | |
| 300 | 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 | 316 | // INPUT |
| 317 | 317 | tTapeDelay_free(&r->in_delay); |
| @@ -349,7 +349,7 @@ void tDattorro_free (tDattorro* const r) · 31 unmodified lines | ||
| 349 | 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 | 354 | // INPUT |
| 355 | 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 | 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 | 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 | 459 | r->size = LEAF_clip(0.01f, size*r->size_max, r->size_max); |
| 460 | 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 | 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 | 488 | r->predelay = LEAF_clip(0.0f, preDelay, 200.0f); |
| 489 | 489 | |
| 490 | 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 | 495 | r->input_filter = LEAF_clip(0.0f, freq, 20000.0f); |
| 496 | 496 | |
| 497 | 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 | 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 | 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 | 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 | 5 | Created: 20 Jan 2017 12:02:17pm |
| 6 | 6 | Author: Michael R Mulshine |
| 7 | 7 | |
| @@ -11,12 +11,12 @@ · 3 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #if _WIN32 || _WIN64 |
| 13 | 13 | |
| 14 | −#include "..\Inc\leaf-sample.h" | |
| 14 | +#include "..\Inc\leaf-sampling.h" | |
| 15 | 15 | #include "..\leaf.h" |
| 16 | 16 | |
| 17 | 17 | #else |
| 18 | 18 | |
| 19 | −#include "../Inc/leaf-sample.h" | |
| 19 | +#include "../Inc/leaf-sampling.h" | |
| 20 | 20 | #include "../leaf.h" |
| 21 | 21 | |
| 22 | 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 | 22 | #include ".\Inc\leaf-global.h" |
| 23 | 23 | #include ".\Inc\leaf-math.h" |
| 24 | 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 | 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 | 30 | #include ".\Inc\leaf-reverb.h" |
| 31 | −#include ".\Inc\leaf-vocoder.h" | |
| 32 | −#include ".\Inc\leaf-808.h" | |
| 33 | −#include ".\Inc\leaf-string.h" | |
| 34 | −#include ".\Inc\leaf-pitch.h" | |
| 35 | −#include ".\Inc\leaf-formant.h" | |
| 31 | +#include ".\Inc\leaf-effects.h" | |
| 32 | +#include ".\Inc\leaf-envelopes.h" | |
| 33 | +#include ".\Inc\leaf-dynamics.h" | |
| 34 | +#include ".\Inc\leaf-analysis.h" | |
| 35 | +#include ".\Inc\leaf-instruments.h" | |
| 36 | 36 | #include ".\Inc\leaf-midi.h" |
| 37 | −#include ".\Inc\leaf-sample.h" | |
| 38 | −#include ".\Inc\leaf-crusher.h" | |
| 39 | −#include ".\Inc\leaf-wavefolder.h" | |
| 40 | −#include ".\Inc\leaf-tables.h" | |
| 37 | +#include ".\Inc\leaf-sampling.h" | |
| 38 | +#include ".\Inc\leaf-physical.h" | |
| 39 | +#include ".\Inc\leaf-electrical.h" | |
| 41 | 40 | |
| 42 | 41 | #else |
| 43 | 42 | |
| 44 | 43 | #include "./Inc/leaf-global.h" |
| 45 | 44 | #include "./Inc/leaf-math.h" |
| 46 | 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 | 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 | 51 | #include "./Inc/leaf-reverb.h" |
| 53 | −#include "./Inc/leaf-vocoder.h" | |
| 54 | −#include "./Inc/leaf-808.h" | |
| 55 | −#include "./Inc/leaf-string.h" | |
| 56 | −#include "./Inc/leaf-pitch.h" | |
| 57 | −#include "./Inc/leaf-formant.h" | |
| 52 | +#include "./Inc/leaf-effects.h" | |
| 53 | +#include "./Inc/leaf-envelopes.h" | |
| 54 | +#include "./Inc/leaf-dynamics.h" | |
| 55 | +#include "./Inc/leaf-analysis.h" | |
| 56 | +#include "./Inc/leaf-instruments.h" | |
| 58 | 57 | #include "./Inc/leaf-midi.h" |
| 59 | −#include "./Inc/leaf-sample.h" | |
| 60 | −#include "./Inc/leaf-crusher.h" | |
| 61 | −#include "./Inc/leaf-wavefolder.h" | |
| 62 | −#include "./Inc/leaf-tables.h" | |
| 63 | −#include "./Inc/leaf-WDF.h" | |
| 58 | +#include "./Inc/leaf-sampling.h" | |
| 59 | +#include "./Inc/leaf-physical.h" | |
| 60 | +#include "./Inc/leaf-electrical.h" | |
| 64 | 61 | |
| 65 | 62 | #endif |
| 66 | 63 | |
| @@ -26,53 +26,51 @@ · 25 unmodified lines | ||
| 26 | 26 | <FILE id="IwBoc4" name="leaf-global.h" compile="0" resource="0" file="../LEAF/Inc/leaf-global.h"/> |
| 27 | 27 | <FILE id="cmehFw" name="leaf-math.h" compile="0" resource="0" file="../LEAF/Inc/leaf-math.h"/> |
| 28 | 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 | 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 | 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"/> | |
| 41 | − <FILE id="OS2D83" name="leaf-utilities.h" compile="0" resource="0" | |
| 42 | − file="../LEAF/Inc/leaf-utilities.h"/> | |
| 43 | − <FILE id="Szb5LP" name="leaf-vocoder.h" compile="0" resource="0" file="../LEAF/Inc/leaf-vocoder.h"/> | |
| 44 | − <FILE id="T6KXi7" name="leaf-sample.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sample.h"/> | |
| 45 | − <FILE id="bpUZCA" name="leaf-crusher.h" compile="0" resource="0" file="../LEAF/Inc/leaf-crusher.h"/> | |
| 46 | − <FILE id="PRkOp2" name="leaf-wavefolder.h" compile="0" resource="0" | |
| 47 | − file="../LEAF/Inc/leaf-wavefolder.h"/> | |
| 48 | − <FILE id="lJdTFA" name="leaf-WDF.h" compile="0" resource="0" file="../LEAF/Inc/leaf-WDF.h"/> | |
| 49 | − <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/> | |
| 35 | + <FILE id="dWHebV" name="leaf-distortion.h" compile="0" resource="0" | |
| 36 | + file="../LEAF/Inc/leaf-distortion.h"/> | |
| 37 | + <FILE id="Szb5LP" name="leaf-effects.h" compile="0" resource="0" file="../LEAF/Inc/leaf-effects.h"/> | |
| 38 | + <FILE id="OS2D83" name="leaf-envelopes.h" compile="0" resource="0" | |
| 39 | + file="../LEAF/Inc/leaf-envelopes.h"/> | |
| 40 | + <FILE id="PRkOp2" name="leaf-dynamics.h" compile="0" resource="0" file="../LEAF/Inc/leaf-dynamics.h"/> | |
| 41 | + <FILE id="LPMRGU" name="leaf-analysis.h" compile="0" resource="0" file="../LEAF/Inc/leaf-analysis.h"/> | |
| 42 | + <FILE id="k0yQ8k" name="leaf-instruments.h" compile="0" resource="0" | |
| 43 | + file="../LEAF/Inc/leaf-instruments.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 | 49 | </GROUP> |
| 51 | 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"/> | |
| 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"/> | |
| 51 | + <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/> | |
| 56 | 52 | <FILE id="g41P2E" name="leaf-math.c" compile="1" resource="0" file="../LEAF/Src/leaf-math.c"/> |
| 57 | 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 | 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 | 74 | </GROUP> |
| 77 | 75 | <FILE id="dmljDQ" name="leaf.h" compile="0" resource="0" file="../LEAF/leaf.h"/> |
| 78 | 76 | </GROUP> |
| @@ -37,6 +37,8 @@ void LEAFTest_init (float sampleRate, int blockSize) · 36 unmodified lines | ||
| 37 | 37 | tCycle_init(&sine); |
| 38 | 38 | tCycle_setFreq(&sine, 200); |
| 39 | 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 | 44 | float LEAFTest_tick (float input) |
| @@ -98,7 +100,7 @@ void leaf_pool_report(void) · 55 unmodified lines | ||
| 98 | 100 | void leaf_pool_dump(void) |
| 99 | 101 | { |
| 100 | 102 | float* buff = (float*)leaf_pool_get_pool(); |
| 101 | − int siz = leaf_pool_get_size(); | |
| 103 | + unsigned long siz = leaf_pool_get_size(); | |
| 102 | 104 | siz /= sizeof(float); |
| 103 | 105 | for (int i = 0; i < siz; i++) |
| 104 | 106 | { |