Unified · Split
| @@ -75,6 +75,8 @@ void tDelayL_tapIn (tDelayL* const, float in, uint32_t tapDelay); · 74 unmodified lines | ||
| 75 | 75 | float tDelayL_tapOut (tDelayL* const, float tapDelay); |
| 76 | 76 | float tDelayL_addTo (tDelayL* const, float value, uint32_t tapDelay); |
| 77 | 77 | float tDelayL_tick (tDelayL* const, float sample); |
| 78 | +void tDelayL_tickIn (tDelayL* const d, float input); | |
| 79 | +float tDelayL_tickOut (tDelayL* const d); | |
| 78 | 80 | float tDelayL_getLastOut (tDelayL* const); |
| 79 | 81 | float tDelayL_getLastIn (tDelayL* const); |
| 80 | 82 | |
| @@ -49,15 +49,14 @@ extern const float shaper1[SHAPER1_TABLE_SIZE]; · 48 unmodified lines | ||
| 49 | 49 | #define MPOLY_NUM_MAX_VOICES 8 |
| 50 | 50 | #define NUM_OSC 4 |
| 51 | 51 | #define INV_NUM_OSC (1.0f / NUM_OSC) |
| 52 | −#define PS_FRAME_SIZE 1024 // SNAC_FRAME_SIZE in LEAFCore.h should match (or be smaller than?) this | |
| 52 | +#define PS_FRAME_SIZE 1024 // SNAC_FRAME_SIZE in leaf-pitch.h should match (or be smaller than?) this | |
| 53 | 53 | #define ENV_WINDOW_SIZE 1024 |
| 54 | 54 | #define ENV_HOP_SIZE 256 |
| 55 | −#define NUM_KNOBS 4 | |
| 56 | 55 | |
| 57 | 56 | #define DELAY_LENGTH 16000 // The maximum delay length of all Delay/DelayL/DelayA components. |
| 58 | 57 | // Feel free to change to suit memory constraints or desired delay max length / functionality. |
| 59 | 58 | |
| 60 | −#define TALKBOX_BUFFER_LENGTH 1600 // Every talkbox instance introduces 5 buffers of this size | |
| 59 | + | |
| 61 | 60 | |
| 62 | 61 | |
| 63 | 62 | union unholy_t { /* a union between a float and an integer */ |
| @@ -50,7 +50,9 @@ extern "C" { · 49 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | //============================================================================== |
| 52 | 52 | |
| 53 | + | |
| 53 | 54 | #define MPOOL_POOL_SIZE 500000 |
| 55 | + | |
| 54 | 56 | #define MPOOL_ALIGN_SIZE (8) |
| 55 | 57 | |
| 56 | 58 | //#define size_t unsigned long |
| @@ -0,0 +1,55 @@ | ||
| 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-globals.h" | |
| 20 | +#include "leaf-math.h" | |
| 21 | +#include "leaf-filter.h" | |
| 22 | + | |
| 23 | +//============================================================================== | |
| 24 | +typedef struct _tOversamplerFilter | |
| 25 | +{ | |
| 26 | + float cutoff, Q; | |
| 27 | + float ic1eq,ic2eq; | |
| 28 | + float g,k,a1,a2,a3; | |
| 29 | +} tOversamplerFilter; | |
| 30 | + | |
| 31 | +typedef struct _tOversampler2x | |
| 32 | +{ | |
| 33 | + tOversamplerFilter filters[2]; | |
| 34 | +} tOversampler2x; | |
| 35 | + | |
| 36 | +void tOversampler2x_init(tOversampler2x* const); | |
| 37 | +float tOversampler2x_tick(tOversampler2x* const, float input, float (*nonLinearTick)(float)); | |
| 38 | + | |
| 39 | +typedef struct _tOversampler4x | |
| 40 | +{ | |
| 41 | + tOversamplerFilter filters[4]; | |
| 42 | +} tOversampler4x; | |
| 43 | + | |
| 44 | +void tOversampler4x_init(tOversampler4x* const); | |
| 45 | +float tOversampler4x_tick(tOversampler4x* const, float input, float (*nonLinearTick)(float)); | |
| 46 | + | |
| 47 | +//============================================================================== | |
| 48 | + | |
| 49 | +#ifdef __cplusplus | |
| 50 | +} | |
| 51 | +#endif | |
| 52 | + | |
| 53 | +#endif // LEAF_OVERSAMPLER_H_INCLUDED | |
| 54 | + | |
| 55 | +//============================================================================== | |
| @@ -1,24 +1,28 @@ | ||
| 1 | −/*============================================================================== | |
| 1 | +/* | |
| 2 | + ============================================================================== | |
| 2 | 3 | |
| 3 | − leaf-utilities.h | |
| 4 | + LEAFUtilities.h | |
| 4 | 5 | Created: 20 Jan 2017 12:02:17pm |
| 5 | 6 | Author: Michael R Mulshine |
| 6 | 7 | |
| 7 | −==============================================================================*/ | |
| 8 | + ============================================================================== | |
| 9 | +*/ | |
| 8 | 10 | |
| 9 | −#ifndef LEAF_UTILITIES_H_INCLUDED | |
| 10 | −#define LEAF_UTILITIES_H_INCLUDED | |
| 11 | − | |
| 12 | −#ifdef __cplusplus | |
| 13 | −extern "C" { | |
| 11 | +#ifndef LEAFUTILITIES_H_INCLUDED | |
| 12 | +#define LEAFUTILITIES_H_INCLUDED | |
| 13 | + | |
| 14 | +#ifdef __cplusplus | |
| 15 | +extern "C" { | |
| 14 | 16 | #endif |
| 15 | 17 | |
| 16 | −//============================================================================== | |
| 18 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 17 | 19 | |
| 18 | 20 | #include "leaf-globals.h" |
| 19 | 21 | #include "leaf-math.h" |
| 22 | +#include "leaf-filter.h" | |
| 23 | +#include "leaf-delay.h" | |
| 20 | 24 | |
| 21 | −//============================================================================== | |
| 25 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 22 | 26 | |
| 23 | 27 | // STACK implementation (fixed size) |
| 24 | 28 | #define STACK_SIZE 128 |
| @@ -46,7 +50,7 @@ int tStack_contains (tStack* const, uint16_t item); · 21 unmodified lines | ||
| 46 | 50 | int tStack_next (tStack* const); |
| 47 | 51 | int tStack_get (tStack* const, int which); |
| 48 | 52 | |
| 49 | −//============================================================================== | |
| 53 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 50 | 54 | |
| 51 | 55 | /* Ramp */ |
| 52 | 56 | typedef struct _tRamp { |
| @@ -68,7 +72,148 @@ int tRamp_setTime (tRamp* const, float time); · 15 unmodified lines | ||
| 68 | 72 | int tRamp_setDest (tRamp* const, float dest); |
| 69 | 73 | int tRamp_setVal (tRamp* const, float val); |
| 70 | 74 | |
| 71 | −//============================================================================== | |
| 75 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 76 | + | |
| 77 | +/* Exponential Smoother */ | |
| 78 | +typedef struct _tExpSmooth { | |
| 79 | + float factor, oneminusfactor; | |
| 80 | + float curr,dest; | |
| 81 | + | |
| 82 | +} tExpSmooth; | |
| 83 | + | |
| 84 | +void tExpSmooth_init (tExpSmooth* const, float val, float factor); | |
| 85 | +void tExpSmooth_free (tExpSmooth* const); | |
| 86 | + | |
| 87 | +float tExpSmooth_tick (tExpSmooth* const); | |
| 88 | +float tExpSmooth_sample (tExpSmooth* const); | |
| 89 | +int tExpSmooth_setFactor (tExpSmooth* const, float factor); | |
| 90 | +int tExpSmooth_setDest (tExpSmooth* const, float dest); | |
| 91 | +int tExpSmooth_setVal (tExpSmooth* const, float val); | |
| 92 | + | |
| 93 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 94 | + | |
| 95 | +/* PowerEnvelopeFollower */ | |
| 96 | +typedef struct _tPwrFollow { | |
| 97 | + float factor, oneminusfactor; | |
| 98 | + float curr; | |
| 99 | + | |
| 100 | +} tPwrFollow; | |
| 101 | + | |
| 102 | +void tPwrFollow_init (tPwrFollow* const, float factor); | |
| 103 | +void tPwrFollow_free (tPwrFollow* const); | |
| 104 | +float tPwrFollow_tick (tPwrFollow* const, float input); | |
| 105 | +float tPwrFollow_sample (tPwrFollow* const); | |
| 106 | +int tPwrFollow_setFactor (tPwrFollow* const, float factor); | |
| 107 | + | |
| 108 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 109 | + | |
| 110 | +//Reed Table - borrowed from STK | |
| 111 | +typedef struct _tReedTable { | |
| 112 | + float offset, slope; | |
| 113 | +} tReedTable; | |
| 114 | + | |
| 115 | +void tReedTable_init (tReedTable* const, float offset, float slope); | |
| 116 | +void tReedTable_free (tReedTable* const); | |
| 117 | +float tReedTable_tick (tReedTable* const, float input); | |
| 118 | +float tReedTable_tanh_tick (tReedTable* const p, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code | |
| 119 | +void tReedTable_setOffset (tReedTable* const, float offset); | |
| 120 | +void tReedTable_setSlope (tReedTable* const, float slope); | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | +/// | |
| 125 | +/* Feedback leveller */ | |
| 126 | +// An auto VCA that you put into a feedback circuit to make it stay at the same level. | |
| 127 | +// It can enforce level bidirectionally (amplifying and attenuating as needed) or | |
| 128 | +// just attenutating. The former option allows for infinite sustain strings, for example, while | |
| 129 | +// The latter option allows for decaying strings, which can never exceed | |
| 130 | +// a specific level. | |
| 131 | + | |
| 132 | +typedef struct _tFBleveller { | |
| 133 | + float targetLevel; // target power level | |
| 134 | + float strength; // how strongly level difference affects the VCA | |
| 135 | + int mode; // 0 for upwards limiting only, 1 for biderctional limiting | |
| 136 | + float curr; | |
| 137 | + tPwrFollow pwrFlw; // internal power follower needed for level tracking | |
| 138 | + | |
| 139 | +} tFBleveller; | |
| 140 | + | |
| 141 | +void tFBleveller_init (tFBleveller* const, float targetLevel, float factor, float strength, int mode); | |
| 142 | +void tFBleveller_free (tFBleveller* const); | |
| 143 | + | |
| 144 | +float tFBleveller_tick (tFBleveller* const, float input); | |
| 145 | +float tFBleveller_sample (tFBleveller* const); | |
| 146 | +int tFBleveller_setTargetLevel (tFBleveller* const, float TargetLevel); | |
| 147 | +int tFBleveller_setFactor (tFBleveller* const, float factor); | |
| 148 | +int tFBleveller_setMode (tFBleveller* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting | |
| 149 | +int tFBleveller_setStrength (tFBleveller* const, float strength); | |
| 150 | + | |
| 151 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 152 | + | |
| 153 | +/* Simple Living String */ | |
| 154 | +typedef struct _tSimpleLivingString { | |
| 155 | + float freq, waveLengthInSamples; // the frequency of the string, determining delay length | |
| 156 | + float dampFreq; // frequency for the bridge LP filter, in Hz | |
| 157 | + float decay; // amplitude damping factor for the string (only active in mode 0) | |
| 158 | + float levMode; | |
| 159 | + float curr; | |
| 160 | + tDelayL delayLine; | |
| 161 | + tOnePole bridgeFilter; | |
| 162 | + tHighpass DCblocker; | |
| 163 | + tFBleveller fbLev; | |
| 164 | + tExpSmooth wlSmooth; | |
| 165 | +} tSimpleLivingString; | |
| 166 | + | |
| 167 | +void tSimpleLivingString_init (tSimpleLivingString* const, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode); | |
| 168 | +void tSimpleLivingString_free (tSimpleLivingString* const); | |
| 169 | +float tSimpleLivingString_tick (tSimpleLivingString* const, float input); | |
| 170 | +float tSimpleLivingString_sample (tSimpleLivingString* const); | |
| 171 | +int tSimpleLivingString_setFreq (tSimpleLivingString* const, float freq); | |
| 172 | +int tSimpleLivingString_setWaveLength (tSimpleLivingString* const, float waveLength); // in samples | |
| 173 | +int tSimpleLivingString_setDampFreq (tSimpleLivingString* const, float dampFreq); | |
| 174 | +int tSimpleLivingString_setDecay (tSimpleLivingString* const, float decay); // should be near 1.0 | |
| 175 | +int tSimpleLivingString_setTargetLev (tSimpleLivingString* const, float targetLev); | |
| 176 | +int tSimpleLivingString_setLevSmoothFactor (tSimpleLivingString* const, float levSmoothFactor); | |
| 177 | +int tSimpleLivingString_setLevStrength (tSimpleLivingString* const, float levStrength); | |
| 178 | +int tSimpleLivingString_setLevMode (tSimpleLivingString* const, int levMode); | |
| 179 | + | |
| 180 | + | |
| 181 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 182 | + | |
| 183 | +/* Living String */ | |
| 184 | +typedef struct _tLivingString { | |
| 185 | + float freq, waveLengthInSamples; // the frequency of the whole string, determining delay length | |
| 186 | + float pickPos; // the pick position, dividing the string in two, in ratio | |
| 187 | + float prepIndex; // the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj) | |
| 188 | + float dampFreq; // frequency for the bridge LP filter, in Hz | |
| 189 | + float decay; // amplitude damping factor for the string (only active in mode 0) | |
| 190 | + float levMode; | |
| 191 | + float curr; | |
| 192 | + tDelayL delLF,delUF,delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model | |
| 193 | + tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL; | |
| 194 | + tHighpass DCblockerL, DCblockerU; | |
| 195 | + tFBleveller fbLevU, fbLevL; | |
| 196 | + tExpSmooth wlSmooth, ppSmooth; | |
| 197 | +} tLivingString; | |
| 198 | + | |
| 199 | +void tLivingString_init (tLivingString* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay, | |
| 200 | + float targetLev, float levSmoothFactor, float levStrength, int levMode); | |
| 201 | +void tLivingString_free (tLivingString* const); | |
| 202 | +float tLivingString_tick (tLivingString* const, float input); | |
| 203 | +float tLivingString_sample (tLivingString* const); | |
| 204 | +int tLivingString_setFreq (tLivingString* const, float freq); | |
| 205 | +int tLivingString_setWaveLength (tLivingString* const, float waveLength); // in samples | |
| 206 | +int tLivingString_setPickPos (tLivingString* const, float pickPos); | |
| 207 | +int tLivingString_setPrepIndex (tLivingString* const, float prepIndex); | |
| 208 | +int tLivingString_setDampFreq (tLivingString* const, float dampFreq); | |
| 209 | +int tLivingString_setDecay (tLivingString* const, float decay); // should be near 1.0 | |
| 210 | +int tLivingString_setTargetLev (tLivingString* const, float targetLev); | |
| 211 | +int tLivingString_setLevSmoothFactor (tLivingString* const, float levSmoothFactor); | |
| 212 | +int tLivingString_setLevStrength (tLivingString* const, float levStrength); | |
| 213 | +int tLivingString_setLevMode (tLivingString* const, int levMode); | |
| 214 | + | |
| 215 | + | |
| 216 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 72 | 217 | |
| 73 | 218 | /* Compressor */ |
| 74 | 219 | typedef struct _tCompressor |
| @@ -86,7 +231,7 @@ void tCompressor_init (tCompressor* const); · 11 unmodified lines | ||
| 86 | 231 | void tCompressor_free (tCompressor* const); |
| 87 | 232 | float tCompressor_tick (tCompressor* const, float input); |
| 88 | 233 | |
| 89 | −//============================================================================== | |
| 234 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 90 | 235 | |
| 91 | 236 | /* Attack-Decay envelope */ |
| 92 | 237 | typedef struct _tEnvelope { |
| @@ -118,7 +263,7 @@ int tEnvelope_setDecay (tEnvelope* const, float decay); · 25 unmodified lines | ||
| 118 | 263 | int tEnvelope_loop (tEnvelope* const, oBool loop); |
| 119 | 264 | int tEnvelope_on (tEnvelope* const, float velocity); |
| 120 | 265 | |
| 121 | −//============================================================================== | |
| 266 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 122 | 267 | |
| 123 | 268 | /* ADSR */ |
| 124 | 269 | typedef struct _tADSR |
| @@ -150,7 +295,7 @@ int tADSR_setRelease(tADSR* const, float release); · 25 unmodified lines | ||
| 150 | 295 | int tADSR_on (tADSR* const, float velocity); |
| 151 | 296 | int tADSR_off (tADSR* const); |
| 152 | 297 | |
| 153 | −//============================================================================== | |
| 298 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 154 | 299 | |
| 155 | 300 | /* Envelope Follower */ |
| 156 | 301 | typedef struct _tEnvelopeFollower |
| @@ -168,7 +313,7 @@ float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x); · 11 unmodified lines | ||
| 168 | 313 | int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff); |
| 169 | 314 | int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh); |
| 170 | 315 | |
| 171 | −//============================================================================== | |
| 316 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 172 | 317 | |
| 173 | 318 | /* tAtkDtk */ |
| 174 | 319 | #define DEFBLOCKSIZE 1024 |
| @@ -219,7 +364,7 @@ void tAtkDtk_setThreshold (tAtkDtk* const, float thres); · 44 unmodified lines | ||
| 219 | 364 | // find largest transient in input block, return index of attack |
| 220 | 365 | int tAtkDtk_detect (tAtkDtk* const, float *in); |
| 221 | 366 | |
| 222 | −//============================================================================== | |
| 367 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 223 | 368 | |
| 224 | 369 | // ENV~ from PD, modified for LEAF |
| 225 | 370 | #define MAXOVERLAP 32 |
| @@ -244,14 +389,12 @@ void tEnv_free (tEnv* const); · 18 unmodified lines | ||
| 244 | 389 | float tEnv_tick (tEnv* const); |
| 245 | 390 | void tEnv_processBlock (tEnv* const, float* in); |
| 246 | 391 | |
| 247 | −//============================================================================== | |
| 248 | − | |
| 249 | −#ifdef __cplusplus | |
| 250 | −} | |
| 392 | +// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ | |
| 393 | + | |
| 394 | +#ifdef __cplusplus | |
| 395 | +} | |
| 251 | 396 | #endif |
| 252 | 397 | |
| 253 | −#endif // LEAF_UTILITIES_H_INCLUDED | |
| 254 | − | |
| 255 | −//============================================================================== | |
| 398 | +#endif // LEAFUTILITIES_H_INCLUDED | |
| 256 | 399 | |
| 257 | 400 | |
| @@ -22,7 +22,7 @@ extern "C" { · 21 unmodified lines | ||
| 22 | 22 | |
| 23 | 23 | /* tTalkbox */ |
| 24 | 24 | #define NUM_TALKBOX_PARAM 4 |
| 25 | −#define TALKBOX_BUFFER_LENGTH 1024 //1600 | |
| 25 | +#define TALKBOX_BUFFER_LENGTH 1024 // Every talkbox instance introduces 5 buffers of this size - was originally 1600 | |
| 26 | 26 | |
| 27 | 27 | typedef struct _tTalkbox |
| 28 | 28 | { |
| @@ -178,6 +178,30 @@ float tDelayL_tick (tDelayL* const d, float input) · 177 unmodified lines | ||
| 178 | 178 | return d->lastOut; |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | +void tDelayL_tickIn (tDelayL* const d, float input) | |
| 182 | +{ | |
| 183 | + d->buff[d->inPoint] = input * d->gain; | |
| 184 | + | |
| 185 | + // Increment input pointer modulo length. | |
| 186 | + if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0; | |
| 187 | +} | |
| 188 | + | |
| 189 | +float tDelayL_tickOut (tDelayL* const d) | |
| 190 | +{ | |
| 191 | + uint32_t idx = (uint32_t) d->outPoint; | |
| 192 | + | |
| 193 | + d->lastOut = LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay], | |
| 194 | + d->buff[idx], | |
| 195 | + d->buff[(idx + 1) % d->maxDelay], | |
| 196 | + d->buff[(idx + 2) % d->maxDelay], | |
| 197 | + d->alpha); | |
| 198 | + | |
| 199 | + // Increment output pointer modulo length | |
| 200 | + if ( (++d->outPoint) >= d->maxDelay ) d->outPoint = 0; | |
| 201 | + | |
| 202 | + return d->lastOut; | |
| 203 | +} | |
| 204 | + | |
| 181 | 205 | int tDelayL_setDelay (tDelayL* const d, float delay) |
| 182 | 206 | { |
| 183 | 207 | d->delay = LEAF_clip(0.0f, delay, d->maxDelay); |
| @@ -0,0 +1,124 @@ | ||
| 1 | +// | |
| 2 | +// leaf-oversampler.c | |
| 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 | +#if _WIN32 || _WIN64 | |
| 10 | + | |
| 11 | +#include "..\Inc\leaf-oversampler.h" | |
| 12 | +#else | |
| 13 | + | |
| 14 | +#include "../Inc/leaf-oversampler.h" | |
| 15 | + | |
| 16 | +#endif | |
| 17 | + | |
| 18 | +// Currently just using a double sample rate version of SVF from leaf-filter.c, may want to implement better filter for oversampling. | |
| 19 | +// Quick testing seems to indicate that this filter sufficiently handles most aliasing. | |
| 20 | +void tOversamplerFilter_init(tOversamplerFilter* const lpf, float freq, float Q, float sampleRateMultiplier) | |
| 21 | +{ | |
| 22 | + lpf->ic1eq = 0; | |
| 23 | + lpf->ic2eq = 0; | |
| 24 | + | |
| 25 | + float a1,a2,a3,g,k; | |
| 26 | + float scaledInverseSampleRate = leaf.invSampleRate * (1 / sampleRateMultiplier); | |
| 27 | + | |
| 28 | + g = tanf(PI * freq * scaledInverseSampleRate); | |
| 29 | + k = 1.0f/Q; | |
| 30 | + a1 = 1.0f/(1.0f+g*(g+k)); | |
| 31 | + a2 = g*a1; | |
| 32 | + a3 = g*a2; | |
| 33 | + | |
| 34 | + lpf->g = g; | |
| 35 | + lpf->k = k; | |
| 36 | + lpf->a1 = a1; | |
| 37 | + lpf->a2 = a2; | |
| 38 | + lpf->a3 = a3; | |
| 39 | +} | |
| 40 | + | |
| 41 | +float tOversamplerFilter_tick(tOversamplerFilter* const lpf, float v0) | |
| 42 | +{ | |
| 43 | + float v1,v2,v3; | |
| 44 | + v3 = v0 - lpf->ic2eq; | |
| 45 | + v1 = (lpf->a1 * lpf->ic1eq) + (lpf->a2 * v3); | |
| 46 | + v2 = lpf->ic2eq + (lpf->a2 * lpf->ic1eq) + (lpf->a3 * v3); | |
| 47 | + lpf->ic1eq = (2.0f * v1) - lpf->ic1eq; | |
| 48 | + lpf->ic2eq = (2.0f * v2) - lpf->ic2eq; | |
| 49 | + | |
| 50 | + return v2; | |
| 51 | +} | |
| 52 | + | |
| 53 | +// 2X Oversampler | |
| 54 | +void tOversampler2x_init(tOversampler2x* const os) | |
| 55 | +{ | |
| 56 | + tOversamplerFilter_init(&os->filters[0], leaf.sampleRate*0.5f, 0.1f, 2.f); | |
| 57 | + tOversamplerFilter_init(&os->filters[1], leaf.sampleRate*0.5f, 0.1f, 2.f); | |
| 58 | +} | |
| 59 | + | |
| 60 | +float tOversampler2x_tick(tOversampler2x* const os, float input, float (*nonLinearTick)(float)) | |
| 61 | +{ | |
| 62 | + float sample = input; | |
| 63 | + float oversample = 0.f; | |
| 64 | + | |
| 65 | + sample = tOversamplerFilter_tick(&os->filters[0], sample); | |
| 66 | + oversample = tOversamplerFilter_tick(&os->filters[0], oversample); | |
| 67 | + | |
| 68 | + sample = nonLinearTick(sample); | |
| 69 | + oversample = nonLinearTick(oversample); | |
| 70 | + | |
| 71 | + sample = tOversamplerFilter_tick(&os->filters[1], sample); | |
| 72 | + oversample = tOversamplerFilter_tick(&os->filters[1], oversample); | |
| 73 | + | |
| 74 | + return sample; | |
| 75 | +} | |
| 76 | + | |
| 77 | +// 4X Oversampler | |
| 78 | +void tOversampler4x_init(tOversampler4x* const os) | |
| 79 | +{ | |
| 80 | + tOversamplerFilter_init(&os->filters[0], leaf.sampleRate*0.25f, 0.1f, 2.f); //sample rate was *0.5 but I assume that was copypaste mistake (copied from 2X filter) - JS | |
| 81 | + tOversamplerFilter_init(&os->filters[1], leaf.sampleRate*0.25f, 0.1f, 4.f); | |
| 82 | + tOversamplerFilter_init(&os->filters[2], leaf.sampleRate*0.25f, 0.1f, 4.f); | |
| 83 | + tOversamplerFilter_init(&os->filters[3] , leaf.sampleRate*0.25f, 0.1f, 2.f); | |
| 84 | +} | |
| 85 | + | |
| 86 | +float tOversampler4x_tick(tOversampler4x* const os, float input, float (*nonLinearTick)(float)) | |
| 87 | +{ | |
| 88 | + float sample = input; | |
| 89 | + float oversample1 = 0.f; | |
| 90 | + float oversample2 = 0.f; | |
| 91 | + float oversample3 = 0.f; | |
| 92 | + // Phase 1: | |
| 93 | + // x = [sample, oversample2] | |
| 94 | + // lpf(x) | |
| 95 | + // Phase 2: | |
| 96 | + // x = [sample, oversample1, oversample2, oversample3] | |
| 97 | + // lpf(dist(lpf(x))) | |
| 98 | + // Phase 3: | |
| 99 | + // x = [sample, oversample2] | |
| 100 | + // lpf(x) | |
| 101 | + | |
| 102 | + sample = tOversamplerFilter_tick(&os->filters[0], sample); | |
| 103 | + oversample2 = tOversamplerFilter_tick(&os->filters[0], oversample2); | |
| 104 | + | |
| 105 | + sample = tOversamplerFilter_tick(&os->filters[1], sample); | |
| 106 | + oversample1 = tOversamplerFilter_tick(&os->filters[1], oversample1); | |
| 107 | + oversample2 = tOversamplerFilter_tick(&os->filters[1], oversample2); | |
| 108 | + oversample3 = tOversamplerFilter_tick(&os->filters[1], oversample3); | |
| 109 | + | |
| 110 | + sample = nonLinearTick(sample); | |
| 111 | + oversample1 = nonLinearTick(oversample1); | |
| 112 | + oversample2 = nonLinearTick(oversample2); | |
| 113 | + oversample3 = nonLinearTick(oversample3); | |
| 114 | + | |
| 115 | + sample = tOversamplerFilter_tick(&os->filters[2], sample); | |
| 116 | + oversample1 = tOversamplerFilter_tick(&os->filters[2], oversample1); | |
| 117 | + oversample2 = tOversamplerFilter_tick(&os->filters[2], oversample2); | |
| 118 | + oversample3 = tOversamplerFilter_tick(&os->filters[2], oversample3); | |
| 119 | + | |
| 120 | + sample = tOversamplerFilter_tick(&os->filters[3], sample); | |
| 121 | + oversample2 = tOversamplerFilter_tick(&os->filters[3], oversample2); | |
| 122 | + | |
| 123 | + return sample; | |
| 124 | +} | |
| @@ -1,10 +1,12 @@ | ||
| 1 | −/*============================================================================== | |
| 1 | +/* | |
| 2 | + ============================================================================== | |
| 2 | 3 | |
| 3 | − leaf-utilities.c | |
| 4 | + LEAFUtilities.c | |
| 4 | 5 | Created: 20 Jan 2017 12:02:17pm |
| 5 | 6 | Author: Michael R Mulshine |
| 6 | 7 | |
| 7 | −==============================================================================*/ | |
| 8 | + ============================================================================== | |
| 9 | +*/ | |
| 8 | 10 | |
| 9 | 11 | |
| 10 | 12 | #if _WIN32 || _WIN64 |
| @@ -29,12 +31,12 @@ float mtof(float f) · 18 unmodified lines | ||
| 29 | 31 | { |
| 30 | 32 | if (f <= -1500.0f) return(0); |
| 31 | 33 | else if (f > 1499.0f) return(mtof(1499.0f)); |
| 32 | − else return (8.17579891564f * exp(0.0577622650f * f)); | |
| 34 | + else return (8.17579891564f * expf(0.0577622650f * f)); | |
| 33 | 35 | } |
| 34 | 36 | |
| 35 | 37 | float ftom(float f) |
| 36 | 38 | { |
| 37 | − return (f > 0 ? 17.3123405046f * log(.12231220585f * f) : -1500.0f); | |
| 39 | + return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f); | |
| 38 | 40 | } |
| 39 | 41 | |
| 40 | 42 | float powtodb(float f) |
| @@ -42,7 +44,7 @@ float powtodb(float f) · 1 unmodified line | ||
| 42 | 44 | if (f <= 0) return (0); |
| 43 | 45 | else |
| 44 | 46 | { |
| 45 | − float val = 100 + 10.f/LOGTEN * log(f); | |
| 47 | + float val = 100 + 10.f/LOGTEN * logf(f); | |
| 46 | 48 | return (val < 0 ? 0 : val); |
| 47 | 49 | } |
| 48 | 50 | } |
| @@ -65,7 +67,7 @@ float dbtopow(float f) · 16 unmodified lines | ||
| 65 | 67 | { |
| 66 | 68 | if (f > 870.0f) |
| 67 | 69 | f = 870.0f; |
| 68 | − return (exp((LOGTEN * 0.1f) * (f-100.0f))); | |
| 70 | + return (expf((LOGTEN * 0.1f) * (f-100.0f))); | |
| 69 | 71 | } |
| 70 | 72 | } |
| 71 | 73 | |
| @@ -78,7 +80,7 @@ float dbtorms(float f) · 6 unmodified lines | ||
| 78 | 80 | if (f > 485.0f) |
| 79 | 81 | f = 485.0f; |
| 80 | 82 | } |
| 81 | − return (exp((LOGTEN * 0.05f) * (f-100.0f))); | |
| 83 | + return (expf((LOGTEN * 0.05f) * (f-100.0f))); | |
| 82 | 84 | } |
| 83 | 85 | |
| 84 | 86 | /* ---------------- env~ - simple envelope follower. ----------------- */ |
| @@ -103,7 +105,7 @@ void tEnv_init(tEnv* const x, int ws, int hs, int bs) · 18 unmodified lines | ||
| 103 | 105 | |
| 104 | 106 | for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0; |
| 105 | 107 | for (i = 0; i < npoints; i++) |
| 106 | − x->buf[i] = (1.0f - cos((2 * PI * i) / npoints))/npoints; | |
| 108 | + x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints; | |
| 107 | 109 | for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0; |
| 108 | 110 | |
| 109 | 111 | x->x_f = 0; |
| @@ -761,6 +763,8 @@ float tRamp_tick(tRamp* const r) { · 651 unmodified lines | ||
| 761 | 763 | r->curr += r->inc; |
| 762 | 764 | |
| 763 | 765 | if (((r->curr >= r->dest) && (r->inc > 0.0f)) || ((r->curr <= r->dest) && (r->inc < 0.0f))) r->inc = 0.0f; |
| 766 | + // 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 | |
| 767 | + // I suggest you add: r->curr=r->dest in the true if case | |
| 764 | 768 | |
| 765 | 769 | return r->curr; |
| 766 | 770 | } |
| @@ -775,6 +779,417 @@ void tRampSampleRateChanged(tRamp* const r) · 8 unmodified lines | ||
| 775 | 779 | r->inv_sr_ms = 1.0f / (leaf.sampleRate * 0.001f); |
| 776 | 780 | r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms)*((float)r->samples_per_tick); |
| 777 | 781 | } |
| 782 | + | |
| 783 | + | |
| 784 | +/* Exponential Smoother */ | |
| 785 | +void tExpSmooth_init(tExpSmooth* const smooth, float val, float factor) | |
| 786 | +{ // 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 | |
| 787 | + smooth->curr=val; | |
| 788 | + smooth->dest=val; | |
| 789 | + if (factor<0) factor=0; | |
| 790 | + if (factor>1) factor=1; | |
| 791 | + smooth->factor=factor; | |
| 792 | + smooth->oneminusfactor=1.0f-factor; | |
| 793 | +} | |
| 794 | + | |
| 795 | +int tExpSmooth_setFactor(tExpSmooth* const smooth, float factor) | |
| 796 | +{ // 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 | |
| 797 | + if (factor<0) | |
| 798 | + factor=0; | |
| 799 | + else | |
| 800 | + if (factor>1) factor=1; | |
| 801 | + smooth->factor=factor; | |
| 802 | + smooth->oneminusfactor=1.0f-factor; | |
| 803 | + return 0; | |
| 804 | +} | |
| 805 | + | |
| 806 | +int tExpSmooth_setDest(tExpSmooth* const smooth, float dest) | |
| 807 | +{ | |
| 808 | + smooth->dest=dest; | |
| 809 | + return 0; | |
| 810 | +} | |
| 811 | + | |
| 812 | +int tExpSmooth_setVal(tExpSmooth* const smooth, float val) | |
| 813 | +{ | |
| 814 | + smooth->curr=val; | |
| 815 | + return 0; | |
| 816 | +} | |
| 817 | + | |
| 818 | +float tExpSmooth_tick(tExpSmooth* const smooth) | |
| 819 | +{ | |
| 820 | + smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr; | |
| 821 | + return smooth->curr; | |
| 822 | +} | |
| 823 | + | |
| 824 | +float tExpSmooth_sample(tExpSmooth* const smooth) | |
| 825 | +{ | |
| 826 | + return smooth->curr; | |
| 827 | +} | |
| 828 | + | |
| 829 | + | |
| 830 | +/* Power Follower */ | |
| 831 | + | |
| 832 | +void tPwrFollow_init(tPwrFollow* const p, float factor) | |
| 833 | +{ | |
| 834 | + p->curr=0.0f; | |
| 835 | + p->factor=factor; | |
| 836 | + p->oneminusfactor=1.0f-factor; | |
| 837 | +} | |
| 838 | + | |
| 839 | +int tPwrFollow_setFactor(tPwrFollow* const p, float factor) | |
| 840 | +{ | |
| 841 | + if (factor<0) factor=0; | |
| 842 | + if (factor>1) factor=1; | |
| 843 | + p->factor=factor; | |
| 844 | + p->oneminusfactor=1.0f-factor; | |
| 845 | + return 0; | |
| 846 | +} | |
| 847 | + | |
| 848 | +float tPwrFollow_tick(tPwrFollow* const p, float input) | |
| 849 | +{ | |
| 850 | + p->curr = p->factor*input*input+p->oneminusfactor*p->curr; | |
| 851 | + return p->curr; | |
| 852 | +} | |
| 853 | + | |
| 854 | +float tPwrFollow_sample(tPwrFollow* const p) | |
| 855 | +{ | |
| 856 | + return p->curr; | |
| 857 | +} | |
| 858 | + | |
| 859 | +/* Feedback Leveler */ | |
| 860 | + | |
| 861 | +void tFBleveller_init(tFBleveller* const p, float targetLevel, float factor, float strength, int mode) | |
| 862 | +{ | |
| 863 | + p->curr=0.0f; | |
| 864 | + p->targetLevel=targetLevel; | |
| 865 | + tPwrFollow_init(&p->pwrFlw,factor); | |
| 866 | + p->mode=mode; | |
| 867 | + p->strength=strength; | |
| 868 | +} | |
| 869 | + | |
| 870 | +int tFBleveller_setStrength(tFBleveller* const p, float strength) | |
| 871 | +{ // strength is how strongly level diff is affecting the amp ratio | |
| 872 | + // try 0.125 for a start | |
| 873 | + p->strength=strength; | |
| 874 | + return 0; | |
| 875 | +} | |
| 876 | + | |
| 877 | +int tFBleveller_setFactor(tFBleveller* const p, float factor) | |
| 878 | +{ | |
| 879 | + tPwrFollow_setFactor(&p->pwrFlw,factor); | |
| 880 | + return 0; | |
| 881 | +} | |
| 882 | + | |
| 883 | +int tFBleveller_setMode(tFBleveller* const p, int mode) | |
| 884 | +{ // 0 for decaying with upwards lev limiting, 1 for constrained absolute level (also downwards limiting) | |
| 885 | + p->mode=mode; | |
| 886 | + return 0; | |
| 887 | +} | |
| 888 | + | |
| 889 | +float tFBleveller_tick(tFBleveller* const p, float input) | |
| 890 | +{ | |
| 891 | + float levdiff=(tPwrFollow_tick(&p->pwrFlw, input)-p->targetLevel); | |
| 892 | + if (p->mode==0 && levdiff<0) levdiff=0; | |
| 893 | + p->curr=input*(1-p->strength*levdiff); | |
| 894 | + return p->curr; | |
| 895 | +} | |
| 896 | + | |
| 897 | +float tFBleveller_sample(tFBleveller* const p) | |
| 898 | +{ | |
| 899 | + return p->curr; | |
| 900 | +} | |
| 901 | + | |
| 902 | + | |
| 903 | +int tFBleveller_setTargetLevel (tFBleveller* const p, float TargetLevel) | |
| 904 | +{ | |
| 905 | + p->targetLevel=TargetLevel; | |
| 906 | +} | |
| 907 | + | |
| 908 | +///Reed Table model | |
| 909 | +//default values from STK are 0.6 offset and -0.8 slope | |
| 910 | + | |
| 911 | +void tReedTable_init (tReedTable* const p, float offset, float slope) | |
| 912 | +{ | |
| 913 | + p->offset = offset; | |
| 914 | + p->slope = slope; | |
| 915 | +} | |
| 916 | + | |
| 917 | +void tReedTable_free (tReedTable* const p) | |
| 918 | +{ | |
| 919 | + ; | |
| 920 | +} | |
| 921 | + | |
| 922 | +float tReedTable_tick (tReedTable* const p, float input) | |
| 923 | +{ | |
| 924 | + // The input is differential pressure across the reed. | |
| 925 | + float output = p->offset + (p->slope * input); | |
| 926 | + | |
| 927 | + // If output is > 1, the reed has slammed shut and the | |
| 928 | + // reflection function value saturates at 1.0. | |
| 929 | + if ( output > 1.0f) output = 1.0f; | |
| 930 | + | |
| 931 | + // This is nearly impossible in a physical system, but | |
| 932 | + // a reflection function value of -1.0 corresponds to | |
| 933 | + // an open end (and no discontinuity in bore profile). | |
| 934 | + if ( output < -1.0f) output = -1.0f; | |
| 935 | + | |
| 936 | + return output; | |
| 937 | +} | |
| 938 | + | |
| 939 | +float tReedTable_tanh_tick (tReedTable* const p, float input) | |
| 940 | +{ | |
| 941 | + // The input is differential pressure across the reed. | |
| 942 | + float output = p->offset + (p->slope * input); | |
| 943 | + | |
| 944 | + // If output is > 1, the reed has slammed shut and the | |
| 945 | + // reflection function value saturates at 1.0. | |
| 946 | + return tanhf(output); | |
| 947 | +} | |
| 948 | + | |
| 949 | +void tReedTable_setOffset (tReedTable* const p, float offset) | |
| 950 | +{ | |
| 951 | + p->offset = offset; | |
| 952 | +} | |
| 953 | + | |
| 954 | +void tReedTable_setSlope (tReedTable* const p, float slope) | |
| 955 | +{ | |
| 956 | + p->slope = slope; | |
| 957 | +} | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | +/* Simple Living String*/ | |
| 962 | + | |
| 963 | +void tSimpleLivingString_init(tSimpleLivingString* const p, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode) | |
| 964 | +{ | |
| 965 | + p->curr=0.0f; | |
| 966 | + tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions) | |
| 967 | + tSimpleLivingString_setFreq(p, freq); | |
| 968 | + tDelayL_init(&p->delayLine,p->waveLengthInSamples, 2400); | |
| 969 | + tOnePole_init(&p->bridgeFilter, dampFreq); | |
| 970 | + tHighpass_init(&p->DCblocker,13); | |
| 971 | + p->decay=decay; | |
| 972 | + tFBleveller_init(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode); | |
| 973 | + p->levMode=levMode; | |
| 974 | +} | |
| 975 | + | |
| 976 | +int tSimpleLivingString_setFreq(tSimpleLivingString* const p, float freq) | |
| 977 | +{ | |
| 978 | + if (freq<20) freq=20; | |
| 979 | + else if (freq>10000) freq=10000; | |
| 980 | + p->waveLengthInSamples = leaf.sampleRate/freq; | |
| 981 | + tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | |
| 982 | + return 0; | |
| 983 | +} | |
| 984 | + | |
| 985 | +int tSimpleLivingString_setWaveLength(tSimpleLivingString* const p, float waveLength) | |
| 986 | +{ | |
| 987 | + if (waveLength<4.8) waveLength=4.8; | |
| 988 | + else if (waveLength>2400) waveLength=2400; | |
| 989 | + p->waveLengthInSamples = waveLength; | |
| 990 | + tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | |
| 991 | + return 0; | |
| 992 | +} | |
| 993 | + | |
| 994 | +int tSimpleLivingString_setDampFreq(tSimpleLivingString* const p, float dampFreq) | |
| 995 | +{ | |
| 996 | + tOnePole_setFreq(&p->bridgeFilter, dampFreq); | |
| 997 | + return 0; | |
| 998 | +} | |
| 999 | + | |
| 1000 | +int tSimpleLivingString_setDecay(tSimpleLivingString* const p, float decay) | |
| 1001 | +{ | |
| 1002 | + p->decay=decay; | |
| 1003 | + return 0; | |
| 1004 | +} | |
| 1005 | + | |
| 1006 | +int tSimpleLivingString_setTargetLev(tSimpleLivingString* const p, float targetLev) | |
| 1007 | +{ | |
| 1008 | + tFBleveller_setTargetLevel(&p->fbLev, targetLev); | |
| 1009 | + return 0; | |
| 1010 | +} | |
| 1011 | + | |
| 1012 | +int tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor) | |
| 1013 | +{ | |
| 1014 | + tFBleveller_setFactor(&p->fbLev, levSmoothFactor); | |
| 1015 | + return 0; | |
| 1016 | +} | |
| 1017 | + | |
| 1018 | +int tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength) | |
| 1019 | +{ | |
| 1020 | + tFBleveller_setStrength(&p->fbLev, levStrength); | |
| 1021 | + return 0; | |
| 1022 | +} | |
| 1023 | + | |
| 1024 | +int tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode) | |
| 1025 | +{ | |
| 1026 | + tFBleveller_setMode(&p->fbLev, levMode); | |
| 1027 | + p->levMode=levMode; | |
| 1028 | + return 0; | |
| 1029 | +} | |
| 1030 | + | |
| 1031 | +float tSimpleLivingString_tick(tSimpleLivingString* const p, float input) | |
| 1032 | +{ | |
| 1033 | + float stringOut=tOnePole_tick(&p->bridgeFilter,tDelayL_tickOut(&p->delayLine)); | |
| 1034 | + float stringInput=tHighpass_tick(&p->DCblocker, tFBleveller_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input)); | |
| 1035 | + tDelayL_tickIn(&p->delayLine, stringInput); | |
| 1036 | + tDelayL_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth)); | |
| 1037 | + p->curr = stringOut; | |
| 1038 | + return p->curr; | |
| 1039 | +} | |
| 1040 | + | |
| 1041 | +float tSimpleLivingString_sample(tSimpleLivingString* const p) | |
| 1042 | +{ | |
| 1043 | + return p->curr; | |
| 1044 | +} | |
| 1045 | + | |
| 1046 | +/* Living String*/ | |
| 1047 | + | |
| 1048 | +void tLivingString_init(tLivingString* const p, float freq, float pickPos, float prepIndex, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode) | |
| 1049 | +{ | |
| 1050 | + p->curr=0.0f; | |
| 1051 | + tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions) | |
| 1052 | + tLivingString_setFreq(p, freq); | |
| 1053 | + tExpSmooth_init(&p->ppSmooth, pickPos, 0.01); // smoother for pick position | |
| 1054 | + tLivingString_setPickPos(p, pickPos); | |
| 1055 | + p->prepIndex=prepIndex; | |
| 1056 | + tDelayL_init(&p->delLF,p->waveLengthInSamples, 2400); | |
| 1057 | + tDelayL_init(&p->delUF,p->waveLengthInSamples, 2400); | |
| 1058 | + tDelayL_init(&p->delUB,p->waveLengthInSamples, 2400); | |
| 1059 | + tDelayL_init(&p->delLB,p->waveLengthInSamples, 2400); | |
| 1060 | + tOnePole_init(&p->bridgeFilter, dampFreq); | |
| 1061 | + tOnePole_init(&p->nutFilter, dampFreq); | |
| 1062 | + tOnePole_init(&p->prepFilterU, dampFreq); | |
| 1063 | + tOnePole_init(&p->prepFilterL, dampFreq); | |
| 1064 | + tHighpass_init(&p->DCblockerU,13); | |
| 1065 | + tHighpass_init(&p->DCblockerL,13); | |
| 1066 | + p->decay=decay; | |
| 1067 | + tFBleveller_init(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode); | |
| 1068 | + tFBleveller_init(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode); | |
| 1069 | + p->levMode=levMode; | |
| 1070 | +} | |
| 1071 | + | |
| 1072 | +int tLivingString_setFreq(tLivingString* const p, float freq) | |
| 1073 | +{ // NOTE: It is faster to set wavelength in samples directly | |
| 1074 | + if (freq<20) freq=20; | |
| 1075 | + else if (freq>10000) freq=10000; | |
| 1076 | + p->waveLengthInSamples = leaf.sampleRate/freq; | |
| 1077 | + tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | |
| 1078 | + return 0; | |
| 1079 | +} | |
| 1080 | + | |
| 1081 | +int tLivingString_setWaveLength(tLivingString* const p, float waveLength) | |
| 1082 | +{ | |
| 1083 | + if (waveLength<4.8) waveLength=4.8; | |
| 1084 | + else if (waveLength>2400) waveLength=2400; | |
| 1085 | + p->waveLengthInSamples = waveLength; | |
| 1086 | + tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples); | |
| 1087 | + return 0; | |
| 1088 | +} | |
| 1089 | + | |
| 1090 | +int tLivingString_setPickPos(tLivingString* const p, float pickPos) | |
| 1091 | +{ // between 0 and 1 | |
| 1092 | + if (pickPos<0.f) pickPos=0.f; | |
| 1093 | + else if (pickPos>1.f) pickPos=1.f; | |
| 1094 | + p->pickPos = pickPos; | |
| 1095 | + tExpSmooth_setDest(&p->ppSmooth, p->pickPos); | |
| 1096 | + return 0; | |
| 1097 | +} | |
| 1098 | + | |
| 1099 | +int tLivingString_setPrepIndex(tLivingString* const p, float prepIndex) | |
| 1100 | +{ // between 0 and 1 | |
| 1101 | + if (prepIndex<0.f) prepIndex=0.f; | |
| 1102 | + else if (prepIndex>1.f) prepIndex=1.f; | |
| 1103 | + p->prepIndex = prepIndex; | |
| 1104 | + return 0; | |
| 1105 | +} | |
| 1106 | + | |
| 1107 | +int tLivingString_setDampFreq(tLivingString* const p, float dampFreq) | |
| 1108 | +{ | |
| 1109 | + tOnePole_setFreq(&p->bridgeFilter, dampFreq); | |
| 1110 | + tOnePole_setFreq(&p->nutFilter, dampFreq); | |
| 1111 | + tOnePole_setFreq(&p->prepFilterU, dampFreq); | |
| 1112 | + tOnePole_setFreq(&p->prepFilterL, dampFreq); | |
| 1113 | + return 0; | |
| 1114 | +} | |
| 1115 | + | |
| 1116 | +int tLivingString_setDecay(tLivingString* const p, float decay) | |
| 1117 | +{ | |
| 1118 | + p->decay=decay; | |
| 1119 | + return 0; | |
| 1120 | +} | |
| 1121 | + | |
| 1122 | +int tLivingString_setTargetLev(tLivingString* const p, float targetLev) | |
| 1123 | +{ | |
| 1124 | + tFBleveller_setTargetLevel(&p->fbLevU, targetLev); | |
| 1125 | + tFBleveller_setTargetLevel(&p->fbLevL, targetLev); | |
| 1126 | + return 0; | |
| 1127 | +} | |
| 1128 | + | |
| 1129 | +int tLivingString_setLevSmoothFactor(tLivingString* const p, float levSmoothFactor) | |
| 1130 | +{ | |
| 1131 | + tFBleveller_setFactor(&p->fbLevU, levSmoothFactor); | |
| 1132 | + tFBleveller_setFactor(&p->fbLevL, levSmoothFactor); | |
| 1133 | + return 0; | |
| 1134 | +} | |
| 1135 | + | |
| 1136 | +int tLivingString_setLevStrength(tLivingString* const p, float levStrength) | |
| 1137 | +{ | |
| 1138 | + tFBleveller_setStrength(&p->fbLevU, levStrength); | |
| 1139 | + tFBleveller_setStrength(&p->fbLevL, levStrength); | |
| 1140 | + return 0; | |
| 1141 | +} | |
| 1142 | + | |
| 1143 | +int tLivingString_setLevMode(tLivingString* const p, int levMode) | |
| 1144 | +{ | |
| 1145 | + tFBleveller_setMode(&p->fbLevU, levMode); | |
| 1146 | + tFBleveller_setMode(&p->fbLevL, levMode); | |
| 1147 | + p->levMode=levMode; | |
| 1148 | + return 0; | |
| 1149 | +} | |
| 1150 | + | |
| 1151 | +float tLivingString_tick(tLivingString* const p, float input) | |
| 1152 | +{ | |
| 1153 | + // from pickPos upwards=forwards | |
| 1154 | + float fromLF=tDelayL_tickOut(&p->delLF); | |
| 1155 | + float fromUF=tDelayL_tickOut(&p->delUF); | |
| 1156 | + float fromUB=tDelayL_tickOut(&p->delUB); | |
| 1157 | + float fromLB=tDelayL_tickOut(&p->delLB); | |
| 1158 | + // into upper half of string, from nut, going backwards | |
| 1159 | + float fromNut=-tFBleveller_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->nutFilter, fromUF))); | |
| 1160 | + tDelayL_tickIn(&p->delUB, fromNut); | |
| 1161 | + // into lower half of string, from pickpoint, going backwards | |
| 1162 | + float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF); | |
| 1163 | + float intoLower=p->prepIndex*fromLowerPrep+(1-p->prepIndex)*fromUB+input; | |
| 1164 | + tDelayL_tickIn(&p->delLB, intoLower); | |
| 1165 | + // into lower half of string, from bridge | |
| 1166 | + float fromBridge=-tFBleveller_tick(&p->fbLevL, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->bridgeFilter, fromLB))); | |
| 1167 | + tDelayL_tickIn(&p->delLF, fromBridge); | |
| 1168 | + // into upper half of string, from pickpoint, going forwards/upwards | |
| 1169 | + float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB); | |
| 1170 | + float intoUpper=p->prepIndex*fromUpperPrep+(1-p->prepIndex)*fromLF+input; | |
| 1171 | + tDelayL_tickIn(&p->delUF, intoUpper); | |
| 1172 | + // update all delay lengths | |
| 1173 | + float pickP=tExpSmooth_tick(&p->ppSmooth); | |
| 1174 | + float wLen=tExpSmooth_tick(&p->wlSmooth); | |
| 1175 | + float lowLen=pickP*wLen; | |
| 1176 | + float upLen=(1-pickP)*wLen; | |
| 1177 | + tDelayL_setDelay(&p->delLF, lowLen); | |
| 1178 | + tDelayL_setDelay(&p->delLB, lowLen); | |
| 1179 | + tDelayL_setDelay(&p->delUF, upLen); | |
| 1180 | + tDelayL_setDelay(&p->delUB, upLen); | |
| 1181 | + p->curr = fromBridge; | |
| 1182 | + return p->curr; | |
| 1183 | +} | |
| 1184 | + | |
| 1185 | +float tLivingString_sample(tLivingString* const p) | |
| 1186 | +{ | |
| 1187 | + return p->curr; | |
| 1188 | +} | |
| 1189 | + | |
| 1190 | + | |
| 1191 | +/* Stack */ | |
| 1192 | + | |
| 778 | 1193 | // If stack contains note, returns index. Else returns -1; |
| 779 | 1194 | int tStack_contains(tStack* const ns, uint16_t noteVal) |
| 780 | 1195 | { |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #endif |
| 18 | 18 | |
| 19 | −void tLockhartWavefolderInit(tLockhartWavefolder* const w) | |
| 19 | +void tLockhartWavefolder_init(tLockhartWavefolder* const w) | |
| 20 | 20 | { |
| 21 | 21 | w->Ln1 = 0.0; |
| 22 | 22 | w->Fn1 = 0.0; |
| @@ -54,7 +54,7 @@ double tLockhartWavefolderLambert(double x, double ln) · 31 unmodified lines | ||
| 54 | 54 | return w; |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | −float tLockhartWavefolderTick(tLockhartWavefolder* const w, float samp) | |
| 57 | +float tLockhartWavefolder_tick(tLockhartWavefolder* const w, float samp) | |
| 58 | 58 | { |
| 59 | 59 | int l; |
| 60 | 60 | double u, Ln, Fn, xn; |
| @@ -9,13 +9,13 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | #ifndef LEAF_H_INCLUDED |
| 12 | −#define LEAF_H_INCLUDED | |
| 13 | − | |
| 14 | −#define LEAF_DEBUG 0 | |
| 15 | − | |
| 16 | −#if LEAF_DEBUG | |
| 17 | −#include "../LEAF_JUCEPlugin/JuceLibraryCode/JuceHeader.h" | |
| 18 | −#endif | |
| 12 | +#define LEAF_H_INCLUDED | |
| 13 | + | |
| 14 | +#define LEAF_DEBUG 0 | |
| 15 | + | |
| 16 | +#if LEAF_DEBUG | |
| 17 | +#include "../LEAF_JUCEPlugin/JuceLibraryCode/JuceHeader.h" | |
| 18 | +#endif | |
| 19 | 19 | |
| 20 | 20 | #if _WIN32 || _WIN64 |
| 21 | 21 | |
| @@ -25,14 +25,15 @@ · 3 unmodified lines | ||
| 25 | 25 | #include ".\Inc\leaf-delay.h" |
| 26 | 26 | #include ".\Inc\leaf-filter.h" |
| 27 | 27 | #include ".\Inc\leaf-oscillator.h" |
| 28 | +#include ".\Inc\leaf-oversampler.h" | |
| 28 | 29 | #include ".\Inc\leaf-reverb.h" |
| 29 | 30 | #include ".\Inc\leaf-vocoder.h" |
| 30 | 31 | #include ".\Inc\leaf-808.h" |
| 31 | 32 | #include ".\Inc\leaf-string.h" |
| 32 | 33 | #include ".\Inc\leaf-pitch.h" |
| 33 | 34 | #include ".\Inc\leaf-formant.h" |
| 34 | −#include ".\Inc\leaf-midi.h" | |
| 35 | −#include ".\Inc\leaf-sample.h" | |
| 35 | +#include ".\Inc\leaf-midi.h" | |
| 36 | +#include ".\Inc\leaf-sample.h" | |
| 36 | 37 | #include ".\Inc\leaf-crusher.h" |
| 37 | 38 | #include ".\Inc\leaf-wavefolder.h" |
| 38 | 39 | #include ".\Inc\leaf-wavetables.h" |
| @@ -46,31 +47,32 @@ · 7 unmodified lines | ||
| 46 | 47 | #include "./Inc/leaf-delay.h" |
| 47 | 48 | #include "./Inc/leaf-filter.h" |
| 48 | 49 | #include "./Inc/leaf-oscillator.h" |
| 50 | +#include "./Inc/leaf-oversampler.h" | |
| 49 | 51 | #include "./Inc/leaf-reverb.h" |
| 50 | 52 | #include "./Inc/leaf-vocoder.h" |
| 51 | 53 | #include "./Inc/leaf-808.h" |
| 52 | 54 | #include "./Inc/leaf-string.h" |
| 53 | 55 | #include "./Inc/leaf-pitch.h" |
| 54 | 56 | #include "./Inc/leaf-formant.h" |
| 55 | −#include "./Inc/leaf-midi.h" | |
| 56 | −#include "./Inc/leaf-sample.h" | |
| 57 | +#include "./Inc/leaf-midi.h" | |
| 58 | +#include "./Inc/leaf-sample.h" | |
| 57 | 59 | #include "./Inc/leaf-crusher.h" |
| 58 | 60 | #include "./Inc/leaf-wavefolder.h" |
| 59 | 61 | #include "./Inc/leaf-wavetables.h" |
| 60 | 62 | #include "./Inc/leaf-crusher.h" |
| 61 | 63 | |
| 62 | −#endif | |
| 64 | +#endif | |
| 63 | 65 | |
| 64 | −#ifdef __cplusplus | |
| 65 | −extern "C" { | |
| 66 | −#endif | |
| 66 | +#ifdef __cplusplus | |
| 67 | +extern "C" { | |
| 68 | +#endif | |
| 67 | 69 | |
| 68 | 70 | void LEAF_init (float sampleRate, int blocksize, float(*randomNumberFunction)(void)); |
| 69 | 71 | void LEAF_setSampleRate (float sampleRate); |
| 70 | −float LEAF_getSampleRate (void); | |
| 71 | − | |
| 72 | −#ifdef __cplusplus | |
| 73 | −} | |
| 74 | −#endif | |
| 72 | +float LEAF_getSampleRate (void); | |
| 73 | + | |
| 74 | +#ifdef __cplusplus | |
| 75 | +} | |
| 76 | +#endif | |
| 75 | 77 | |
| 76 | 78 | #endif // LEAF_H_INCLUDED |
| @@ -191,3 +191,4 @@ static void run_pool_test(void) · 190 unmodified lines | ||
| 191 | 191 | |
| 192 | 192 | leaf_pool_dump(); |
| 193 | 193 | } |
| 194 | + | |