Unified · Split
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -25,23 +25,23 @@ extern "C" { · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | typedef struct _tLockhartWavefolder |
| 27 | 27 | { |
| 28 | − float Ln1; | |
| 29 | − float Fn1; | |
| 28 | + double Ln1; | |
| 29 | + double Fn1; | |
| 30 | 30 | float xn1; |
| 31 | − | |
| 32 | − float RL; | |
| 33 | − float R; | |
| 34 | − float VT; | |
| 35 | − float Is; | |
| 36 | 31 | |
| 37 | − float a; | |
| 38 | − float b; | |
| 39 | − float d; | |
| 32 | + double RL; | |
| 33 | + double R; | |
| 34 | + double VT; | |
| 35 | + double Is; | |
| 36 | + | |
| 37 | + double a; | |
| 38 | + double b; | |
| 39 | + double d; | |
| 40 | 40 | |
| 41 | 41 | // Antialiasing error threshold |
| 42 | − float thresh; | |
| 43 | − float half_a; | |
| 44 | − float longthing; | |
| 42 | + double thresh; | |
| 43 | + double half_a; | |
| 44 | + double longthing; | |
| 45 | 45 | |
| 46 | 46 | } _tLockhartWavefolder; |
| 47 | 47 | |
| @@ -54,6 +54,27 @@ extern "C" { · 6 unmodified lines | ||
| 54 | 54 | |
| 55 | 55 | //============================================================================== |
| 56 | 56 | |
| 57 | + | |
| 58 | + | |
| 59 | + typedef struct _tSampleReducer | |
| 60 | + { | |
| 61 | + float invRatio; | |
| 62 | + float hold; | |
| 63 | + uint32_t count; | |
| 64 | + } _tSampleReducer; | |
| 65 | + | |
| 66 | + typedef _tSampleReducer* tSampleReducer; | |
| 67 | + | |
| 68 | + void tSampleReducer_init (tSampleReducer* const); | |
| 69 | + void tSampleReducer_free (tSampleReducer* const); | |
| 70 | + | |
| 71 | + float tSampleReducer_tick (tSampleReducer* const, float input); | |
| 72 | + | |
| 73 | + // sampling ratio | |
| 74 | + void tSampleReducer_setRatio (tSampleReducer* const, float ratio); | |
| 75 | + | |
| 76 | + //============================================================================== | |
| 77 | + | |
| 57 | 78 | typedef struct _tCrusher |
| 58 | 79 | { |
| 59 | 80 | float srr; |
| @@ -63,6 +84,7 @@ extern "C" { · 3 unmodified lines | ||
| 63 | 84 | uint32_t op; //which bitwise operation (0-7) |
| 64 | 85 | |
| 65 | 86 | float gain; |
| 87 | + tSampleReducer sReducer; | |
| 66 | 88 | |
| 67 | 89 | } _tCrusher; |
| 68 | 90 | |
| @@ -85,7 +107,9 @@ extern "C" { · 16 unmodified lines | ||
| 85 | 107 | // sampling ratio |
| 86 | 108 | void tCrusher_setSamplingRatio (tCrusher* const, float ratio); |
| 87 | 109 | |
| 110 | + | |
| 88 | 111 | //============================================================================== |
| 112 | + | |
| 89 | 113 | |
| 90 | 114 | typedef struct _tOversampler |
| 91 | 115 | { |
Binary file not shown.
| @@ -16,11 +16,17 @@ · 15 unmodified lines | ||
| 16 | 16 | #include "../Inc/leaf-distortion.h" |
| 17 | 17 | #include "../Inc/leaf-tables.h" |
| 18 | 18 | |
| 19 | + | |
| 19 | 20 | #endif |
| 20 | 21 | |
| 21 | 22 | //============================================================================================================ |
| 22 | 23 | // WAVEFOLDER |
| 23 | 24 | //============================================================================================================ |
| 25 | + | |
| 26 | + | |
| 27 | +//from the paper: Virtual Analog Model of the Lockhart Wavefolder | |
| 28 | +//by Fabián Esqueda, Henri Pöntynen, Julian D. Parker and Stefan Bilbao | |
| 29 | + | |
| 24 | 30 | void tLockhartWavefolder_init(tLockhartWavefolder* const wf) |
| 25 | 31 | { |
| 26 | 32 | _tLockhartWavefolder* w = *wf = (_tLockhartWavefolder*) leaf_alloc(sizeof(_tLockhartWavefolder)); |
| @@ -37,9 +43,10 @@ void tLockhartWavefolder_init(tLockhartWavefolder* const wf) · 10 unmodified lines | ||
| 37 | 43 | w->a = 2.0*w->RL/w->R; |
| 38 | 44 | w->b = (w->R+2.0*w->RL)/(w->VT*w->R); |
| 39 | 45 | w->d = (w->RL*w->Is)/w->VT; |
| 40 | − w->half_a = 0.5f * w->a; | |
| 46 | + w->half_a = 0.5 * w->a; | |
| 41 | 47 | w->longthing = (0.5*w->VT/w->b); |
| 42 | 48 | |
| 49 | + | |
| 43 | 50 | // Antialiasing error threshold |
| 44 | 51 | w->thresh = 10e-10; |
| 45 | 52 | } |
| @@ -55,28 +62,26 @@ double tLockhartWavefolderLambert(double x, double ln) · 9 unmodified lines | ||
| 55 | 62 | { |
| 56 | 63 | double thresh, w, expw, p, r, s, err; |
| 57 | 64 | // Error threshold |
| 58 | − thresh = 10e-6; | |
| 65 | + thresh = 10e-10; | |
| 59 | 66 | // Initial guess (use previous value) |
| 60 | 67 | w = ln; |
| 61 | 68 | |
| 62 | 69 | // Haley's method (Sec. 4.2 of the paper) |
| 63 | − for(int i=0; i<100; i+=1) { | |
| 70 | + for(int i=0; i<1000; i+=1) { | |
| 64 | 71 | |
| 65 | 72 | expw = exp(w); |
| 66 | 73 | |
| 67 | 74 | p = w*expw - x; |
| 68 | 75 | r = (w+1.0)*expw; |
| 69 | − s = (w+2.0)/(2.0*(w+1.0)); err = (p/(r-(p*s))); | |
| 76 | + s = (w+2.0)/(2.0*(w+1.0)); | |
| 77 | + err = (p/(r-(p*s))); | |
| 70 | 78 | |
| 71 | 79 | if (fabs(err)<thresh) { |
| 72 | − break; | |
| 73 | − } | |
| 74 | − if (isnan(err)) | |
| 75 | − { | |
| 76 | − break; | |
| 80 | + break; | |
| 77 | 81 | } |
| 78 | 82 | |
| 79 | 83 | w = w - err; |
| 84 | + | |
| 80 | 85 | } |
| 81 | 86 | return w; |
| 82 | 87 | } |
| @@ -86,11 +91,9 @@ float tLockhartWavefolder_tick(tLockhartWavefolder* const wf, float samp) · 3 unmodified lines | ||
| 86 | 91 | _tLockhartWavefolder* w = *wf; |
| 87 | 92 | |
| 88 | 93 | float out = 0.0f; |
| 89 | − // Constants | |
| 90 | − | |
| 91 | 94 | |
| 92 | 95 | // Compute Antiderivative |
| 93 | − int l = (samp > 0) - (samp < 0); | |
| 96 | + int l = (samp > 0.0f) - (samp < 0.0f); | |
| 94 | 97 | double u = w->d*exp(l*w->b*samp); |
| 95 | 98 | double Ln = tLockhartWavefolderLambert(u,w->Ln1); |
| 96 | 99 | double Fn = w->longthing*(Ln*(Ln + 2.0)) - w->half_a*samp*samp; |
| @@ -99,24 +102,16 @@ float tLockhartWavefolder_tick(tLockhartWavefolder* const wf, float samp) · 2 unmodified lines | ||
| 99 | 102 | if (fabs(samp-w->xn1)<w->thresh) { |
| 100 | 103 | |
| 101 | 104 | // Compute Averaged Wavefolder Output |
| 102 | − double xn = 0.5*(samp+w->xn1); | |
| 105 | + float xn = 0.5f*(samp+w->xn1); | |
| 103 | 106 | u = w->d*exp(l*w->b*xn); |
| 104 | 107 | Ln = tLockhartWavefolderLambert(u,w->Ln1); |
| 105 | 108 | out = (float) (l*w->VT*Ln - w->a*xn); |
| 106 | − if (isnan(out)) | |
| 107 | − { | |
| 108 | − ; | |
| 109 | − } | |
| 110 | 109 | |
| 111 | 110 | } |
| 112 | 111 | else { |
| 113 | 112 | |
| 114 | 113 | // Apply AA Form |
| 115 | 114 | out = (float) ((Fn-w->Fn1)/(samp-w->xn1)); |
| 116 | − if (isnan(out)) | |
| 117 | − { | |
| 118 | − ; | |
| 119 | − } | |
| 120 | 115 | } |
| 121 | 116 | |
| 122 | 117 | // Update States |
| @@ -140,14 +135,14 @@ void tCrusher_init (tCrusher* const cr) · 17 unmodified lines | ||
| 140 | 135 | c->div = SCALAR; |
| 141 | 136 | c->rnd = 0.25f; |
| 142 | 137 | c->srr = 0.25f; |
| 143 | − | |
| 138 | + tSampleReducer_init(&c->sReducer); | |
| 144 | 139 | c->gain = (c->div / SCALAR) * 0.7f + 0.3f; |
| 145 | 140 | } |
| 146 | 141 | |
| 147 | 142 | void tCrusher_free (tCrusher* const cr) |
| 148 | 143 | { |
| 149 | 144 | _tCrusher* c = *cr; |
| 150 | − | |
| 145 | + tSampleReducer_free(&c->sReducer); | |
| 151 | 146 | leaf_free(c); |
| 152 | 147 | } |
| 153 | 148 | |
| @@ -169,7 +164,7 @@ float tCrusher_tick (tCrusher* const cr, float input) · 15 unmodified lines | ||
| 169 | 164 | |
| 170 | 165 | sample = LEAF_round(sample, c->rnd); |
| 171 | 166 | |
| 172 | − sample = LEAF_reduct(sample, c->srr); | |
| 167 | + sample = tSampleReducer_tick(&c->sReducer, sample); | |
| 173 | 168 | |
| 174 | 169 | return sample * c->gain; |
| 175 | 170 | |
| @@ -204,8 +199,55 @@ void tCrusher_setSamplingRatio (tCrusher* const cr, float ratio) · 28 unmodified lines | ||
| 204 | 199 | { |
| 205 | 200 | _tCrusher* c = *cr; |
| 206 | 201 | c->srr = ratio; |
| 202 | + tSampleReducer_setRatio(&c->sReducer, ratio); | |
| 203 | + | |
| 207 | 204 | } |
| 208 | 205 | |
| 206 | +//============================================================================================================ | |
| 207 | +// Sample-Rate reducer | |
| 208 | +//============================================================================================================ | |
| 209 | + | |
| 210 | + | |
| 211 | +void tSampleReducer_init(tSampleReducer* const sr) | |
| 212 | +{ | |
| 213 | + _tSampleReducer* s = *sr = (_tSampleReducer*) leaf_alloc(sizeof(_tSampleReducer)); | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + s->invRatio = 1.0f; | |
| 218 | + s->hold = 0.0f; | |
| 219 | + s->count = 0; | |
| 220 | + | |
| 221 | +} | |
| 222 | + | |
| 223 | +void tSampleReducer_free (tSampleReducer* const sr) | |
| 224 | +{ | |
| 225 | + _tSampleReducer* s = *sr; | |
| 226 | + | |
| 227 | + leaf_free(s); | |
| 228 | +} | |
| 229 | + | |
| 230 | +float tSampleReducer_tick(tSampleReducer* const sr, float input) | |
| 231 | +{ | |
| 232 | + _tSampleReducer* s = *sr; | |
| 233 | + if (s->count > s->invRatio) | |
| 234 | + { | |
| 235 | + s->hold = input; | |
| 236 | + s->count = 0; | |
| 237 | + } | |
| 238 | + | |
| 239 | + s->count++; | |
| 240 | + return s->hold; | |
| 241 | +} | |
| 242 | + | |
| 243 | + | |
| 244 | +void tSampleReducer_setRatio(tSampleReducer* const sr, float ratio) | |
| 245 | +{ | |
| 246 | + _tSampleReducer* s = *sr; | |
| 247 | + if ((ratio <= 1.0f) && (ratio >= 0.0f)) | |
| 248 | + s->invRatio = 1.0f / ratio; | |
| 249 | + | |
| 250 | +} | |
| 209 | 251 | |
| 210 | 252 | //============================================================================================================ |
| 211 | 253 | // Oversampler |
| @@ -411,7 +453,7 @@ float tOversampler_downsample(tOversampler *const osr, float* input) · 199 unmodified lines | ||
| 411 | 453 | output = acc0; |
| 412 | 454 | |
| 413 | 455 | /* Processing is complete. |
| 414 | − Now copy the last numTaps - 1 samples to the satrt of the state buffer. | |
| 456 | + Now copy the last numTaps - 1 samples to the start of the state buffer. | |
| 415 | 457 | This prepares the state buffer for the next function call. */ |
| 416 | 458 | |
| 417 | 459 | /* Points to the start of the state buffer */ |
| @@ -165,23 +165,6 @@ float LEAF_shaper(float input, float m_drive) · 164 unmodified lines | ||
| 165 | 165 | return shaperOut; |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | −// reduce sample resolution | |
| 169 | −float hold = 0.f; | |
| 170 | −int reduct_count = 0; | |
| 171 | − | |
| 172 | − | |
| 173 | −float LEAF_reduct (float input, float ratio) | |
| 174 | −{ | |
| 175 | − reduct_count++; | |
| 176 | − if (reduct_count > 1.f / ratio) | |
| 177 | − { | |
| 178 | − hold = input; | |
| 179 | − reduct_count = 0; | |
| 180 | − } | |
| 181 | − | |
| 182 | − return hold; | |
| 183 | −} | |
| 184 | − | |
| 185 | 168 | // round input to nearest rnd |
| 186 | 169 | float LEAF_round (float input, float rnd) |
| 187 | 170 | { |
| @@ -270,12 +253,12 @@ oBool LEAF_isPrime(uint64_t number ) · 82 unmodified lines | ||
| 270 | 253 | float LEAF_tanh(float x) |
| 271 | 254 | { |
| 272 | 255 | |
| 273 | − if( x < -3 ) | |
| 274 | − return -1; | |
| 275 | − else if( x > 3 ) | |
| 276 | − return 1; | |
| 256 | + if( x < -3.0f ) | |
| 257 | + return -1.0f; | |
| 258 | + else if( x > 3.0f ) | |
| 259 | + return 1.0f; | |
| 277 | 260 | else |
| 278 | − return x * ( 27 + x * x ) / ( 27 + 9 * x * x ); | |
| 261 | + return x * ( 27.0f + x * x ) / ( 27.0f + 9.0f * x * x ); | |
| 279 | 262 | } |
| 280 | 263 | |
| 281 | 264 | |