History

recategorization of objects, some objects renamed

Matthew Wang committed 7 years ago

Commit 7803edf1 parent 3b564d450 files · +5701 −5731Browse files

Unified · Split

50 files
  1. LEAF/Inc/.DS_Store +0 −0
  2. LEAF/Inc/leaf-analysis.h +226 −0
  3. LEAF/Inc/leaf-crusher.h +0 −64
  4. LEAF/Inc/leaf-delay.h +26 −26
  5. LEAF/Inc/leaf-distortion.h +99 −0
  6. LEAF/Inc/leaf-dynamics.h +79 −0
  7. LEAF/Inc/leaf-effects.h +251 −0
  8. LEAF/Inc/leaf-electrical.h +4 −4
  9. LEAF/Inc/leaf-envelopes.h +136 −0
  10. LEAF/Inc/leaf-filters.h +12 −12
  11. LEAF/Inc/leaf-formant.h +0 −68
  12. LEAF/Inc/leaf-instruments.h +7 −7
  13. LEAF/Inc/leaf-midi.h +29 −1
  14. LEAF/Inc/leaf-oscillators.h +83 −84
  15. LEAF/Inc/leaf-oversampler.h +0 −51
  16. LEAF/Inc/leaf-physical.h +221 −0
  17. LEAF/Inc/leaf-pitch.h +0 −161
  18. LEAF/Inc/leaf-reverb.h +29 −30
  19. LEAF/Inc/leaf-sample.h +0 −125
  20. LEAF/Inc/leaf-sampling.h +124 −0
  21. LEAF/Inc/leaf-string.h +0 −143
  22. LEAF/Inc/leaf-tables.h +3 −3
  23. LEAF/Inc/leaf-utilities.h +0 −483
  24. LEAF/Inc/leaf-vocoder.h +0 −89
  25. LEAF/Inc/leaf-wavefolder.h +0 −48
  26. LEAF/Src/leaf-analysis.c +733 −0
  27. LEAF/Src/leaf-crusher.c +0 −84
  28. LEAF/Src/leaf-delay.c +30 −30
  29. LEAF/Src/leaf-distortion.c +173 −2
  30. LEAF/Src/leaf-dynamics.c +172 −0
  31. LEAF/Src/leaf-effects.c +1393 −0
  32. LEAF/Src/leaf-electrical.c +13 −2
  33. LEAF/Src/leaf-envelopes.c +629 −0
  34. LEAF/Src/leaf-filters.c +11 −11
  35. LEAF/Src/leaf-formant.c +0 −206
  36. LEAF/Src/leaf-instruments.c +3 −3
  37. LEAF/Src/leaf-math.c +2 −0
  38. LEAF/Src/leaf-midi.c +213 −0
  39. LEAF/Src/leaf-oscillators.c +305 −299
  40. LEAF/Src/leaf-physical.c +596 −0
  41. LEAF/Src/leaf-pitch.c +0 −563
  42. LEAF/Src/leaf-reverb.c +32 −32
  43. LEAF/Src/leaf-sampling.c +3 −3
  44. LEAF/Src/leaf-string.c +0 −289
  45. LEAF/Src/leaf-utilities.c +0 −2227
  46. LEAF/Src/leaf-vocoder.c +0 −400
  47. LEAF/Src/leaf-wavefolder.c +0 −114
  48. LEAF/leaf.h +24 −27
  49. LEAF_JUCEPlugin/LEAF.jucer +38 −40
  50. LEAF_JUCEPlugin/Source/MyTest.cpp +3 −1
LEAF/Inc/.DS_Store+0−0

Binary file not shown.

LEAF/Inc/leaf-analysis.h+226−0
@@ -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
13extern "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 */
26typedef struct _tEnvelopeFollower
27{
28 float y;
29 float a_thresh;
30 float d_coeff;
31
32} tEnvelopeFollower;
33
34void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff);
35void tEnvelopeFollower_free (tEnvelopeFollower* const);
36
37float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x);
38int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff);
39int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh);
40
41// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
42
43/* PowerEnvelopeFollower */
44typedef struct _tPowerFollower {
45 float factor, oneminusfactor;
46 float curr;
47
48} tPowerFollower;
49
50void tPowerFollower_init (tPowerFollower* const, float factor);
51void tPowerFollower_free (tPowerFollower* const);
52float tPowerFollower_tick (tPowerFollower* const, float input);
53float tPowerFollower_sample (tPowerFollower* const);
54int 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
64typedef 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
78void tEnvPD_init (tEnvPD* const, int windowSize, int hopSize, int blockSize);
79void tEnvPD_free (tEnvPD* const);
80float tEnvPD_tick (tEnvPD* const);
81void 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
91typedef 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
112void tAttackDetection_init (tAttackDetection* const, int blocksize);
113void tAttackDetection_init_expanded (tAttackDetection* const, int blocksize, int atk, int rel);
114void tAttackDetection_free (tAttackDetection* const);
115
116// set expected input blocksize
117void tAttackDetection_setBlocksize (tAttackDetection* const, int size);
118
119// change atkDetector sample rate
120void tAttackDetection_setSamplerate (tAttackDetection* const, int inRate);
121
122// set attack time and coeff
123void tAttackDetection_setAtk (tAttackDetection* const, int inAtk);
124
125// set release time and coeff
126void tAttackDetection_setRel (tAttackDetection* const, int inRel);
127
128// set level above which values are identified as attacks
129void tAttackDetection_setThreshold (tAttackDetection* const, float thres);
130
131// find largest transient in input block, return index of attack
132int 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
143typedef 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
161void tSNAC_init (tSNAC* const, int overlaparg); // constructor
162void tSNAC_free (tSNAC* const); // destructor
163
164void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size);
165void tSNAC_setOverlap (tSNAC *s, int lap);
166void tSNAC_setBias (tSNAC *s, float bias);
167void tSNAC_setMinRMS (tSNAC *s, float rms);
168
169/*To get freq, perform SAMPLE_RATE/snac_getperiod() */
170float tSNAC_getPeriod (tSNAC *s);
171float 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
182typedef 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
211void tPeriodDetection_init (tPeriodDetection* const, float* in, float* out, int bufSize, int frameSize);
212void tPeriodDetection_free (tPeriodDetection* const);
213
214float tPeriodDetection_findPeriod (tPeriodDetection* const, float sample);
215void tPeriodDetection_setHopSize (tPeriodDetection* p, int hs);
216void tPeriodDetection_setWindowSize (tPeriodDetection* p, int ws);
217
218//==============================================================================
219
220#ifdef __cplusplus
221}
222#endif
223
224#endif // LEAF_ANALYSIS_H_INCLUDED
225
226//==============================================================================
LEAF/Inc/leaf-crusher.h+0−64
@@ -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
16extern "C" {
17#endif
18
19//==============================================================================
20
21#include "leaf-global.h"
22#include "leaf-math.h"
23
24//==============================================================================
25
26typedef 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
39void tCrusher_init (tCrusher* const);
40void tCrusher_free (tCrusher* const);
41
42float tCrusher_tick (tCrusher* const, float input);
43
44// 0.0 - 1.0
45void tCrusher_setOperation (tCrusher* const, float op);
46
47// 0.0 - 1.0
48void tCrusher_setQuality (tCrusher* const, float val);
49
50// what division to round to
51void tCrusher_setRound (tCrusher* const, float rnd);
52
53// sampling ratio
54void tCrusher_setSamplingRatio (tCrusher* const, float ratio);
55
56//==============================================================================
57
58#ifdef __cplusplus
59}
60#endif
61
62#endif // LEAF_WAVEFOLDER_H_INCLUDED
63
64//==============================================================================
LEAF/Inc/leaf-delay.h+26−26
@@ -48,7 +48,7 @@ float tDelay_getLastIn (tDelay* const); · 47 unmodified lines
48//==============================================================================48//==============================================================================
49 49
50/* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */50/* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */
51typedef struct _tDelayL51typedef struct _tLinearDelay
52{52{
53 float gain;53 float gain;
54 float* buff;54 float* buff;
@@ -63,26 +63,26 @@ typedef struct _tDelayL · 8 unmodified lines
63 63
64 float alpha, omAlpha;64 float alpha, omAlpha;
65 65
66} tDelayL;66} tLinearDelay;
67 67
68void tDelayL_init (tDelayL* const, float delay, uint32_t maxDelay);68void tLinearDelay_init (tLinearDelay* const, float delay, uint32_t maxDelay);
69void tDelayL_free (tDelayL* const);69void tLinearDelay_free (tLinearDelay* const);
70 70
71int tDelayL_setDelay (tDelayL* const, float delay);71int tLinearDelay_setDelay (tLinearDelay* const, float delay);
72float tDelayL_getDelay (tDelayL* const);72float tLinearDelay_getDelay (tLinearDelay* const);
73void tDelayL_tapIn (tDelayL* const, float in, uint32_t tapDelay);73void tLinearDelay_tapIn (tLinearDelay* const, float in, uint32_t tapDelay);
74float tDelayL_tapOut (tDelayL* const, float tapDelay);74float tLinearDelay_tapOut (tLinearDelay* const, float tapDelay);
75float tDelayL_addTo (tDelayL* const, float value, uint32_t tapDelay);75float tLinearDelay_addTo (tLinearDelay* const, float value, uint32_t tapDelay);
76float tDelayL_tick (tDelayL* const, float sample);76float tLinearDelay_tick (tLinearDelay* const, float sample);
77void tDelayL_tickIn (tDelayL* const d, float input);77void tLinearDelay_tickIn (tLinearDelay* const d, float input);
78float tDelayL_tickOut (tDelayL* const d);78float tLinearDelay_tickOut (tLinearDelay* const d);
79float tDelayL_getLastOut (tDelayL* const);79float tLinearDelay_getLastOut (tLinearDelay* const);
80float tDelayL_getLastIn (tDelayL* const);80float tLinearDelay_getLastIn (tLinearDelay* const);
81 81
82//==============================================================================82//==============================================================================
83 83
84/* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */84/* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */
85typedef struct _tDelayA85typedef struct _tAllpassDelay
86{86{
87 float gain;87 float gain;
88 float* buff;88 float* buff;
@@ -99,19 +99,19 @@ typedef struct _tDelayA · 10 unmodified lines
99 99
100 float apInput;100 float apInput;
101 101
102} tDelayA;102} tAllpassDelay;
103 103
104void tDelayA_init (tDelayA* const, float delay, uint32_t maxDelay);104void tAllpassDelay_init (tAllpassDelay* const, float delay, uint32_t maxDelay);
105void tDelayA_free (tDelayA* const);105void tAllpassDelay_free (tAllpassDelay* const);
106 106
107int tDelayA_setDelay (tDelayA* const, float delay);107int tAllpassDelay_setDelay (tAllpassDelay* const, float delay);
108float tDelayA_getDelay (tDelayA* const);108float tAllpassDelay_getDelay (tAllpassDelay* const);
109void tDelayA_tapIn (tDelayA* const, float in, uint32_t tapDelay);109void tAllpassDelay_tapIn (tAllpassDelay* const, float in, uint32_t tapDelay);
110float tDelayA_tapOut (tDelayA* const, uint32_t tapDelay);110float tAllpassDelay_tapOut (tAllpassDelay* const, uint32_t tapDelay);
111float tDelayA_addTo (tDelayA* const, float value, uint32_t tapDelay);111float tAllpassDelay_addTo (tAllpassDelay* const, float value, uint32_t tapDelay);
112float tDelayA_tick (tDelayA* const, float sample);112float tAllpassDelay_tick (tAllpassDelay* const, float sample);
113float tDelayA_getLastOut (tDelayA* const);113float tAllpassDelay_getLastOut (tAllpassDelay* const);
114float tDelayA_getLastIn (tDelayA* const);114float tAllpassDelay_getLastIn (tAllpassDelay* const);
115 115
116//==============================================================================116//==============================================================================
117 117
LEAF/Inc/leaf-distortion.h+99−0
@@ -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
13extern "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
26typedef struct _tLockhartWavefolder
27{
28 double Ln1;
29 double Fn1;
30 float xn1;
31
32} tLockhartWavefolder;
33
34void tLockhartWavefolder_init (tLockhartWavefolder* const);
35void tLockhartWavefolder_free (tLockhartWavefolder* const);
36
37float tLockhartWavefolder_tick (tLockhartWavefolder* const, float samp);
38
39//==============================================================================
40
41typedef 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
54void tCrusher_init (tCrusher* const);
55void tCrusher_free (tCrusher* const);
56
57float tCrusher_tick (tCrusher* const, float input);
58
59// 0.0 - 1.0
60void tCrusher_setOperation (tCrusher* const, float op);
61
62// 0.0 - 1.0
63void tCrusher_setQuality (tCrusher* const, float val);
64
65// what division to round to
66void tCrusher_setRound (tCrusher* const, float rnd);
67
68// sampling ratio
69void tCrusher_setSamplingRatio (tCrusher* const, float ratio);
70
71//==============================================================================
72
73typedef struct _tOversampler
74{
75 int ratio;
76 float* pCoeffs;
77 float* upState;
78 float* downState;
79 int numTaps;
80 int phaseLength;
81} tOversampler;
82
83void tOversampler_init(tOversampler* const, int order, oBool extraQuality);
84void tOversampler_free(tOversampler* const);
85void tOversampler_upsample(tOversampler* const, float input, float* output);
86float tOversampler_downsample(tOversampler *const os, float* input);
87float tOversampler_tick(tOversampler* const, float input, float (*effectTick)(float));
88int tOversampler_getLatency(tOversampler* const os);
89
90//==============================================================================
91
92#ifdef __cplusplus
93}
94#endif
95
96#endif // LEAF_DISTORTION_H_INCLUDED
97
98//==============================================================================
99
LEAF/Inc/leaf-dynamics.h+79−0
@@ -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
14extern "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 */
28typedef 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
39void tCompressor_init (tCompressor* const);
40void tCompressor_free (tCompressor* const);
41float 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
51typedef 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
60void tFeedbackLeveler_init (tFeedbackLeveler* const, float targetLevel, float factor, float strength, int mode);
61void tFeedbackLeveler_free (tFeedbackLeveler* const);
62
63float tFeedbackLeveler_tick (tFeedbackLeveler* const, float input);
64float tFeedbackLeveler_sample (tFeedbackLeveler* const);
65void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const, float TargetLevel);
66void tFeedbackLeveler_setFactor (tFeedbackLeveler* const, float factor);
67void tFeedbackLeveler_setMode (tFeedbackLeveler* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting
68void 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//==============================================================================
LEAF/Inc/leaf-effects.h+251−0
@@ -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
13extern "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
27typedef 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
46void tTalkbox_init (tTalkbox* const, int bufsize);
47void tTalkbox_free (tTalkbox* const);
48float tTalkbox_tick (tTalkbox* const, float synth, float voice);
49void tTalkbox_update (tTalkbox* const);
50void tTalkbox_suspend (tTalkbox* const);
51void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g);
52void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o);
53void tTalkbox_setQuality (tTalkbox* const, float quality);
54
55//==============================================================================
56
57/* tVocoder */
58#define NUM_VOCODER_PARAM 8
59#define NBANDS 16
60
61typedef 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
76void tVocoder_init (tVocoder* const);
77void tVocoder_free (tVocoder* const);
78float tVocoder_tick (tVocoder* const, float synth, float voice);
79void tVocoder_update (tVocoder* const);
80void 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
97typedef 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
112void tSOLAD_init (tSOLAD* const);
113void tSOLAD_free (tSOLAD* const);
114
115// send one block of input samples, receive one block of output samples
116void tSOLAD_ioSamples (tSOLAD *w, float* in, float* out, int blocksize);
117
118// set periodicity analysis data
119void tSOLAD_setPeriod (tSOLAD *w, float period);
120
121// set pitch factor between 0.25 and 4
122void tSOLAD_setPitchFactor (tSOLAD *w, float pitchfactor);
123
124// force readpointer lag
125void tSOLAD_setReadLag (tSOLAD *w, float readlag);
126
127// reset state variables
128void tSOLAD_resetState (tSOLAD *w);
129
130// Pitch shifter
131typedef 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
160void tPitchShifter_init (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize);
161void tPitchShifter_free (tPitchShifter* const);
162
163float tPitchShifter_tick (tPitchShifter* const, float sample);
164float tPitchShifterToFreq_tick (tPitchShifter* const, float sample, float freq);
165float tPitchShifterToFunc_tick (tPitchShifter* const, float sample, float (*fun)(float));
166void tPitchShifter_ioSamples_toFreq (tPitchShifter* const, float* in, float* out, int size, float toFreq);
167void tPitchShifter_ioSamples_toPeriod(tPitchShifter* const, float* in, float* out, int size, float toPeriod);
168void tPitchShifter_ioSamples_toFunc (tPitchShifter* const, float* in, float* out, int size, float (*fun)(float));
169void tPitchShifter_setPitchFactor (tPitchShifter* const, float pf);
170void tPitchShifter_setTimeConstant (tPitchShifter* const, float tc);
171void tPitchShifter_setHopSize (tPitchShifter* const, int hs);
172void tPitchShifter_setWindowSize (tPitchShifter* const, int ws);
173float tPitchShifter_getPeriod (tPitchShifter* const);
174
175//==============================================================================
176
177// Pitch shift
178typedef 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
198void tPitchShift_init (tPitchShift* const,tPeriodDetection* const, float* out, int bufSize);
199void tPitchShift_free (tPitchShift* const);
200
201float tPitchShift_shift (tPitchShift* const);
202float tPitchShift_shiftToFunc (tPitchShift* const, float (*fun)(float));
203float tPitchShift_shiftToFreq (tPitchShift* const, float freq);
204void tPitchShift_setPitchFactor (tPitchShift* const, float pf);
205
206//==============================================================================
207
208#define FORD 7
209#define FORMANT_BUFFER_SIZE 2048
210
211typedef 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
235void tFormantShifter_init (tFormantShifter* const, int bufsize, int order);
236void tFormantShifter_free (tFormantShifter* const);
237
238float tFormantShifter_tick (tFormantShifter* const, float input, float fwarp);
239float tFormantShifter_remove (tFormantShifter* const, float input);
240float tFormantShifter_add (tFormantShifter* const, float input, float fwarp);
241void 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//==============================================================================
LEAF/Inc/leaf-electrical.hrenamed from LEAF/Inc/leaf-WDF.h+4−4
@@ -1,12 +1,12 @@
1/*1/*
2 * leaf-WDF.h2 * leaf-electrical.h
3 *3 *
4 * Created on: Sep 25, 20194 * Created on: Sep 25, 2019
5 * Author: jeffsnyder5 * Author: jeffsnyder
6 */6 */
7 7
8#ifndef LEAF_INC_LEAF_WDF_H_8#ifndef LEAF_INC_LEAF_ELECTRICAL_H_
9#define LEAF_INC_LEAF_WDF_H_9#define LEAF_INC_LEAF_ELECTRICAL_H_
10 10
11#ifdef __cplusplus11#ifdef __cplusplus
12extern "C" {12extern "C" {
@@ -86,4 +86,4 @@ float tWDF_getCurrent(tWDF* const r); · 73 unmodified lines
86}86}
87#endif87#endif
88 88
89#endif /* LEAF_INC_LEAF_WDF_H_ */89#endif /* LEAF_INC_LEAF_ELECTRICAL_H_ */
LEAF/Inc/leaf-envelopes.h+136−0
@@ -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
15extern "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 */
27typedef 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
47void tEnvelope_init (tEnvelope* const, float attack, float decay, oBool loop);
48void tEnvelope_free (tEnvelope* const);
49
50float tEnvelope_tick (tEnvelope* const);
51int tEnvelope_setAttack (tEnvelope* const, float attack);
52int tEnvelope_setDecay (tEnvelope* const, float decay);
53int tEnvelope_loop (tEnvelope* const, oBool loop);
54int tEnvelope_on (tEnvelope* const, float velocity);
55
56// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
57
58/* ADSR */
59typedef 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
77void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release);
78void tADSR_free (tADSR* const);
79
80float tADSR_tick (tADSR* const);
81int tADSR_setAttack (tADSR* const, float attack);
82int tADSR_setDecay (tADSR* const, float decay);
83int tADSR_setSustain(tADSR* const, float sustain);
84int tADSR_setRelease(tADSR* const, float release);
85int tADSR_on (tADSR* const, float velocity);
86int tADSR_off (tADSR* const);
87
88// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
89
90// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
91
92/* Ramp */
93typedef 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
103void tRamp_init (tRamp* const, float time, int samplesPerTick);
104void tRamp_free (tRamp* const);
105
106float tRamp_tick (tRamp* const);
107float tRamp_sample (tRamp* const);
108int tRamp_setTime (tRamp* const, float time);
109int tRamp_setDest (tRamp* const, float dest);
110int tRamp_setVal (tRamp* const, float val);
111
112// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
113
114/* Exponential Smoother */
115typedef struct _tExpSmooth {
116 float factor, oneminusfactor;
117 float curr,dest;
118
119} tExpSmooth;
120
121void tExpSmooth_init (tExpSmooth* const, float val, float factor);
122void tExpSmooth_free (tExpSmooth* const);
123
124float tExpSmooth_tick (tExpSmooth* const);
125float tExpSmooth_sample (tExpSmooth* const);
126int tExpSmooth_setFactor (tExpSmooth* const, float factor);
127int tExpSmooth_setDest (tExpSmooth* const, float dest);
128int tExpSmooth_setVal (tExpSmooth* const, float val);
129
130#ifdef __cplusplus
131}
132#endif
133
134#endif // LEAF_ENVELOPES_H_INCLUDED
135
136
LEAF/Inc/leaf-filters.hrenamed from LEAF/Inc/leaf-filter.h+12−12
@@ -1,13 +1,13 @@
1/*==============================================================================1/*==============================================================================
2 2
3 leaf-filter.h3 leaf-filters.h
4 Created: 20 Jan 2017 12:01:10pm4 Created: 20 Jan 2017 12:01:10pm
5 Author: Michael R Mulshine5 Author: Michael R Mulshine
6 6
7==============================================================================*/7==============================================================================*/
8 8
9#ifndef LEAF_FILTER_H_INCLUDED9#ifndef LEAF_FILTERS_H_INCLUDED
10#define LEAF_FILTER_H_INCLUDED10#define LEAF_FILTERS_H_INCLUDED
11 11
12#ifdef __cplusplus12#ifdef __cplusplus
13extern "C" {13extern "C" {
@@ -26,7 +26,7 @@ typedef struct _tAllpass · 12 unmodified lines
26{26{
27 float gain;27 float gain;
28 28
29 tDelayL delay;29 tLinearDelay delay;
30 30
31 float lastOut;31 float lastOut;
32 32
@@ -227,21 +227,21 @@ int tSVF_setQ (tSVF* const, float Q); · 194 unmodified lines
227//==============================================================================227//==============================================================================
228 228
229/* Efficient State Variable Filter for 14-bit control input, [0, 4096). */229/* Efficient State Variable Filter for 14-bit control input, [0, 4096). */
230typedef struct _tSVFE230typedef struct _tEfficientSVF
231{231{
232 SVFType type;232 SVFType type;
233 float cutoff, Q;233 float cutoff, Q;
234 float ic1eq,ic2eq;234 float ic1eq,ic2eq;
235 float g,k,a1,a2,a3;235 float g,k,a1,a2,a3;
236 236
237} tSVFE;237} tEfficientSVF;
238 238
239void tSVFE_init (tSVFE* const, SVFType type, uint16_t controlFreq, float Q);239void tEfficientSVF_init (tEfficientSVF* const, SVFType type, uint16_t controlFreq, float Q);
240void tSVFE_free (tSVFE* const);240void tEfficientSVF_free (tEfficientSVF* const);
241 241
242float tSVFE_tick (tSVFE* const, float v0);242float tEfficientSVF_tick (tEfficientSVF* const, float v0);
243int tSVFE_setFreq (tSVFE* const, uint16_t controlFreq);243int tEfficientSVF_setFreq (tEfficientSVF* const, uint16_t controlFreq);
244int tSVFE_setQ (tSVFE* const, float Q);244int 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#endif308#endif
309 309
310#endif // LEAF_FILTER_H_INCLUDED310#endif // LEAF_FILTERS_H_INCLUDED
311 311
312//==============================================================================312//==============================================================================
LEAF/Inc/leaf-formant.h+0−68
@@ -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
13extern "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
27typedef 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
51void tFormantShifter_init (tFormantShifter* const, int bufsize, int order);
52void tFormantShifter_free (tFormantShifter* const);
53
54float tFormantShifter_tick (tFormantShifter* const, float input, float fwarp);
55float tFormantShifter_remove (tFormantShifter* const, float input);
56float tFormantShifter_add (tFormantShifter* const, float input, float fwarp);
57void 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
LEAF/Inc/leaf-instruments.hrenamed from LEAF/Inc/leaf-808.h+7−7
@@ -1,13 +1,13 @@
1/*==============================================================================1/*==============================================================================
2 2
3 leaf-808.h3 leaf-instruments.h
4 Created: 30 Nov 2018 10:24:44am4 Created: 30 Nov 2018 10:24:44am
5 Author: airship5 Author: airship
6 6
7==============================================================================*/7==============================================================================*/
8 8
9#ifndef LEAF_808_H_INCLUDED9#ifndef LEAF_INSTRUMENTS_H_INCLUDED
10#define LEAF_808_H_INCLUDED10#define LEAF_INSTRUMENTS_H_INCLUDED
11 11
12#ifdef __cplusplus12#ifdef __cplusplus
13extern "C" {13extern "C" {
@@ -16,9 +16,9 @@ extern "C" { · 2 unmodified lines
16//==============================================================================16//==============================================================================
17 17
18#include "leaf-math.h"18#include "leaf-math.h"
19#include "leaf-oscillator.h"19#include "leaf-oscillators.h"
20#include "leaf-utilities.h"20#include "leaf-filters.h"
21#include "leaf-filter.h"21#include "leaf-envelopes.h"
22 22
23//==============================================================================23//==============================================================================
24 24
@@ -177,7 +177,7 @@ void t808Kick_setNoiseFilterQ (t808Kick* const, float noiseFilterQ) · 152 unmodified lines
177}177}
178#endif178#endif
179 179
180#endif // LEAF_808_H_INCLUDED180#endif // LEAF_INSTRUMENTS_H_INCLUDED
181 181
182//==============================================================================182//==============================================================================
183 183
LEAF/Inc/leaf-midi.h+29−1
@@ -18,10 +18,38 @@ extern "C" { · 17 unmodified lines
18#include "leaf-global.h"18#include "leaf-global.h"
19#include "leaf-mempool.h"19#include "leaf-mempool.h"
20#include "leaf-math.h"20#include "leaf-math.h"
21#include "leaf-utilities.h"21#include "leaf-envelopes.h"
22 22
23//==============================================================================23//==============================================================================
24 24
25// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
26
27// STACK implementation (fixed size)
28#define STACK_SIZE 128
29typedef 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
39void tStack_init (tStack* const);
40void tStack_free (tStack* const);
41
42void tStack_setCapacity (tStack* const, uint16_t cap);
43int tStack_addIfNotAlreadyThere (tStack* const, uint16_t item);
44void tStack_add (tStack* const, uint16_t item);
45int tStack_remove (tStack* const, uint16_t item);
46void tStack_clear (tStack* const);
47int tStack_first (tStack* const);
48int tStack_getSize (tStack* const);
49int tStack_contains (tStack* const, uint16_t item);
50int tStack_next (tStack* const);
51int tStack_get (tStack* const, int which);
52
25/* tPoly */53/* tPoly */
26typedef struct _tPoly54typedef struct _tPoly
27{55{
LEAF/Inc/leaf-oscillators.hrenamed from LEAF/Inc/leaf-oscillator.h+83−84
@@ -1,13 +1,13 @@
1/*==============================================================================1/*==============================================================================
2 2
3 leaf-oscillator.h3 leaf-oscillators.h
4 Created: 20 Jan 2017 12:00:58pm4 Created: 20 Jan 2017 12:00:58pm
5 Author: Michael R Mulshine5 Author: Michael R Mulshine
6 6
7==============================================================================*/7==============================================================================*/
8 8
9#ifndef LEAF_OSCILLATOR_H_INCLUDED9#ifndef LEAF_OSCILLATORS_H_INCLUDED
10#define LEAF_OSCILLATOR_H_INCLUDED10#define LEAF_OSCILLATORS_H_INCLUDED
11 11
12#ifdef __cplusplus12#ifdef __cplusplus
13extern "C" {13extern "C" {
@@ -16,68 +16,7 @@ extern "C" { · 2 unmodified lines
16//==============================================================================16//==============================================================================
17 17
18#include "leaf-math.h"18#include "leaf-math.h"
19 19#include "leaf-filters.h"
20#include "leaf-filter.h"
21
22//==============================================================================
23
24/* tNeuron */
25typedef enum NeuronMode
26{
27 NeuronNormal = 0,
28 NeuronTanh,
29 NeuronAaltoShaper,
30 NeuronModeNil
31} NeuronMode;
32
33typedef 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
50void tNeuron_init (tNeuron* const);
51void tNeuron_free (tNeuron* const);
52
53void tNeuron_reset (tNeuron* const);
54float tNeuron_Tick (tNeuron* const);
55void tNeuron_setMode (tNeuron* const, NeuronMode mode);
56void tNeuron_setCurrent (tNeuron* const, float current);
57void tNeuron_setK (tNeuron* const, float K);
58void tNeuron_setL (tNeuron* const, float L);
59void tNeuron_setN (tNeuron* const, float N);
60void tNeuron_setC (tNeuron* const, float C);
61void tNeuron_setV1 (tNeuron* const, float V1);
62void tNeuron_setV2 (tNeuron* const, float V2);
63void tNeuron_setV3 (tNeuron* const, float V3);
64void tNeuron_setTimeStep (tNeuron* const, float timestep);
65
66//==============================================================================
67
68/* tPhasor: Aliasing phasor [0.0, 1.0) */
69typedef struct _tPhasor
70{
71 float phase;
72 float inc,freq;
73
74} tPhasor;
75
76void tPhasor_init (tPhasor* const);
77void tPhasor_free (tPhasor* const);
78
79float tPhasor_tick (tPhasor* const);
80int tPhasor_setFreq (tPhasor* const, float freq);
81 20
82//==============================================================================21//==============================================================================
83 22
@@ -98,23 +37,6 @@ int tCycle_setFreq (tCycle* const, float freq); · 14 unmodified lines
98 37
99//==============================================================================38//==============================================================================
100 39
101/* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */
102typedef struct _tSawtooth
103{
104 // Underlying phasor
105 float phase;
106 float inc,freq;
107
108} tSawtooth;
109
110void tSawtooth_init (tSawtooth* const);
111void tSawtooth_free (tSawtooth* const);
112
113float tSawtooth_tick (tSawtooth* const);
114int tSawtooth_setFreq (tSawtooth* const, float freq);
115
116//==============================================================================
117
118/* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */40/* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */
119typedef struct _tTriangle41typedef struct _tTriangle
120{42{
@@ -146,6 +68,39 @@ void tSquare_free (tSquare* const); · 25 unmodified lines
146 68
147float tSquare_tick (tSquare* const);69float tSquare_tick (tSquare* const);
148int tSquare_setFreq (tSquare* const, float freq);70int tSquare_setFreq (tSquare* const, float freq);
71
72//==============================================================================
73
74/* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */
75typedef struct _tSawtooth
76{
77 // Underlying phasor
78 float phase;
79 float inc,freq;
80
81} tSawtooth;
82
83void tSawtooth_init (tSawtooth* const);
84void tSawtooth_free (tSawtooth* const);
85
86float tSawtooth_tick (tSawtooth* const);
87int tSawtooth_setFreq (tSawtooth* const, float freq);
88
89//==============================================================================
90
91/* tPhasor: Aliasing phasor [0.0, 1.0) */
92typedef struct _tPhasor
93{
94 float phase;
95 float inc,freq;
96
97} tPhasor;
98
99void tPhasor_init (tPhasor* const);
100void tPhasor_free (tPhasor* const);
101
102float tPhasor_tick (tPhasor* const);
103int tPhasor_setFreq (tPhasor* const, float freq);
149 104
150//==============================================================================105//==============================================================================
151 106
@@ -161,7 +116,7 @@ typedef struct _tNoise · 9 unmodified lines
161{116{
162 NoiseType type;117 NoiseType type;
163 float pinkb0, pinkb1, pinkb2;118 float pinkb0, pinkb1, pinkb2;
164 float(*rand)();119 float(*rand)(void);
165 120
166} tNoise;121} tNoise;
167 122
@@ -169,6 +124,50 @@ void tNoise_init (tNoise* const, NoiseType type); · 1 unmodified line
169void tNoise_free (tNoise* const);124void tNoise_free (tNoise* const);
170 125
171float tNoise_tick (tNoise* const);126float tNoise_tick (tNoise* const);
127
128//==============================================================================
129
130/* tNeuron */
131typedef enum NeuronMode
132{
133 NeuronNormal = 0,
134 NeuronTanh,
135 NeuronAaltoShaper,
136 NeuronModeNil
137} NeuronMode;
138
139typedef 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
156void tNeuron_init (tNeuron* const);
157void tNeuron_free (tNeuron* const);
158
159void tNeuron_reset (tNeuron* const);
160float tNeuron_Tick (tNeuron* const);
161void tNeuron_setMode (tNeuron* const, NeuronMode mode);
162void tNeuron_setCurrent (tNeuron* const, float current);
163void tNeuron_setK (tNeuron* const, float K);
164void tNeuron_setL (tNeuron* const, float L);
165void tNeuron_setN (tNeuron* const, float N);
166void tNeuron_setC (tNeuron* const, float C);
167void tNeuron_setV1 (tNeuron* const, float V1);
168void tNeuron_setV2 (tNeuron* const, float V2);
169void tNeuron_setV3 (tNeuron* const, float V3);
170void 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#endif176#endif
178 177
179#endif // LEAF_OSCILLATOR_H_INCLUDED178#endif // LEAF_OSCILLATORS_H_INCLUDED
180 179
181//==============================================================================180//==============================================================================
LEAF/Inc/leaf-oversampler.h+0−51
@@ -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
14extern "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
26typedef struct _tOversampler
27{
28 int ratio;
29 float* pCoeffs;
30 float* upState;
31 float* downState;
32 int numTaps;
33 int phaseLength;
34} tOversampler;
35
36void tOversampler_init(tOversampler* const, int order, oBool extraQuality);
37void tOversampler_free(tOversampler* const);
38void tOversampler_upsample(tOversampler* const, float input, float* output);
39float tOversampler_downsample(tOversampler *const os, float* input);
40float tOversampler_tick(tOversampler* const, float input, float (*effectTick)(float));
41int tOversampler_getLatency(tOversampler* const os);
42
43//==============================================================================
44
45#ifdef __cplusplus
46}
47#endif
48
49#endif // LEAF_OVERSAMPLER_H_INCLUDED
50
51//==============================================================================
LEAF/Inc/leaf-physical.h+221−0
@@ -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
15extern "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 */
31typedef 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
46void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]);
47void tPluck_free (tPluck* const);
48
49float tPluck_tick (tPluck* const);
50
51// Pluck the string.
52void tPluck_pluck (tPluck* const, float amplitude);
53
54// Start a note with the given frequency and amplitude.;
55void tPluck_noteOn (tPluck* const, float frequency, float amplitude );
56
57// Stop a note with the given amplitude (speed of decay).
58void tPluck_noteOff (tPluck* const, float amplitude );
59
60// Set instrument parameters for a particular frequency.
61void tPluck_setFrequency (tPluck* const, float frequency );
62
63// Perform the control change specified by \e number and \e value (0.0 - 128.0).
64void tPluck_controlChange (tPluck* const, int number, float value);
65
66// tPluck Utilities.
67float tPluck_getLastOut (tPluck* const);
68
69//==============================================================================
70
71/* Stif Karplus Strong model */
72typedef 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
95typedef enum SKControlType
96{
97 SKPickPosition = 0,
98 SKStringDamping,
99 SKDetune,
100 SKControlTypeNil
101} SKControlType;
102
103void tKarplusStrong_init (tKarplusStrong* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]);
104void tKarplusStrong_free (tKarplusStrong* const);
105
106float tKarplusStrong_tick (tKarplusStrong* const);
107
108// Pluck the string.
109void tKarplusStrong_pluck (tKarplusStrong* const, float amplitude);
110
111// Start a note with the given frequency and amplitude.;
112void tKarplusStrong_noteOn (tKarplusStrong* const, float frequency, float amplitude );
113
114// Stop a note with the given amplitude (speed of decay).
115void tKarplusStrong_noteOff (tKarplusStrong* const, float amplitude );
116
117// Set instrument parameters for a particular frequency.
118void 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.
122void tKarplusStrong_controlChange (tKarplusStrong* const, SKControlType type, float value);
123
124// Set the stretch "factor" of the string (0.0 - 1.0).
125void tKarplusStrong_setStretch (tKarplusStrong* const, float stretch );
126
127// Set the pluck or "excitation" position along the string (0.0 - 1.0).
128void tKarplusStrong_setPickupPosition (tKarplusStrong* const, float position );
129
130// Set the base loop gain.
131void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const, float aGain );
132
133// tKarplusStrong utilities.
134float tKarplusStrong_getLastOut (tKarplusStrong* const);
135
136// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
137
138/* Simple Living String */
139typedef 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
152void tSimpleLivingString_init (tSimpleLivingString* const, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode);
153void tSimpleLivingString_free (tSimpleLivingString* const);
154float tSimpleLivingString_tick (tSimpleLivingString* const, float input);
155float tSimpleLivingString_sample (tSimpleLivingString* const);
156int tSimpleLivingString_setFreq (tSimpleLivingString* const, float freq);
157int tSimpleLivingString_setWaveLength (tSimpleLivingString* const, float waveLength); // in samples
158int tSimpleLivingString_setDampFreq (tSimpleLivingString* const, float dampFreq);
159int tSimpleLivingString_setDecay (tSimpleLivingString* const, float decay); // should be near 1.0
160int tSimpleLivingString_setTargetLev (tSimpleLivingString* const, float targetLev);
161int tSimpleLivingString_setLevSmoothFactor (tSimpleLivingString* const, float levSmoothFactor);
162int tSimpleLivingString_setLevStrength (tSimpleLivingString* const, float levStrength);
163int tSimpleLivingString_setLevMode (tSimpleLivingString* const, int levMode);
164
165// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
166
167/* Living String */
168typedef 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
183void tLivingString_init (tLivingString* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay,
184 float targetLev, float levSmoothFactor, float levStrength, int levMode);
185void tLivingString_free (tLivingString* const);
186float tLivingString_tick (tLivingString* const, float input);
187float tLivingString_sample (tLivingString* const);
188int tLivingString_setFreq (tLivingString* const, float freq);
189int tLivingString_setWaveLength (tLivingString* const, float waveLength); // in samples
190int tLivingString_setPickPos (tLivingString* const, float pickPos);
191int tLivingString_setPrepIndex (tLivingString* const, float prepIndex);
192int tLivingString_setDampFreq (tLivingString* const, float dampFreq);
193int tLivingString_setDecay (tLivingString* const, float decay); // should be near 1.0
194int tLivingString_setTargetLev (tLivingString* const, float targetLev);
195int tLivingString_setLevSmoothFactor (tLivingString* const, float levSmoothFactor);
196int tLivingString_setLevStrength (tLivingString* const, float levStrength);
197int tLivingString_setLevMode (tLivingString* const, int levMode);
198
199// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
200
201//Reed Table - borrowed from STK
202typedef struct _tReedTable {
203 float offset, slope;
204} tReedTable;
205
206void tReedTable_init (tReedTable* const, float offset, float slope);
207void tReedTable_free (tReedTable* const);
208float tReedTable_tick (tReedTable* const, float input);
209float tReedTable_tanh_tick (tReedTable* const p, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code
210void tReedTable_setOffset (tReedTable* const, float offset);
211void tReedTable_setSlope (tReedTable* const, float slope);
212
213//==============================================================================
214
215#ifdef __cplusplus
216}
217#endif
218
219#endif // LEAF_PHYSICAL_H_INCLUDED
220
221//==============================================================================
LEAF/Inc/leaf-pitch.h+0−161
@@ -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
15extern "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
39typedef 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
68void tPitchShifter_init (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize);
69void tPitchShifter_free (tPitchShifter* const);
70
71float tPitchShifter_tick (tPitchShifter* const, float sample);
72float tPitchShifterToFreq_tick (tPitchShifter* const, float sample, float freq);
73float tPitchShifterToFunc_tick (tPitchShifter* const, float sample, float (*fun)(float));
74void tPitchShifter_ioSamples_toFreq (tPitchShifter* const, float* in, float* out, int size, float toFreq);
75void tPitchShifter_ioSamples_toPeriod(tPitchShifter* const, float* in, float* out, int size, float toPeriod);
76void tPitchShifter_ioSamples_toFunc (tPitchShifter* const, float* in, float* out, int size, float (*fun)(float));
77void tPitchShifter_setPitchFactor (tPitchShifter* const, float pf);
78void tPitchShifter_setTimeConstant (tPitchShifter* const, float tc);
79void tPitchShifter_setHopSize (tPitchShifter* const, int hs);
80void tPitchShifter_setWindowSize (tPitchShifter* const, int ws);
81float tPitchShifter_getPeriod (tPitchShifter* const);
82
83//==============================================================================
84
85// Period detection
86typedef 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
115void tPeriod_init (tPeriod* const, float* in, float* out, int bufSize, int frameSize);
116void tPeriod_free (tPeriod* const);
117
118float tPeriod_findPeriod (tPeriod* const, float sample);
119void tPeriod_setHopSize (tPeriod* p, int hs);
120void tPeriod_setWindowSize (tPeriod* p, int ws);
121
122//==============================================================================
123
124// Pitch shift
125typedef 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
145void tPitchShift_init (tPitchShift* const, tPeriod* const, float* out, int bufSize);
146void tPitchShift_free (tPitchShift* const);
147
148float tPitchShift_shift (tPitchShift* const);
149float tPitchShift_shiftToFunc (tPitchShift* const, float (*fun)(float));
150float tPitchShift_shiftToFreq (tPitchShift* const, float freq);
151void tPitchShift_setPitchFactor (tPitchShift* const, float pf);
152
153//==============================================================================
154
155#ifdef __cplusplus
156}
157#endif
158
159#endif // LEAF_PITCH_H_INCLUDED
160
161//==============================================================================
LEAF/Inc/leaf-reverb.h+29−30
@@ -17,15 +17,14 @@ extern "C" { · 16 unmodified lines
17 17
18#include "leaf-global.h"18#include "leaf-global.h"
19#include "leaf-math.h"19#include "leaf-math.h"
20
21#include "leaf-delay.h"20#include "leaf-delay.h"
22#include "leaf-filter.h"21#include "leaf-filters.h"
23#include "leaf-oscillator.h"22#include "leaf-oscillators.h"
24 23
25//==============================================================================24//==============================================================================
26 25
27/* PRCRev: Reverb, reimplemented from STK (Cook and Scavone). */26/* PRCReverb: Reverb, reimplemented from STK (Cook and Scavone). */
28typedef struct _tPRCRev27typedef struct _tPRCReverb
29{28{
30 float mix, t60;29 float mix, t60;
31 30
@@ -38,23 +37,23 @@ typedef struct _tPRCRev · 6 unmodified lines
38 37
39 float lastIn, lastOut;38 float lastIn, lastOut;
40 39
41} tPRCRev;40} tPRCReverb;
42 41
43void tPRCRev_init (tPRCRev* const, float t60);42void tPRCReverb_init (tPRCReverb* const, float t60);
44void tPRCRev_free (tPRCRev* const);43void tPRCReverb_free (tPRCReverb* const);
45 44
46float tPRCRev_tick (tPRCRev* const, float input);45float tPRCReverb_tick (tPRCReverb* const, float input);
47 46
48// Set reverb time in seconds.47// Set reverb time in seconds.
49void tPRCRev_setT60 (tPRCRev* const, float t60);48void tPRCReverb_setT60 (tPRCReverb* const, float t60);
50 49
51// Set mix between dry input and wet output signal.50// Set mix between dry input and wet output signal.
52void tPRCRev_setMix (tPRCRev* const, float mix);51void tPRCReverb_setMix (tPRCReverb* const, float mix);
53 52
54//==============================================================================53//==============================================================================
55 54
56/* NRev: Reverb, reimplemented from STK (Cook and Scavone). */55/* NReverb: Reverb, reimplemented from STK (Cook and Scavone). */
57typedef struct _tNRev56typedef struct _tNReverb
58{57{
59 float mix, t60;58 float mix, t60;
60 59
@@ -68,22 +67,22 @@ typedef struct _tNRev · 7 unmodified lines
68 67
69 float lastIn, lastOut;68 float lastIn, lastOut;
70 69
71} tNRev;70} tNReverb;
72 71
73void tNRev_init (tNRev* const, float t60);72void tNReverb_init (tNReverb* const, float t60);
74void tNRev_free (tNRev* const);73void tNReverb_free (tNReverb* const);
75 74
76float tNRev_tick (tNRev* const, float input);75float tNReverb_tick (tNReverb* const, float input);
77 76
78// Set reverb time in seconds.77// Set reverb time in seconds.
79void tNRev_setT60 (tNRev* const, float t60);78void tNReverb_setT60 (tNReverb* const, float t60);
80 79
81// Set mix between dry input and wet output signal.80// Set mix between dry input and wet output signal.
82void tNRev_setMix (tNRev* const, float mix);81void tNReverb_setMix (tNReverb* const, float mix);
83 82
84//==============================================================================83//==============================================================================
85 84
86typedef struct _tDattorro85typedef struct _tDattorroReverb
87{86{
88 float predelay;87 float predelay;
89 float input_filter;88 float input_filter;
@@ -125,19 +124,19 @@ typedef struct _tDattorro · 35 unmodified lines
125 124
126 tCycle f2_lfo;125 tCycle f2_lfo;
127 126
128} tDattorro;127} tDattorroReverb;
129 128
130void tDattorro_init (tDattorro* const);129void tDattorroReverb_init (tDattorroReverb* const);
131void tDattorro_free (tDattorro* const);130void tDattorroReverb_free (tDattorroReverb* const);
132 131
133float tDattorro_tick (tDattorro* const, float input);132float tDattorroReverb_tick (tDattorroReverb* const, float input);
134 133
135void tDattorro_setMix (tDattorro* const, float mix);134void tDattorroReverb_setMix (tDattorroReverb* const, float mix);
136void tDattorro_setSize (tDattorro* const, float size);135void tDattorroReverb_setSize (tDattorroReverb* const, float size);
137void tDattorro_setInputDelay (tDattorro* const, float preDelay);136void tDattorroReverb_setInputDelay (tDattorroReverb* const, float preDelay);
138void tDattorro_setInputFilter (tDattorro* const, float freq);137void tDattorroReverb_setInputFilter (tDattorroReverb* const, float freq);
139void tDattorro_setFeedbackFilter (tDattorro* const, float freq);138void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const, float freq);
140void tDattorro_setFeedbackGain (tDattorro* const, float gain);139void tDattorroReverb_setFeedbackGain (tDattorroReverb* const, float gain);
141 140
142#ifdef __cplusplus141#ifdef __cplusplus
143}142}
LEAF/Inc/leaf-sample.h+0−125
@@ -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
14extern "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//==============================================================================
LEAF/Inc/leaf-sampling.h+124−0
@@ -0,0 +1,124 @@
1/*==============================================================================
2
3leaf-sampling.h
4Created: 23 Jan 2019 11:22:09am
5Author: Mike Mulshine
6
7==============================================================================*/
8
9
10#ifndef LEAF_SAMPLING_H_INCLUDED
11#define LEAF_SAMPLING_H_INCLUDED
12
13#ifdef __cplusplus
14extern "C" {
15#endif
16
17//==============================================================================
18
19#include "leaf-global.h"
20#include "leaf-math.h"
21#include "leaf-envelopes.h"
22
23//==============================================================================
24
25typedef enum RecordMode
26{
27 RecordOneShot = 0,
28 RecordLoop,
29 RecordModeNil
30} RecordMode;
31
32typedef 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
45void tBuffer_init (tBuffer* const, uint32_t length);
46void tBuffer_free (tBuffer* const);
47
48void tBuffer_tick (tBuffer* const, float sample);
49
50void tBuffer_read(tBuffer* const, float* buff, uint32_t len);
51
52float tBuffer_get (tBuffer* const, int idx);
53
54void tBuffer_record (tBuffer* const);
55void tBuffer_stop (tBuffer* const);
56
57void tBuffer_setRecordMode (tBuffer* const, RecordMode mode);
58
59void tBuffer_clear (tBuffer* const);
60
61//==============================================================================
62
63typedef enum PlayMode
64{
65 PlayNormal,
66 PlayLoop,
67 PlayBackAndForth,
68 PlayModeNil
69} PlayMode;
70
71typedef 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
97void tSampler_init (tSampler* const, tBuffer* const);
98void tSampler_free (tSampler* const);
99
100float tSampler_tick (tSampler* const);
101
102void tSampler_setSample (tSampler* const, tBuffer* s);
103
104void tSampler_setMode (tSampler* const, PlayMode mode);
105
106void tSampler_play (tSampler* const);
107void tSampler_stop (tSampler* const);
108
109void tSampler_setStart (tSampler* const, int32_t start);
110void tSampler_setEnd (tSampler* const, int32_t end);
111
112void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length);
113
114void tSampler_setRate (tSampler* const, float rate);
115
116//==============================================================================
117
118#ifdef __cplusplus
119}
120#endif
121
122#endif // LEAF_SAMPLING_H_INCLUDED
123
124//==============================================================================
LEAF/Inc/leaf-string.h+0−143
@@ -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
15extern "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 */
30typedef 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
45void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]);
46void tPluck_free (tPluck* const);
47
48float tPluck_tick (tPluck* const);
49
50// Pluck the string.
51void tPluck_pluck (tPluck* const, float amplitude);
52
53// Start a note with the given frequency and amplitude.;
54void tPluck_noteOn (tPluck* const, float frequency, float amplitude );
55
56// Stop a note with the given amplitude (speed of decay).
57void tPluck_noteOff (tPluck* const, float amplitude );
58
59// Set instrument parameters for a particular frequency.
60void tPluck_setFrequency (tPluck* const, float frequency );
61
62// Perform the control change specified by \e number and \e value (0.0 - 128.0).
63void tPluck_controlChange (tPluck* const, int number, float value);
64
65// tPluck Utilities.
66float tPluck_getLastOut (tPluck* const);
67
68//==============================================================================
69
70/* Stif Karplus Strong model */
71typedef 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
94typedef enum SKControlType
95{
96 SKPickPosition = 0,
97 SKStringDamping,
98 SKDetune,
99 SKControlTypeNil
100} SKControlType;
101
102void tStifKarp_init (tStifKarp* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]);
103void tStifKarp_free (tStifKarp* const);
104
105float tStifKarp_tick (tStifKarp* const);
106
107// Pluck the string.
108void tStifKarp_pluck (tStifKarp* const, float amplitude);
109
110// Start a note with the given frequency and amplitude.;
111void tStifKarp_noteOn (tStifKarp* const, float frequency, float amplitude );
112
113// Stop a note with the given amplitude (speed of decay).
114void tStifKarp_noteOff (tStifKarp* const, float amplitude );
115
116// Set instrument parameters for a particular frequency.
117void 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.
121void tStifKarp_controlChange (tStifKarp* const, SKControlType type, float value);
122
123// Set the stretch "factor" of the string (0.0 - 1.0).
124void tStifKarp_setStretch (tStifKarp* const, float stretch );
125
126// Set the pluck or "excitation" position along the string (0.0 - 1.0).
127void tStifKarp_setPickupPosition (tStifKarp* const, float position );
128
129// Set the base loop gain.
130void tStifKarp_setBaseLoopGain (tStifKarp* const, float aGain );
131
132// tStifKarp utilities.
133float tStifKarp_getLastOut (tStifKarp* const);
134
135//==============================================================================
136
137#ifdef __cplusplus
138}
139#endif
140
141#endif // LEAF_STRING_H_INCLUDED
142
143//==============================================================================
LEAF/Inc/leaf-tables.h+3−3
@@ -6,8 +6,8 @@ · 5 unmodified lines
6 6
7==============================================================================*/7==============================================================================*/
8 8
9#ifndef LEAF_WAVETABLES_H_INCLUDED9#ifndef LEAF_TABLES_H_INCLUDED
10#define LEAF_WAVETABLES_H_INCLUDED10#define LEAF_TABLES_H_INCLUDED
11 11
12#ifdef __cplusplus12#ifdef __cplusplus
13extern "C" {13extern "C" {
@@ -95,6 +95,6 @@ extern const float squarewave[11][SQR_TABLE_SIZE]; · 81 unmodified lines
95}95}
96#endif96#endif
97 97
98#endif // LEAF_WAVETABLES_H_INCLUDED98#endif // LEAF_TABLES_H_INCLUDED
99 99
100//==============================================================================100//==============================================================================
LEAF/Inc/leaf-utilities.h+0−483
@@ -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
15extern "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
28typedef 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
38void tStack_init (tStack* const);
39void tStack_free (tStack* const);
40
41void tStack_setCapacity (tStack* const, uint16_t cap);
42int tStack_addIfNotAlreadyThere (tStack* const, uint16_t item);
43void tStack_add (tStack* const, uint16_t item);
44int tStack_remove (tStack* const, uint16_t item);
45void tStack_clear (tStack* const);
46int tStack_first (tStack* const);
47int tStack_getSize (tStack* const);
48int tStack_contains (tStack* const, uint16_t item);
49int tStack_next (tStack* const);
50int tStack_get (tStack* const, int which);
51
52// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
53
54/* Ramp */
55typedef 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
65void tRamp_init (tRamp* const, float time, int samplesPerTick);
66void tRamp_free (tRamp* const);
67
68float tRamp_tick (tRamp* const);
69float tRamp_sample (tRamp* const);
70int tRamp_setTime (tRamp* const, float time);
71int tRamp_setDest (tRamp* const, float dest);
72int tRamp_setVal (tRamp* const, float val);
73
74// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
75
76/* Exponential Smoother */
77typedef struct _tExpSmooth {
78 float factor, oneminusfactor;
79 float curr,dest;
80
81} tExpSmooth;
82
83void tExpSmooth_init (tExpSmooth* const, float val, float factor);
84void tExpSmooth_free (tExpSmooth* const);
85
86float tExpSmooth_tick (tExpSmooth* const);
87float tExpSmooth_sample (tExpSmooth* const);
88int tExpSmooth_setFactor (tExpSmooth* const, float factor);
89int tExpSmooth_setDest (tExpSmooth* const, float dest);
90int tExpSmooth_setVal (tExpSmooth* const, float val);
91
92// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
93
94/* PowerEnvelopeFollower */
95typedef struct _tPwrFollow {
96 float factor, oneminusfactor;
97 float curr;
98
99} tPwrFollow;
100
101void tPwrFollow_init (tPwrFollow* const, float factor);
102void tPwrFollow_free (tPwrFollow* const);
103float tPwrFollow_tick (tPwrFollow* const, float input);
104float tPwrFollow_sample (tPwrFollow* const);
105int tPwrFollow_setFactor (tPwrFollow* const, float factor);
106
107// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
108
109//Reed Table - borrowed from STK
110typedef struct _tReedTable {
111 float offset, slope;
112} tReedTable;
113
114void tReedTable_init (tReedTable* const, float offset, float slope);
115void tReedTable_free (tReedTable* const);
116float tReedTable_tick (tReedTable* const, float input);
117float tReedTable_tanh_tick (tReedTable* const p, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code
118void tReedTable_setOffset (tReedTable* const, float offset);
119void 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
131typedef 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
140void tFBleveller_init (tFBleveller* const, float targetLevel, float factor, float strength, int mode);
141void tFBleveller_free (tFBleveller* const);
142
143float tFBleveller_tick (tFBleveller* const, float input);
144float tFBleveller_sample (tFBleveller* const);
145int tFBleveller_setTargetLevel (tFBleveller* const, float TargetLevel);
146int tFBleveller_setFactor (tFBleveller* const, float factor);
147int tFBleveller_setMode (tFBleveller* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting
148int tFBleveller_setStrength (tFBleveller* const, float strength);
149
150// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
151
152/* Simple Living String */
153typedef 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
166void tSimpleLivingString_init (tSimpleLivingString* const, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode);
167void tSimpleLivingString_free (tSimpleLivingString* const);
168float tSimpleLivingString_tick (tSimpleLivingString* const, float input);
169float tSimpleLivingString_sample (tSimpleLivingString* const);
170int tSimpleLivingString_setFreq (tSimpleLivingString* const, float freq);
171int tSimpleLivingString_setWaveLength (tSimpleLivingString* const, float waveLength); // in samples
172int tSimpleLivingString_setDampFreq (tSimpleLivingString* const, float dampFreq);
173int tSimpleLivingString_setDecay (tSimpleLivingString* const, float decay); // should be near 1.0
174int tSimpleLivingString_setTargetLev (tSimpleLivingString* const, float targetLev);
175int tSimpleLivingString_setLevSmoothFactor (tSimpleLivingString* const, float levSmoothFactor);
176int tSimpleLivingString_setLevStrength (tSimpleLivingString* const, float levStrength);
177int tSimpleLivingString_setLevMode (tSimpleLivingString* const, int levMode);
178
179
180// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
181
182/* Living String */
183typedef 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
198void tLivingString_init (tLivingString* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay,
199 float targetLev, float levSmoothFactor, float levStrength, int levMode);
200void tLivingString_free (tLivingString* const);
201float tLivingString_tick (tLivingString* const, float input);
202float tLivingString_sample (tLivingString* const);
203int tLivingString_setFreq (tLivingString* const, float freq);
204int tLivingString_setWaveLength (tLivingString* const, float waveLength); // in samples
205int tLivingString_setPickPos (tLivingString* const, float pickPos);
206int tLivingString_setPrepIndex (tLivingString* const, float prepIndex);
207int tLivingString_setDampFreq (tLivingString* const, float dampFreq);
208int tLivingString_setDecay (tLivingString* const, float decay); // should be near 1.0
209int tLivingString_setTargetLev (tLivingString* const, float targetLev);
210int tLivingString_setLevSmoothFactor (tLivingString* const, float levSmoothFactor);
211int tLivingString_setLevStrength (tLivingString* const, float levStrength);
212int tLivingString_setLevMode (tLivingString* const, int levMode);
213
214
215// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
216
217/* Compressor */
218typedef 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
229void tCompressor_init (tCompressor* const);
230void tCompressor_free (tCompressor* const);
231float tCompressor_tick (tCompressor* const, float input);
232
233// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
234
235/* Attack-Decay envelope */
236typedef 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
256void tEnvelope_init (tEnvelope* const, float attack, float decay, oBool loop);
257void tEnvelope_free (tEnvelope* const);
258
259float tEnvelope_tick (tEnvelope* const);
260int tEnvelope_setAttack (tEnvelope* const, float attack);
261int tEnvelope_setDecay (tEnvelope* const, float decay);
262int tEnvelope_loop (tEnvelope* const, oBool loop);
263int tEnvelope_on (tEnvelope* const, float velocity);
264
265// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
266
267/* ADSR */
268typedef 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
286void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release);
287void tADSR_free (tADSR* const);
288
289float tADSR_tick (tADSR* const);
290int tADSR_setAttack (tADSR* const, float attack);
291int tADSR_setDecay (tADSR* const, float decay);
292int tADSR_setSustain(tADSR* const, float sustain);
293int tADSR_setRelease(tADSR* const, float release);
294int tADSR_on (tADSR* const, float velocity);
295int tADSR_off (tADSR* const);
296
297// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
298
299/* Envelope Follower */
300typedef struct _tEnvelopeFollower
301{
302 float y;
303 float a_thresh;
304 float d_coeff;
305
306} tEnvelopeFollower;
307
308void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff);
309void tEnvelopeFollower_free (tEnvelopeFollower* const);
310
311float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x);
312int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff);
313int 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
323typedef 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
344void tAtkDtk_init (tAtkDtk* const, int blocksize);
345void tAtkDtk_init_expanded (tAtkDtk* const, int blocksize, int atk, int rel);
346void tAtkDtk_free (tAtkDtk* const);
347
348// set expected input blocksize
349void tAtkDtk_setBlocksize (tAtkDtk* const, int size);
350
351// change atkDetector sample rate
352void tAtkDtk_setSamplerate (tAtkDtk* const, int inRate);
353
354// set attack time and coeff
355void tAtkDtk_setAtk (tAtkDtk* const, int inAtk);
356
357// set release time and coeff
358void tAtkDtk_setRel (tAtkDtk* const, int inRel);
359
360// set level above which values are identified as attacks
361void tAtkDtk_setThreshold (tAtkDtk* const, float thres);
362
363// find largest transient in input block, return index of attack
364int 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
374typedef 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
388void tEnv_init (tEnv* const, int windowSize, int hopSize, int blockSize);
389void tEnv_free (tEnv* const);
390float tEnv_tick (tEnv* const);
391void 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
403typedef 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
418void tSOLAD_init (tSOLAD* const);
419void tSOLAD_free (tSOLAD* const);
420
421// send one block of input samples, receive one block of output samples
422void tSOLAD_ioSamples (tSOLAD *w, float* in, float* out, int blocksize);
423
424// set periodicity analysis data
425void tSOLAD_setPeriod (tSOLAD *w, float period);
426
427// set pitch factor between 0.25 and 4
428void tSOLAD_setPitchFactor (tSOLAD *w, float pitchfactor);
429
430// force readpointer lag
431void tSOLAD_setReadLag (tSOLAD *w, float readlag);
432
433// reset state variables
434void 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
445typedef 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
463void tSNAC_init (tSNAC* const, int overlaparg); // constructor
464void tSNAC_free (tSNAC* const); // destructor
465
466void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size);
467void tSNAC_setOverlap (tSNAC *s, int lap);
468void tSNAC_setBias (tSNAC *s, float bias);
469void tSNAC_setMinRMS (tSNAC *s, float rms);
470
471/*To get freq, perform SAMPLE_RATE/snac_getperiod() */
472float tSNAC_getPeriod (tSNAC *s);
473float tSNAC_getfidelity (tSNAC *s);
474
475// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
476
477#ifdef __cplusplus
478}
479#endif
480
481#endif // LEAFUTILITIES_H_INCLUDED
482
483
LEAF/Inc/leaf-vocoder.h+0−89
@@ -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
13extern "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
26typedef 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
45void tTalkbox_init (tTalkbox* const, int bufsize);
46void tTalkbox_free (tTalkbox* const);
47float tTalkbox_tick (tTalkbox* const, float synth, float voice);
48void tTalkbox_update (tTalkbox* const);
49void tTalkbox_suspend (tTalkbox* const);
50void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g);
51void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o);
52void tTalkbox_setQuality (tTalkbox* const, float quality);
53
54//==============================================================================
55
56/* tVocoder */
57#define NUM_VOCODER_PARAM 8
58#define NBANDS 16
59
60typedef 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
75void tVocoder_init (tVocoder* const);
76void tVocoder_free (tVocoder* const);
77float tVocoder_tick (tVocoder* const, float synth, float voice);
78void tVocoder_update (tVocoder* const);
79void tVocoder_suspend (tVocoder* const);
80
81//==============================================================================
82
83#ifdef __cplusplus
84}
85#endif
86
87#endif // LEAF_VOCODER_H_INCLUDED
88
89//==============================================================================
LEAF/Inc/leaf-wavefolder.h+0−48
@@ -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
14extern "C" {
15#endif
16
17//==============================================================================
18
19#include "leaf-global.h"
20#include "leaf-math.h"
21
22//==============================================================================
23
24/* tLockhartWavefolder */
25
26typedef struct _tLockhartWavefolder
27{
28 double Ln1;
29 double Fn1;
30 float xn1;
31
32} tLockhartWavefolder;
33
34void tLockhartWavefolder_init (tLockhartWavefolder* const);
35void tLockhartWavefolder_free (tLockhartWavefolder* const);
36
37float 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//==============================================================================
LEAF/Src/leaf-analysis.c+733−0
@@ -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
25void 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
32void tEnvelopeFollower_free(tEnvelopeFollower* const e)
33{
34
35}
36
37float 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
52int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff)
53{
54 return ef->d_coeff = decayCoeff;
55}
56
57int 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//===========================================================================
69void 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
76void tPowerFollower_free(tPowerFollower* const p)
77{
78
79}
80
81int 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
90float 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
96float tPowerFollower_sample(tPowerFollower* const p)
97{
98 return p->curr;
99}
100
101
102
103
104//===========================================================================
105/* ---------------- env~ - simple envelope follower. ----------------- */
106//===========================================================================
107
108void 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
148void tEnvPD_free (tEnvPD* const x)
149{
150
151}
152
153float tEnvPD_tick (tEnvPD* const x)
154{
155 return powtodb(x->x_result);
156}
157
158void 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**********/
197static void atkdtk_init(tAttackDetection* const a, int blocksize, int atk, int rel);
198static void atkdtk_envelope(tAttackDetection* const a, float *in);
199
200/********Constructor/Destructor***************/
201
202void tAttackDetection_init(tAttackDetection* const a, int blocksize)
203{
204 atkdtk_init(a, blocksize, DEFATTACK, DEFRELEASE);
205}
206
207void tAttackDetection_init_expanded(tAttackDetection* const a, int blocksize, int atk, int rel)
208{
209 atkdtk_init(a, blocksize, atk, rel);
210}
211
212void tAttackDetection_free(tAttackDetection *a)
213{
214
215}
216
217/*******Public Functions***********/
218
219
220void 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
231void 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
242void tAttackDetection_setThreshold(tAttackDetection* const a, float thres)
243{
244 a->threshold = thres;
245 return;
246}
247
248void 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
256void 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
265int 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
284static 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
298static 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//===========================================================================
316void 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
339void tPeriodDetection_free (tPeriodDetection* const p)
340{
341 tEnvPD_free(&p->env);
342 tSNAC_free(&p->snac);
343}
344
345float 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
378void tPeriodDetection_setHopSize(tPeriodDetection* p, int hs)
379{
380 p->hopSize = hs;
381}
382
383void 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
406static void snac_analyzeframe(tSNAC* const s);
407static void snac_autocorrelation(tSNAC* const s);
408static void snac_normalize(tSNAC* const s);
409static void snac_pickpeak(tSNAC* const s);
410static void snac_periodandfidelity(tSNAC* const s);
411static void snac_biasbuf(tSNAC* const s);
412static float snac_spectralpeak(tSNAC* const s, float periodlength);
413
414
415/******************************************************************************/
416/******************************** constructor, destructor *********************/
417/******************************************************************************/
418
419
420void 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
439void 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
451void 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
471void 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
478void 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
488void 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
497float tSNAC_getPeriod(tSNAC* const s)
498{
499 return(s->periodlength);
500}
501
502
503float tSNAC_getFidelity(tSNAC* const s)
504{
505 return(s->fidelity);
506}
507
508
509/******************************************************************************/
510/***************************** private procedures *****************************/
511/******************************************************************************/
512
513
514// main analysis function
515static 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
544static 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
577static 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
614static 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
630static 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
672static 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
716static 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
LEAF/Src/leaf-crusher.c+0−84
@@ -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
23void 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
33void tCrusher_free (tCrusher* const c)
34{
35
36}
37
38float 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
60void tCrusher_setOperation (tCrusher* const c, float op)
61{
62 c->op = (uint32_t) (op * 8.0f);
63}
64
65// 0.0 - 1.0
66void 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
76void tCrusher_setRound (tCrusher* const c, float rnd)
77{
78 c->rnd = fabsf(rnd);
79}
80
81void tCrusher_setSamplingRatio (tCrusher* const c, float ratio)
82{
83 c->srr = ratio;
84}
LEAF/Src/leaf-delay.c+30−30
@@ -127,8 +127,8 @@ float tDelay_getGain (tDelay* const d) · 126 unmodified lines
127 return d->gain;127 return d->gain;
128}128}
129 129
130// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayL ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //130// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ LinearDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
131void tDelayL_init (tDelayL* const d, float delay, uint32_t maxDelay)131void tLinearDelay_init (tLinearDelay* const d, float delay, uint32_t maxDelay)
132{132{
133 d->maxDelay = maxDelay;133 d->maxDelay = maxDelay;
134 134
@@ -146,15 +146,15 @@ void tDelayL_init (tDelayL* const d, float delay, uint32_t maxDelay) · 11 unmodified lines
146 d->inPoint = 0;146 d->inPoint = 0;
147 d->outPoint = 0;147 d->outPoint = 0;
148 148
149 tDelayL_setDelay(d, d->delay);149 tLinearDelay_setDelay(d, d->delay);
150}150}
151 151
152void tDelayL_free(tDelayL* const d)152void tLinearDelay_free(tLinearDelay* const d)
153{153{
154 leaf_free(d->buff);154 leaf_free(d->buff);
155}155}
156 156
157float tDelayL_tick (tDelayL* const d, float input)157float tLinearDelay_tick (tLinearDelay* const d, float input)
158{158{
159 d->buff[d->inPoint] = input * d->gain;159 d->buff[d->inPoint] = input * d->gain;
160 160
@@ -176,7 +176,7 @@ float tDelayL_tick (tDelayL* const d, float input) · 15 unmodified lines
176 return d->lastOut;176 return d->lastOut;
177}177}
178 178
179void tDelayL_tickIn (tDelayL* const d, float input)179void tLinearDelay_tickIn (tLinearDelay* const d, float input)
180{180{
181 d->buff[d->inPoint] = input * d->gain;181 d->buff[d->inPoint] = input * d->gain;
182 182
@@ -184,7 +184,7 @@ void tDelayL_tickIn (tDelayL* const d, float input) · 1 unmodified line
184 if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;184 if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
185}185}
186 186
187float tDelayL_tickOut (tDelayL* const d)187float tLinearDelay_tickOut (tLinearDelay* const d)
188{188{
189 uint32_t idx = (uint32_t) d->outPoint;189 uint32_t idx = (uint32_t) d->outPoint;
190 190
@@ -200,7 +200,7 @@ float tDelayL_tickOut (tDelayL* const d) · 9 unmodified lines
200 return d->lastOut;200 return d->lastOut;
201}201}
202 202
203int tDelayL_setDelay (tDelayL* const d, float delay)203int tLinearDelay_setDelay (tLinearDelay* const d, float delay)
204{204{
205 d->delay = LEAF_clip(0.0f, delay, d->maxDelay);205 d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
206 206
@@ -219,7 +219,7 @@ int tDelayL_setDelay (tDelayL* const d, float delay) · 12 unmodified lines
219 return 0;219 return 0;
220}220}
221 221
222float tDelayL_tapOut (tDelayL* const d, float tapDelay)222float tLinearDelay_tapOut (tLinearDelay* const d, float tapDelay)
223{223{
224 float tap = (float) d->inPoint - tapDelay - 1.f;224 float tap = (float) d->inPoint - tapDelay - 1.f;
225 225
@@ -244,7 +244,7 @@ float tDelayL_tapOut (tDelayL* const d, float tapDelay) · 18 unmodified lines
244 244
245}245}
246 246
247void tDelayL_tapIn (tDelayL* const d, float value, uint32_t tapDelay)247void tLinearDelay_tapIn (tLinearDelay* const d, float value, uint32_t tapDelay)
248{248{
249 int32_t tap = d->inPoint - tapDelay - 1;249 int32_t tap = d->inPoint - tapDelay - 1;
250 250
@@ -254,7 +254,7 @@ void tDelayL_tapIn (tDelayL* const d, float value, uint32_t tapDelay) · 3 unmodified lines
254 d->buff[tap] = value;254 d->buff[tap] = value;
255}255}
256 256
257float tDelayL_addTo (tDelayL* const d, float value, uint32_t tapDelay)257float tLinearDelay_addTo (tLinearDelay* const d, float value, uint32_t tapDelay)
258{258{
259 int32_t tap = d->inPoint - tapDelay - 1;259 int32_t tap = d->inPoint - tapDelay - 1;
260 260
@@ -264,34 +264,34 @@ float tDelayL_addTo (tDelayL* const d, float value, uint32_t tapDelay) · 3 unmodified lines
264 return (d->buff[tap] += value);264 return (d->buff[tap] += value);
265}265}
266 266
267float tDelayL_getDelay (tDelayL *d)267float tLinearDelay_getDelay (tLinearDelay *d)
268{268{
269 return d->delay;269 return d->delay;
270}270}
271 271
272float tDelayL_getLastOut (tDelayL* const d)272float tLinearDelay_getLastOut (tLinearDelay* const d)
273{273{
274 return d->lastOut;274 return d->lastOut;
275}275}
276 276
277float tDelayL_getLastIn (tDelayL* const d)277float tLinearDelay_getLastIn (tLinearDelay* const d)
278{278{
279 return d->lastIn;279 return d->lastIn;
280}280}
281 281
282void tDelayL_setGain (tDelayL* const d, float gain)282void tLinearDelay_setGain (tLinearDelay* const d, float gain)
283{283{
284 if (gain < 0.0f) d->gain = 0.0f;284 if (gain < 0.0f) d->gain = 0.0f;
285 else d->gain = gain;285 else d->gain = gain;
286}286}
287 287
288float tDelayL_getGain (tDelayL* const d)288float tLinearDelay_getGain (tLinearDelay* const d)
289{289{
290 return d->gain;290 return d->gain;
291}291}
292 292
293// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayA ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //293// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ AllpassDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
294void tDelayA_init (tDelayA* const d, float delay, uint32_t maxDelay)294void tAllpassDelay_init (tAllpassDelay* const d, float delay, uint32_t maxDelay)
295{295{
296 d->maxDelay = maxDelay;296 d->maxDelay = maxDelay;
297 297
@@ -309,17 +309,17 @@ void tDelayA_init (tDelayA* const d, float delay, uint32_t maxDelay) · 11 unmodified lines
309 d->inPoint = 0;309 d->inPoint = 0;
310 d->outPoint = 0;310 d->outPoint = 0;
311 311
312 tDelayA_setDelay(d, d->delay);312 tAllpassDelay_setDelay(d, d->delay);
313 313
314 d->apInput = 0.0f;314 d->apInput = 0.0f;
315}315}
316 316
317void tDelayA_free(tDelayA* const d)317void tAllpassDelay_free(tAllpassDelay* const d)
318{318{
319 leaf_free(d->buff);319 leaf_free(d->buff);
320}320}
321 321
322float tDelayA_tick (tDelayA* const d, float input)322float tAllpassDelay_tick (tAllpassDelay* const d, float input)
323{323{
324 d->buff[d->inPoint] = input * d->gain;324 d->buff[d->inPoint] = input * d->gain;
325 325
@@ -340,7 +340,7 @@ float tDelayA_tick (tDelayA* const d, float input) · 14 unmodified lines
340 return d->lastOut;340 return d->lastOut;
341}341}
342 342
343int tDelayA_setDelay (tDelayA* const d, float delay)343int tAllpassDelay_setDelay (tAllpassDelay* const d, float delay)
344{344{
345 d->delay = LEAF_clip(0.5f, delay, d->maxDelay);345 d->delay = LEAF_clip(0.5f, delay, d->maxDelay);
346 346
@@ -373,7 +373,7 @@ int tDelayA_setDelay (tDelayA* const d, float delay) · 26 unmodified lines
373 return 0;373 return 0;
374}374}
375 375
376float tDelayA_tapOut (tDelayA* const d, uint32_t tapDelay)376float tAllpassDelay_tapOut (tAllpassDelay* const d, uint32_t tapDelay)
377{377{
378 int32_t tap = d->inPoint - tapDelay - 1;378 int32_t tap = d->inPoint - tapDelay - 1;
379 379
@@ -384,7 +384,7 @@ float tDelayA_tapOut (tDelayA* const d, uint32_t tapDelay) · 4 unmodified lines
384 384
385}385}
386 386
387void tDelayA_tapIn (tDelayA* const d, float value, uint32_t tapDelay)387void tAllpassDelay_tapIn (tAllpassDelay* const d, float value, uint32_t tapDelay)
388{388{
389 int32_t tap = d->inPoint - tapDelay - 1;389 int32_t tap = d->inPoint - tapDelay - 1;
390 390
@@ -394,7 +394,7 @@ void tDelayA_tapIn (tDelayA* const d, float value, uint32_t tapDelay) · 3 unmodified lines
394 d->buff[tap] = value;394 d->buff[tap] = value;
395}395}
396 396
397float tDelayA_addTo (tDelayA* const d, float value, uint32_t tapDelay)397float tAllpassDelay_addTo (tAllpassDelay* const d, float value, uint32_t tapDelay)
398{398{
399 int32_t tap = d->inPoint - tapDelay - 1;399 int32_t tap = d->inPoint - tapDelay - 1;
400 400
@@ -404,28 +404,28 @@ float tDelayA_addTo (tDelayA* const d, float value, uint32_t tapDelay) · 3 unmodified lines
404 return (d->buff[tap] += value);404 return (d->buff[tap] += value);
405}405}
406 406
407float tDelayA_getDelay (tDelayA* const d)407float tAllpassDelay_getDelay (tAllpassDelay* const d)
408{408{
409 return d->delay;409 return d->delay;
410}410}
411 411
412float tDelayA_getLastOut (tDelayA* const d)412float tAllpassDelay_getLastOut (tAllpassDelay* const d)
413{413{
414 return d->lastOut;414 return d->lastOut;
415}415}
416 416
417float tDelayA_getLastIn (tDelayA* const d)417float tAllpassDelay_getLastIn (tAllpassDelay* const d)
418{418{
419 return d->lastIn;419 return d->lastIn;
420}420}
421 421
422void tDelayA_setGain (tDelayA* const d, float gain)422void tAllpassDelay_setGain (tAllpassDelay* const d, float gain)
423{423{
424 if (gain < 0.0f) d->gain = 0.0f;424 if (gain < 0.0f) d->gain = 0.0f;
425 else d->gain = gain;425 else d->gain = gain;
426}426}
427 427
428float tDelayA_getGain (tDelayA* const d)428float tAllpassDelay_getGain (tAllpassDelay* const d)
429{429{
430 return d->gain;430 return d->gain;
431}431}
LEAF/Src/leaf-distortion.crenamed from LEAF/Src/leaf-oversampler.c+173−2
@@ -8,17 +8,188 @@ · 7 unmodified lines
8 8
9#if _WIN32 || _WIN649#if _WIN32 || _WIN64
10 10
11#include "..\Inc\leaf-oversampler.h"11#include "..\Inc\leaf-distortion.h"
12#include "..\Inc\leaf-tables.h"12#include "..\Inc\leaf-tables.h"
13#else13#else
14 14
15 15
16#include "../Inc/leaf-oversampler.h"16#include "../Inc/leaf-distortion.h"
17#include "../Inc/leaf-tables.h"17#include "../Inc/leaf-tables.h"
18 18
19#endif19#endif
20 20
21//============================================================================================================
22// WAVEFOLDER
23//============================================================================================================
24void tLockhartWavefolder_init(tLockhartWavefolder* const w)
25{
26 w->Ln1 = 0.0;
27 w->Fn1 = 0.0;
28 w->xn1 = 0.0f;
29}
30
31void tLockhardWavefolder_free(tLockhartWavefolder* const w)
32{
33
34}
35
36double 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
66float 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
126void 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
136void tCrusher_free (tCrusher* const c)
137{
138
139}
140
141float 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
163void tCrusher_setOperation (tCrusher* const c, float op)
164{
165 c->op = (uint32_t) (op * 8.0f);
166}
167
168// 0.0 - 1.0
169void 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
179void tCrusher_setRound (tCrusher* const c, float rnd)
180{
181 c->rnd = fabsf(rnd);
182}
183
184void tCrusher_setSamplingRatio (tCrusher* const c, float ratio)
185{
186 c->srr = ratio;
187}
188
189
190//============================================================================================================
21// Oversampler191// Oversampler
192//============================================================================================================
22// Latency is equal to the phase length (numTaps / ratio)193// Latency is equal to the phase length (numTaps / ratio)
23void tOversampler_init(tOversampler* const os, int ratio, oBool extraQuality)194void tOversampler_init(tOversampler* const os, int ratio, oBool extraQuality)
24{195{
LEAF/Src/leaf-dynamics.c+172−0
@@ -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 */
44void 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
57void tCompressor_free(tCompressor* const c)
58{
59
60}
61
62int ccount = 0;
63float 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
124void 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
133void tFeedbackLeveler_free(tFeedbackLeveler* const p)
134{
135 tPowerFollower_free(&p->pwrFlw);
136}
137
138void 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
144void tFeedbackLeveler_setFactor(tFeedbackLeveler* const p, float factor)
145{
146 tPowerFollower_setFactor(&p->pwrFlw,factor);
147}
148
149void 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
154float 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
162float tFeedbackLeveler_sample(tFeedbackLeveler* const p)
163{
164 return p->curr;
165}
166
167
168void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const p, float TargetLevel)
169{
170 p->targetLevel=TargetLevel;
171}
172
LEAF/Src/leaf-effects.c+1393−0
@@ -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
27void 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
45void 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
54void 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
81void 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
101void 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
136void 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
165float 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
220void 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
231void 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
245void tVocoder_free (tVocoder* const v)
246{
247
248}
249
250void 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
332float 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
395void 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//============================================================================================================
407static int pitchshifter_attackdetect(tPitchShifter* ps);
408
409void 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
437void 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
445float 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
489float 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
531float 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
573void 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
599void 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
625void 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
651void 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
677void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf)
678{
679 ps->pitchFactor = pf;
680}
681
682void 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
688void tPitchShifter_setHopSize(tPitchShifter* ps, int hs)
689{
690 ps->hopSize = hs;
691}
692
693void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws)
694{
695 ps->windowSize = ws;
696}
697
698float tPitchShifter_getPeriod(tPitchShifter* ps)
699{
700 return tSNAC_getPeriod(&ps->snac);
701}
702
703static 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
734static 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
760void 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
780void tPitchShift_free(tPitchShift* const ps)
781{
782 tSOLAD_free(&ps->sola);
783 tHighpass_free(&ps->hp);
784}
785
786void tPitchShift_setPitchFactor(tPitchShift* ps, float pf)
787{
788 ps->pitchFactor = pf;
789}
790
791float 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
820float 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
850float 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
893static void solad_init(tSOLAD *w);
894static inline float read_sample(tSOLAD *w, float floatindex);
895static void pitchdown(tSOLAD *w, float *out);
896static void pitchup(tSOLAD *w, float *out);
897
898/******************************************************************************/
899/***************** public access functions ************************************/
900/******************************************************************************/
901
902// init
903void 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
910void tSOLAD_free(tSOLAD* const w)
911{
912}
913
914// send one block of input samples, receive one block of output samples
915void 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
931void 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
938void 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
946void 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
959void 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
1000static 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 */
1118static 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
1184static 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
1194static 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
1206void 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
1236void 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
1254float tFormantShifter_tick(tFormantShifter* fs, float in, float fwarp)
1255{
1256 return tFormantShifter_add(fs, tFormantShifter_remove(fs, in), fwarp);
1257}
1258
1259float 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
1299float 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}
LEAF/Src/leaf-electrical.crenamed from LEAF/Src/leaf-WDF.c+13−2
@@ -1,12 +1,23 @@
1/*1/*
2 * leaf-WDF.c2 * leaf-electrical.c
3 *3 *
4 * Created on: Sep 25, 20194 * Created on: Sep 25, 2019
5 * Author: jeffsnyder5 * 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
11static float get_port_resistance_for_resistor(tWDF* const r);22static float get_port_resistance_for_resistor(tWDF* const r);
12static float get_port_resistance_for_capacitor(tWDF* const r);23static float get_port_resistance_for_capacitor(tWDF* const r);
LEAF/Src/leaf-envelopes.c+629−0
@@ -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
28float 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
35float ftom(float f)
36{
37 return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f);
38}
39
40float 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
50float 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
60float 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
72float 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 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
88void 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
127void tEnvelope_free(tEnvelope* const env)
128{
129
130}
131
132int 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
149int 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
166int tEnvelope_loop(tEnvelope* const env, oBool loop)
167{
168 env->loop = loop;
169
170 return 0;
171}
172
173
174int 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
196float 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 */
267void 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
321void tADSR_free(tADSR* const adsr)
322{
323
324}
325
326int 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
343int 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
360int 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
369int 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
386int 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
410int 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
424float 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 */
504void 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
524void tRamp_free(tRamp* const ramp)
525{
526
527}
528
529int 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
543int 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
550int 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
557float 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
568float tRamp_sample(tRamp* const r) {
569
570 return r->curr;
571}
572
573void 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 */
581void 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
591void tExpSmooth_free(tExpSmooth* const smooth)
592{
593
594}
595
596int 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
607int tExpSmooth_setDest(tExpSmooth* const smooth, float dest)
608{
609 smooth->dest=dest;
610 return 0;
611}
612
613int tExpSmooth_setVal(tExpSmooth* const smooth, float val)
614{
615 smooth->curr=val;
616 return 0;
617}
618
619float tExpSmooth_tick(tExpSmooth* const smooth)
620{
621 smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr;
622 return smooth->curr;
623}
624
625float tExpSmooth_sample(tExpSmooth* const smooth)
626{
627 return smooth->curr;
628}
629
LEAF/Src/leaf-filters.crenamed from LEAF/Src/leaf-filter.c+11−11
@@ -8,13 +8,13 @@ · 7 unmodified lines
8 8
9#if _WIN32 || _WIN649#if _WIN32 || _WIN64
10 10
11#include "..\Inc\leaf-filter.h"11#include "..\Inc\leaf-filters.h"
12#include "..\Inc\leaf-tables.h"12#include "..\Inc\leaf-tables.h"
13#include "..\leaf.h"13#include "..\leaf.h"
14 14
15#else15#else
16 16
17#include "../Inc/leaf-filter.h"17#include "../Inc/leaf-filters.h"
18#include "../Inc/leaf-tables.h"18#include "../Inc/leaf-tables.h"
19#include "../leaf.h"19#include "../leaf.h"
20 20
@@ -27,17 +27,17 @@ void tAllpass_init(tAllpass* const f, float initDelay, uint32_t maxDelay) · 6 unmodified lines
27 27
28 f->lastOut = 0.0f;28 f->lastOut = 0.0f;
29 29
30 tDelayL_init(&f->delay, initDelay, maxDelay);30 tLinearDelay_init(&f->delay, initDelay, maxDelay);
31}31}
32 32
33void tAllpass_free(tAllpass* const f)33void tAllpass_free(tAllpass* const f)
34{34{
35 tDelayL_free(&f->delay);35 tLinearDelay_free(&f->delay);
36}36}
37 37
38void tAllpass_setDelay(tAllpass* const f, float delay)38void 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
43void tAllpass_setGain(tAllpass* const f, float gain)43void tAllpass_setGain(tAllpass* const f, float gain)
@@ -49,7 +49,7 @@ float tAllpass_tick(tAllpass* const f, float input) · 5 unmodified lines
49{49{
50 float s1 = (-f->gain) * f->lastOut + input;50 float s1 = (-f->gain) * f->lastOut + input;
51 51
52 float s2 = tDelayL_tick(&f->delay, s1) + (f->gain) * input;52 float s2 = tLinearDelay_tick(&f->delay, s1) + (f->gain) * input;
53 53
54 f->lastOut = s2;54 f->lastOut = s2;
55 55
@@ -758,7 +758,7 @@ int tSVF_setQ(tSVF* const svf, float Q) · 702 unmodified lines
758}758}
759 759
760// Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable.760// Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable.
761void tSVFE_init(tSVFE* const svf, SVFType type, uint16_t input, float Q)761void tEfficientSVF_init(tEfficientSVF* const svf, SVFType type, uint16_t input, float Q)
762{762{
763 svf->type = type;763 svf->type = type;
764 764
@@ -779,12 +779,12 @@ void tSVFE_init(tSVFE* const svf, SVFType type, uint16_t input, float Q) · 14 unmodified lines
779 svf->a3 = a3;779 svf->a3 = a3;
780}780}
781 781
782void tSVFE_free(tSVFE* const svf)782void tEfficientSVF_free(tEfficientSVF* const svf)
783{783{
784 784
785}785}
786 786
787float tSVFE_tick(tSVFE* const svf, float v0)787float tEfficientSVF_tick(tEfficientSVF* const svf, float v0)
788{788{
789 float v1,v2,v3;789 float v1,v2,v3;
790 v3 = v0 - svf->ic2eq;790 v3 = v0 - svf->ic2eq;
@@ -802,7 +802,7 @@ float tSVFE_tick(tSVFE* const svf, float v0) · 11 unmodified lines
802 802
803}803}
804 804
805int tSVFE_setFreq(tSVFE* const svf, uint16_t input)805int tEfficientSVF_setFreq(tEfficientSVF* const svf, uint16_t input)
806{806{
807 svf->g = filtertan[input];807 svf->g = filtertan[input];
808 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));808 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
@@ -812,7 +812,7 @@ int tSVFE_setFreq(tSVFE* const svf, uint16_t input) · 3 unmodified lines
812 return 0;812 return 0;
813}813}
814 814
815int tSVFE_setQ(tSVFE* const svf, float Q)815int tEfficientSVF_setQ(tEfficientSVF* const svf, float Q)
816{816{
817 svf->k = 1.0f/Q;817 svf->k = 1.0f/Q;
818 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));818 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
LEAF/Src/leaf-formant.c+0−206
@@ -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
19void 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
49void 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
67float tFormantShifter_tick(tFormantShifter* fs, float in, float fwarp)
68{
69 return tFormantShifter_add(fs, tFormantShifter_remove(fs, in), fwarp);
70}
71
72float 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
112float 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}
LEAF/Src/leaf-instruments.crenamed from LEAF/Src/leaf-808.c+3−3
@@ -1,6 +1,6 @@
1/*==============================================================================1/*==============================================================================
2 2
3 leaf-808.c3 leaf-instruments.c
4 Created: 30 Nov 2018 10:24:21am4 Created: 30 Nov 2018 10:24:21am
5 Author: airship5 Author: airship
6 6
@@ -8,11 +8,11 @@ · 1 unmodified line
8 8
9#if _WIN32 || _WIN649#if _WIN32 || _WIN64
10 10
11#include "..\Inc\leaf-808.h"11#include "..\Inc\leaf-instruments.h"
12 12
13#else13#else
14 14
15#include "../Inc/leaf-808.h"15#include "../Inc/leaf-instruments.h"
16 16
17#endif17#endif
18 18
LEAF/Src/leaf-math.c+2−0
@@ -355,3 +355,5 @@ float LEAF_interpolation_linear (float A, float B, float alpha) · 354 unmodified lines
355 355
356 return out;356 return out;
357}357}
358
359
LEAF/Src/leaf-midi.c+213−0
@@ -305,3 +305,216 @@ int tPoly_isOn(tPoly* const poly, uint8_t voice) · 304 unmodified lines
305 return (poly->voices[voice][0] > 0) ? 1 : 0;305 return (poly->voices[voice][0] > 0) ? 1 : 0;
306}306}
307 307
308
309//====================================================================================
310/* Stack */
311//====================================================================================
312
313void 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
323void tStack_free(tStack* const ns)
324{
325
326}
327
328// If stack contains note, returns index. Else returns -1;
329int 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
338void 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
370int 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
413int 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
449void 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
473int tStack_getSize(tStack* const ns)
474{
475 return ns->size;
476}
477
478void 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.
489int 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
512int tStack_get(tStack* const ns, int which)
513{
514 return ns->data[which];
515}
516
517int tStack_first(tStack* const ns)
518{
519 return ns->data[0];
520}
LEAF/Src/leaf-oscillators.crenamed from LEAF/Src/leaf-oscillator.c+305−299
@@ -1,6 +1,6 @@
1/*==============================================================================1/*==============================================================================
2 2
3 leaf-oscillator.c3 leaf-oscillators.c
4 Created: 20 Jan 2017 12:00:58pm4 Created: 20 Jan 2017 12:00:58pm
5 Author: Michael R Mulshine5 Author: Michael R Mulshine
6 6
@@ -9,212 +9,17 @@ · 2 unmodified lines
9#if _WIN32 || _WIN649#if _WIN32 || _WIN64
10 10
11#include "..\Inc\leaf-tables.h"11#include "..\Inc\leaf-tables.h"
12#include "..\Inc\leaf-oscillator.h"12#include "..\Inc\leaf-oscillators.h"
13#include "..\leaf.h"13#include "..\leaf.h"
14 14
15#else15#else
16 16
17#include "../Inc/leaf-tables.h"17#include "../Inc/leaf-tables.h"
18#include "../Inc/leaf-oscillator.h"18#include "../Inc/leaf-oscillators.h"
19#include "../leaf.h"19#include "../leaf.h"
20 20
21#endif21#endif
22 22
23void tNeuronSampleRateChanged(tNeuron* n)
24{
25
26}
27
28void 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
57void tNeuron_free(tNeuron* const n)
58{
59 tPoleZero_free(&n->f);
60}
61
62void 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
91void tNeuron_setV1(tNeuron* const n, float V1)
92{
93 n->V[0] = V1;
94}
95
96
97void tNeuron_setV2(tNeuron* const n, float V2)
98{
99 n->V[1] = V2;
100}
101
102void tNeuron_setV3(tNeuron* const n, float V3)
103{
104 n->V[2] = V3;
105}
106
107void tNeuron_setTimeStep(tNeuron* const n, float timeStep)
108{
109 n->timeStep = timeStep;
110}
111
112void tNeuron_setK(tNeuron* const n, float K)
113{
114 n->gK = K;
115}
116
117void tNeuron_setL(tNeuron* const n, float L)
118{
119 n->gL = L;
120 n->rate[2] = n->gL/n->C;
121}
122
123void tNeuron_setN(tNeuron* const n, float N)
124{
125 n->gN = N;
126}
127
128void tNeuron_setC(tNeuron* const n, float C)
129{
130 n->C = C;
131 n->rate[2] = n->gL/n->C;
132}
133
134float 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
208void tNeuron_setMode (tNeuron* const n, NeuronMode mode)
209{
210 n->mode = mode;
211}
212
213void tNeuron_setCurrent (tNeuron* const n, float current)
214{
215 n->current = current;
216}
217
218// Cycle23// Cycle
219void tCycle_init(tCycle* const c)24void tCycle_init(tCycle* const c)
220{25{
@@ -258,56 +63,25 @@ void tCycleSampleRateChanged (tCycle* const c) · 37 unmodified lines
258 c->inc = c->freq * leaf.invSampleRate;63 c->inc = c->freq * leaf.invSampleRate;
259}64}
260 65
261/* Phasor */66//========================================================================
262void tPhasorSampleRateChanged (tPhasor* const p)67/* Triangle */
263{68void tTriangle_start(tTriangle* const c)
264 p->inc = p->freq * leaf.invSampleRate;
265};
266
267void tPhasor_init(tPhasor* const p)
268{
269 p->phase = 0.0f;
270 p->inc = 0.0f;
271}
272
273void tPhasor_free(tPhasor* const p)
274{69{
275 70
276}71}
277 72
278int tPhasor_setFreq(tPhasor* const p, float freq)73void tTriangle_init(tTriangle* const c)
279{74{
280 if (freq < 0.0f) freq = 0.0f;75 c->inc = 0.0f;
281 76 c->phase = 0.0f;
282 p->freq = freq;
283 p->inc = freq * leaf.invSampleRate;
284
285 return 0;
286}77}
287 78
288float tPhasor_tick(tPhasor* const p)79void 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 84int tTriangle_setFreq(tTriangle* const c, float freq)
298
299void tSawtooth_init(tSawtooth* const c)
300{
301 c->inc = 0.0f;
302 c->phase = 0.0f;
303}
304
305void tSawtooth_free(tSawtooth* const c)
306{
307
308}
309
310int tSawtooth_setFreq(tSawtooth* const c, float freq)
311{85{
312 if (freq < 0.0f) freq = 0.0f;86 if (freq < 0.0f) freq = 0.0f;
313 87
@@ -317,7 +91,8 @@ int tSawtooth_setFreq(tSawtooth* const c, float freq) · 3 unmodified lines
317 return 0;91 return 0;
318}92}
319 93
320float tSawtooth_tick(tSawtooth* const c)94
95float tTriangle_tick(tTriangle* const c)
321{96{
322 // Phasor increment97 // Phasor increment
323 c->phase += c->inc;98 c->phase += c->inc;
@@ -332,89 +107,85 @@ float tSawtooth_tick(tSawtooth* const c) · 8 unmodified lines
332 107
333 if (c->freq <= 20.0f)108 if (c->freq <= 20.0f)
334 {109 {
335 out = sawtooth[T20][idx];110 out = triangle[T20][idx];
336 }111 }
337 else if (c->freq <= 40.0f)112 else if (c->freq <= 40.0f)
338 {113 {
339 w = ((40.0f - c->freq) * INV_20);114 w = ((40.0f - c->freq) * INV_20);
340 out = (sawtooth[T20][idx] * w) + (sawtooth[T40][idx] * (1.0f - w));115 out = (triangle[T20][idx] * w) + (triangle[T40][idx] * (1.0f - w));
341 }116 }
342 else if (c->freq <= 80.0f)117 else if (c->freq <= 80.0f)
343 {118 {
344 w = ((80.0f - c->freq) * INV_40);119 w = ((80.0f - c->freq) * INV_40);
345 out = (sawtooth[T40][idx] * w) + (sawtooth[T80][idx] * (1.0f - w));120 out = (triangle[T40][idx] * w) + (triangle[T80][idx] * (1.0f - w));
346 }121 }
347 else if (c->freq <= 160.0f)122 else if (c->freq <= 160.0f)
348 {123 {
349 w = ((160.0f - c->freq) * INV_80);124 w = ((160.0f - c->freq) * INV_80);
350 out = (sawtooth[T80][idx] * w) + (sawtooth[T160][idx] * (1.0f - w));125 out = (triangle[T80][idx] * w) + (triangle[T160][idx] * (1.0f - w));
351 }126 }
352 else if (c->freq <= 320.0f)127 else if (c->freq <= 320.0f)
353 {128 {
354 w = ((320.0f - c->freq) * INV_160);129 w = ((320.0f - c->freq) * INV_160);
355 out = (sawtooth[T160][idx] * w) + (sawtooth[T320][idx] * (1.0f - w));130 out = (triangle[T160][idx] * w) + (triangle[T320][idx] * (1.0f - w));
356 }131 }
357 else if (c->freq <= 640.0f)132 else if (c->freq <= 640.0f)
358 {133 {
359 w = ((640.0f - c->freq) * INV_320);134 w = ((640.0f - c->freq) * INV_320);
360 out = (sawtooth[T320][idx] * w) + (sawtooth[T640][idx] * (1.0f - w));135 out = (triangle[T320][idx] * w) + (triangle[T640][idx] * (1.0f - w));
361 }136 }
362 else if (c->freq <= 1280.0f)137 else if (c->freq <= 1280.0f)
363 {138 {
364 w = ((1280.0f - c->freq) * INV_640);139 w = ((1280.0f - c->freq) * INV_640);
365 out = (sawtooth[T640][idx] * w) + (sawtooth[T1280][idx] * (1.0f - w));140 out = (triangle[T640][idx] * w) + (triangle[T1280][idx] * (1.0f - w));
366 }141 }
367 else if (c->freq <= 2560.0f)142 else if (c->freq <= 2560.0f)
368 {143 {
369 w = ((2560.0f - c->freq) * INV_1280);144 w = ((2560.0f - c->freq) * INV_1280);
370 out = (sawtooth[T1280][idx] * w) + (sawtooth[T2560][idx] * (1.0f - w));145 out = (triangle[T1280][idx] * w) + (triangle[T2560][idx] * (1.0f - w));
371 }146 }
372 else if (c->freq <= 5120.0f)147 else if (c->freq <= 5120.0f)
373 {148 {
374 w = ((5120.0f - c->freq) * INV_2560);149 w = ((5120.0f - c->freq) * INV_2560);
375 out = (sawtooth[T2560][idx] * w) + (sawtooth[T5120][idx] * (1.0f - w));150 out = (triangle[T2560][idx] * w) + (triangle[T5120][idx] * (1.0f - w));
376 }151 }
377 else if (c->freq <= 10240.0f)152 else if (c->freq <= 10240.0f)
378 {153 {
379 w = ((10240.0f - c->freq) * INV_5120);154 w = ((10240.0f - c->freq) * INV_5120);
380 out = (sawtooth[T5120][idx] * w) + (sawtooth[T10240][idx] * (1.0f - w));155 out = (triangle[T5120][idx] * w) + (triangle[T10240][idx] * (1.0f - w));
381 }156 }
382 else if (c->freq <= 20480.0f)157 else if (c->freq <= 20480.0f)
383 {158 {
384 w = ((20480.0f - c->freq) * INV_10240);159 w = ((20480.0f - c->freq) * INV_10240);
385 out = (sawtooth[T10240][idx] * w) + (sawtooth[T20480][idx] * (1.0f - w));160 out = (triangle[T10240][idx] * w) + (triangle[T20480][idx] * (1.0f - w));
386 }161 }
387 else162 else
388 {163 {
389 out = sawtooth[T20480][idx];164 out = triangle[T20480][idx];
390 }165 }
391 166
392 return out;167 return out;
393}168}
394 169
395void tSawtoothSampleRateChanged (tSawtooth* const c)170void tTriangleSampleRateChanged (tTriangle* const c)
396{171{
397 c->inc = c->freq * leaf.invSampleRate;172 c->inc = c->freq * leaf.invSampleRate;
398}173}
399 174
400/* Triangle */175//========================================================================
401void tTriangle_start(tTriangle* const c)176/* Square */
402{177void tSquare_init(tSquare* const c)
403
404}
405
406void tTriangle_init(tTriangle* const c)
407{178{
408 c->inc = 0.0f;179 c->inc = 0.0f;
409 c->phase = 0.0f;180 c->phase = 0.0f;
410}181}
411 182
412void tTriangle_free(tTriangle* const c)183void tSquare_free(tSquare* const c)
413{184{
414 185
415}186}
416 187
417int tTriangle_setFreq(tTriangle* const c, float freq)188int tSquare_setFreq(tSquare* const c, float freq)
418{189{
419 if (freq < 0.0f) freq = 0.0f;190 if (freq < 0.0f) freq = 0.0f;
420 191
@@ -424,100 +195,99 @@ int tTriangle_setFreq(tTriangle* const c, float freq) · 3 unmodified lines
424 return 0;195 return 0;
425}196}
426 197
427 198float tSquare_tick(tSquare* const c)
428float tTriangle_tick(tTriangle* const c)
429{199{
430 // Phasor increment200 // Phasor increment
431 c->phase += c->inc;201 c->phase += c->inc;
432 while (c->phase >= 1.0f) c->phase -= 1.0f;202 while (c->phase >= 1.0f) c->phase -= 1.0f;
433 203
434 float out = 0.0f;204 float out = 0.0f;
435 float w;205 float w = 0.0f;
436
437 int idx = (int)(c->phase * TRI_TABLE_SIZE);206 int idx = (int)(c->phase * TRI_TABLE_SIZE);
438 207
439 // Wavetable synthesis208 // Wavetable synthesis
440 209
441 if (c->freq <= 20.0f)210 if (c->freq <= 20.0f)
442 {211 {
443 out = triangle[T20][idx];212 out = squarewave[T20][idx];
444 }213 }
445 else if (c->freq <= 40.0f)214 else if (c->freq <= 40.0f)
446 {215 {
447 w = ((40.0f - c->freq) * INV_20);216 w = ((40.0f - c->freq) * INV_20);
448 out = (triangle[T20][idx] * w) + (triangle[T40][idx] * (1.0f - w));217 out = (squarewave[T20][idx] * w) + (squarewave[T40][idx] * (1.0f - w));
449 }218 }
450 else if (c->freq <= 80.0f)219 else if (c->freq <= 80.0f)
451 {220 {
452 w = ((80.0f - c->freq) * INV_40);221 w = ((80.0f - c->freq) * INV_40);
453 out = (triangle[T40][idx] * w) + (triangle[T80][idx] * (1.0f - w));222 out = (squarewave[T40][idx] * w) + (squarewave[T80][idx] * (1.0f - w));
454 }223 }
455 else if (c->freq <= 160.0f)224 else if (c->freq <= 160.0f)
456 {225 {
457 w = ((160.0f - c->freq) * INV_80);226 w = ((160.0f - c->freq) * INV_80);
458 out = (triangle[T80][idx] * w) + (triangle[T160][idx] * (1.0f - w));227 out = (squarewave[T80][idx] * w) + (squarewave[T160][idx] * (1.0f - w));
459 }228 }
460 else if (c->freq <= 320.0f)229 else if (c->freq <= 320.0f)
461 {230 {
462 w = ((320.0f - c->freq) * INV_160);231 w = ((320.0f - c->freq) * INV_160);
463 out = (triangle[T160][idx] * w) + (triangle[T320][idx] * (1.0f - w));232 out = (squarewave[T160][idx] * w) + (squarewave[T320][idx] * (1.0f - w));
464 }233 }
465 else if (c->freq <= 640.0f)234 else if (c->freq <= 640.0f)
466 {235 {
467 w = ((640.0f - c->freq) * INV_320);236 w = ((640.0f - c->freq) * INV_320);
468 out = (triangle[T320][idx] * w) + (triangle[T640][idx] * (1.0f - w));237 out = (squarewave[T320][idx] * w) + (squarewave[T640][idx] * (1.0f - w));
469 }238 }
470 else if (c->freq <= 1280.0f)239 else if (c->freq <= 1280.0f)
471 {240 {
472 w = ((1280.0f - c->freq) * INV_640);241 w = ((1280.0f - c->freq) * INV_640);
473 out = (triangle[T640][idx] * w) + (triangle[T1280][idx] * (1.0f - w));242 out = (squarewave[T640][idx] * w) + (squarewave[T1280][idx] * (1.0f - w));
474 }243 }
475 else if (c->freq <= 2560.0f)244 else if (c->freq <= 2560.0f)
476 {245 {
477 w = ((2560.0f - c->freq) * INV_1280);246 w = ((2560.0f - c->freq) * INV_1280);
478 out = (triangle[T1280][idx] * w) + (triangle[T2560][idx] * (1.0f - w));247 out = (squarewave[T1280][idx] * w) + (squarewave[T2560][idx] * (1.0f - w));
479 }248 }
480 else if (c->freq <= 5120.0f)249 else if (c->freq <= 5120.0f)
481 {250 {
482 w = ((5120.0f - c->freq) * INV_2560);251 w = ((5120.0f - c->freq) * INV_2560);
483 out = (triangle[T2560][idx] * w) + (triangle[T5120][idx] * (1.0f - w));252 out = (squarewave[T2560][idx] * w) + (squarewave[T5120][idx] * (1.0f - w));
484 }253 }
485 else if (c->freq <= 10240.0f)254 else if (c->freq <= 10240.0f)
486 {255 {
487 w = ((10240.0f - c->freq) * INV_5120);256 w = ((10240.0f - c->freq) * INV_5120);
488 out = (triangle[T5120][idx] * w) + (triangle[T10240][idx] * (1.0f - w));257 out = (squarewave[T5120][idx] * w) + (squarewave[T10240][idx] * (1.0f - w));
489 }258 }
490 else if (c->freq <= 20480.0f)259 else if (c->freq <= 20480.0f)
491 {260 {
492 w = ((20480.0f - c->freq) * INV_10240);261 w = ((20480.0f - c->freq) * INV_10240);
493 out = (triangle[T10240][idx] * w) + (triangle[T20480][idx] * (1.0f - w));262 out = (squarewave[T10240][idx] * w) + (squarewave[T20480][idx] * (1.0f - w));
494 }263 }
495 else264 else
496 {265 {
497 out = triangle[T20480][idx];266 out = squarewave[T20480][idx];
498 }267 }
499 268
500 return out;269 return out;
501}270}
502 271
503void tTriangleSampleRateChanged (tTriangle* const c)272void tSquareSampleRateChanged (tSquare* const c)
504{273{
505 c->inc = c->freq * leaf.invSampleRate;274 c->inc = c->freq * leaf.invSampleRate;
506}275}
507 276
508/* Square */277//=====================================================================
509void tSquare_init(tSquare* const c)278// Sawtooth
279void tSawtooth_init(tSawtooth* const c)
510{280{
511 c->inc = 0.0f;281 c->inc = 0.0f;
512 c->phase = 0.0f;282 c->phase = 0.0f;
513}283}
514 284
515void tSquare_free(tSquare* const c)285void tSawtooth_free(tSawtooth* const c)
516{286{
517 287
518}288}
519 289
520int tSquare_setFreq(tSquare* const c, float freq)290int tSawtooth_setFreq(tSawtooth* const c, float freq)
521{291{
522 if (freq < 0.0f) freq = 0.0f;292 if (freq < 0.0f) freq = 0.0f;
523 293
@@ -527,85 +297,123 @@ int tSquare_setFreq(tSquare* const c, float freq) · 3 unmodified lines
527 return 0;297 return 0;
528}298}
529 299
530float tSquare_tick(tSquare* const c)300float tSawtooth_tick(tSawtooth* const c)
531{301{
532 // Phasor increment302 // Phasor increment
533 c->phase += c->inc;303 c->phase += c->inc;
534 while (c->phase >= 1.0f) c->phase -= 1.0f;304 while (c->phase >= 1.0f) c->phase -= 1.0f;
535 305
536 float out = 0.0f;306 float out = 0.0f;
537 float w = 0.0f;307 float w;
308
538 int idx = (int)(c->phase * TRI_TABLE_SIZE);309 int idx = (int)(c->phase * TRI_TABLE_SIZE);
539 310
540 // Wavetable synthesis311 // Wavetable synthesis
541 312
542 if (c->freq <= 20.0f)313 if (c->freq <= 20.0f)
543 {314 {
544 out = squarewave[T20][idx];315 out = sawtooth[T20][idx];
545 }316 }
546 else if (c->freq <= 40.0f)317 else if (c->freq <= 40.0f)
547 {318 {
548 w = ((40.0f - c->freq) * INV_20);319 w = ((40.0f - c->freq) * INV_20);
549 out = (squarewave[T20][idx] * w) + (squarewave[T40][idx] * (1.0f - w));320 out = (sawtooth[T20][idx] * w) + (sawtooth[T40][idx] * (1.0f - w));
550 }321 }
551 else if (c->freq <= 80.0f)322 else if (c->freq <= 80.0f)
552 {323 {
553 w = ((80.0f - c->freq) * INV_40);324 w = ((80.0f - c->freq) * INV_40);
554 out = (squarewave[T40][idx] * w) + (squarewave[T80][idx] * (1.0f - w));325 out = (sawtooth[T40][idx] * w) + (sawtooth[T80][idx] * (1.0f - w));
555 }326 }
556 else if (c->freq <= 160.0f)327 else if (c->freq <= 160.0f)
557 {328 {
558 w = ((160.0f - c->freq) * INV_80);329 w = ((160.0f - c->freq) * INV_80);
559 out = (squarewave[T80][idx] * w) + (squarewave[T160][idx] * (1.0f - w));330 out = (sawtooth[T80][idx] * w) + (sawtooth[T160][idx] * (1.0f - w));
560 }331 }
561 else if (c->freq <= 320.0f)332 else if (c->freq <= 320.0f)
562 {333 {
563 w = ((320.0f - c->freq) * INV_160);334 w = ((320.0f - c->freq) * INV_160);
564 out = (squarewave[T160][idx] * w) + (squarewave[T320][idx] * (1.0f - w));335 out = (sawtooth[T160][idx] * w) + (sawtooth[T320][idx] * (1.0f - w));
565 }336 }
566 else if (c->freq <= 640.0f)337 else if (c->freq <= 640.0f)
567 {338 {
568 w = ((640.0f - c->freq) * INV_320);339 w = ((640.0f - c->freq) * INV_320);
569 out = (squarewave[T320][idx] * w) + (squarewave[T640][idx] * (1.0f - w));340 out = (sawtooth[T320][idx] * w) + (sawtooth[T640][idx] * (1.0f - w));
570 }341 }
571 else if (c->freq <= 1280.0f)342 else if (c->freq <= 1280.0f)
572 {343 {
573 w = ((1280.0f - c->freq) * INV_640);344 w = ((1280.0f - c->freq) * INV_640);
574 out = (squarewave[T640][idx] * w) + (squarewave[T1280][idx] * (1.0f - w));345 out = (sawtooth[T640][idx] * w) + (sawtooth[T1280][idx] * (1.0f - w));
575 }346 }
576 else if (c->freq <= 2560.0f)347 else if (c->freq <= 2560.0f)
577 {348 {
578 w = ((2560.0f - c->freq) * INV_1280);349 w = ((2560.0f - c->freq) * INV_1280);
579 out = (squarewave[T1280][idx] * w) + (squarewave[T2560][idx] * (1.0f - w));350 out = (sawtooth[T1280][idx] * w) + (sawtooth[T2560][idx] * (1.0f - w));
580 }351 }
581 else if (c->freq <= 5120.0f)352 else if (c->freq <= 5120.0f)
582 {353 {
583 w = ((5120.0f - c->freq) * INV_2560);354 w = ((5120.0f - c->freq) * INV_2560);
584 out = (squarewave[T2560][idx] * w) + (squarewave[T5120][idx] * (1.0f - w));355 out = (sawtooth[T2560][idx] * w) + (sawtooth[T5120][idx] * (1.0f - w));
585 }356 }
586 else if (c->freq <= 10240.0f)357 else if (c->freq <= 10240.0f)
587 {358 {
588 w = ((10240.0f - c->freq) * INV_5120);359 w = ((10240.0f - c->freq) * INV_5120);
589 out = (squarewave[T5120][idx] * w) + (squarewave[T10240][idx] * (1.0f - w));360 out = (sawtooth[T5120][idx] * w) + (sawtooth[T10240][idx] * (1.0f - w));
590 }361 }
591 else if (c->freq <= 20480.0f)362 else if (c->freq <= 20480.0f)
592 {363 {
593 w = ((20480.0f - c->freq) * INV_10240);364 w = ((20480.0f - c->freq) * INV_10240);
594 out = (squarewave[T10240][idx] * w) + (squarewave[T20480][idx] * (1.0f - w));365 out = (sawtooth[T10240][idx] * w) + (sawtooth[T20480][idx] * (1.0f - w));
595 }366 }
596 else367 else
597 {368 {
598 out = squarewave[T20480][idx];369 out = sawtooth[T20480][idx];
599 }370 }
600 371
601 return out;372 return out;
602}373}
603 374
604void tSquareSampleRateChanged (tSquare* const c)375void tSawtoothSampleRateChanged (tSawtooth* const c)
605{376{
606 c->inc = c->freq * leaf.invSampleRate;377 c->inc = c->freq * leaf.invSampleRate;
607}378}
608 379
380//========================================================================
381/* Phasor */
382void tPhasorSampleRateChanged (tPhasor* const p)
383{
384 p->inc = p->freq * leaf.invSampleRate;
385};
386
387void tPhasor_init(tPhasor* const p)
388{
389 p->phase = 0.0f;
390 p->inc = 0.0f;
391}
392
393void tPhasor_free(tPhasor* const p)
394{
395
396}
397
398int 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
408float tPhasor_tick(tPhasor* const p)
409{
410 p->phase += p->inc;
411
412 if (p->phase >= 1.0f) p->phase -= 1.0f;
413
414 return p->phase;
415}
416
609/* Noise */417/* Noise */
610void tNoise_init(tNoise* const n, NoiseType type)418void tNoise_init(tNoise* const n, NoiseType type)
611{419{
@@ -636,3 +444,201 @@ float tNoise_tick(tNoise* const n) · 24 unmodified lines
636 return rand;444 return rand;
637 }445 }
638}446}
447
448//=================================================================================
449/* Neuron */
450
451void tNeuronSampleRateChanged(tNeuron* n)
452{
453
454}
455
456void 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
485void tNeuron_free(tNeuron* const n)
486{
487 tPoleZero_free(&n->f);
488}
489
490void 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
519void tNeuron_setV1(tNeuron* const n, float V1)
520{
521 n->V[0] = V1;
522}
523
524
525void tNeuron_setV2(tNeuron* const n, float V2)
526{
527 n->V[1] = V2;
528}
529
530void tNeuron_setV3(tNeuron* const n, float V3)
531{
532 n->V[2] = V3;
533}
534
535void tNeuron_setTimeStep(tNeuron* const n, float timeStep)
536{
537 n->timeStep = timeStep;
538}
539
540void tNeuron_setK(tNeuron* const n, float K)
541{
542 n->gK = K;
543}
544
545void tNeuron_setL(tNeuron* const n, float L)
546{
547 n->gL = L;
548 n->rate[2] = n->gL/n->C;
549}
550
551void tNeuron_setN(tNeuron* const n, float N)
552{
553 n->gN = N;
554}
555
556void tNeuron_setC(tNeuron* const n, float C)
557{
558 n->C = C;
559 n->rate[2] = n->gL/n->C;
560}
561
562float 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
636void tNeuron_setMode (tNeuron* const n, NeuronMode mode)
637{
638 n->mode = mode;
639}
640
641void tNeuron_setCurrent (tNeuron* const n, float current)
642{
643 n->current = current;
644}
LEAF/Src/leaf-physical.c+596−0
@@ -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 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
20void 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
35void 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
43float tPluck_getLastOut (tPluck *p)
44{
45 return p->lastOut;
46}
47
48float 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
53void 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.;
67void 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).
75void 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.
84void 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).
100void tPluck_controlChange (tPluck* const p, int number, float value)
101{
102 return;
103}
104
105void tPluckSampleRateChanged(tPluck* const p)
106{
107 //tPluckSetFrequency(p, p->lastFreq);
108}
109
110/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tKarplusStrong ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
111void 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
139void 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
152float tKarplusStrong_getLastOut (tKarplusStrong* const p)
153{
154 return p->lastOut;
155}
156
157float 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
174void 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.;
190void 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).
197void 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.
206void 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).
226void 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).
251void 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.
261void 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).
269void 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
285void tKarplusStrongSampleRateChanged (tKarplusStrong* const c)
286{
287 tKarplusStrong_setFrequency(c, c->lastFrequency);
288 tKarplusStrong_setStretch(c, c->stretching);
289}
290
291/* Simple Living String*/
292
293void 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
306void 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
315int 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
324int 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
333int tSimpleLivingString_setDampFreq(tSimpleLivingString* const p, float dampFreq)
334{
335 tOnePole_setFreq(&p->bridgeFilter, dampFreq);
336 return 0;
337}
338
339int tSimpleLivingString_setDecay(tSimpleLivingString* const p, float decay)
340{
341 p->decay=decay;
342 return 0;
343}
344
345int tSimpleLivingString_setTargetLev(tSimpleLivingString* const p, float targetLev)
346{
347 tFeedbackLeveler_setTargetLevel(&p->fbLev, targetLev);
348 return 0;
349}
350
351int tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor)
352{
353 tFeedbackLeveler_setFactor(&p->fbLev, levSmoothFactor);
354 return 0;
355}
356
357int tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength)
358{
359 tFeedbackLeveler_setStrength(&p->fbLev, levStrength);
360 return 0;
361}
362
363int tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode)
364{
365 tFeedbackLeveler_setMode(&p->fbLev, levMode);
366 p->levMode=levMode;
367 return 0;
368}
369
370float 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
380float tSimpleLivingString_sample(tSimpleLivingString* const p)
381{
382 return p->curr;
383}
384
385/* Living String*/
386
387void 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
411void 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
429int 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
438int 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
447int 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
456int 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
464int 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
473int tLivingString_setDecay(tLivingString* const p, float decay)
474{
475 p->decay=decay;
476 return 0;
477}
478
479int 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
486int 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
493int 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
500int 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
508float 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
542float 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
550void tReedTable_init (tReedTable* const p, float offset, float slope)
551{
552 p->offset = offset;
553 p->slope = slope;
554}
555
556void tReedTable_free (tReedTable* const p)
557{
558 ;
559}
560
561float 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
578float 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
588void tReedTable_setOffset (tReedTable* const p, float offset)
589{
590 p->offset = offset;
591}
592
593void tReedTable_setSlope (tReedTable* const p, float slope)
594{
595 p->slope = slope;
596}
LEAF/Src/leaf-pitch.c+0−563
@@ -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
18static int pitchshifter_attackdetect(tPitchShifter* ps);
19
20void 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
48void 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
56float 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
100float 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
142float 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
184void 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
210void 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
236void 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
262void 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
288void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf)
289{
290 ps->pitchFactor = pf;
291}
292
293void 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
299void tPitchShifter_setHopSize(tPitchShifter* ps, int hs)
300{
301 ps->hopSize = hs;
302}
303
304void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws)
305{
306 ps->windowSize = ws;
307}
308
309float tPitchShifter_getPeriod(tPitchShifter* ps)
310{
311 return tSNAC_getPeriod(&ps->snac);
312}
313
314static 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
341void 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
364void tPeriod_free (tPeriod* const p)
365{
366 tEnv_free(&p->env);
367 tSNAC_free(&p->snac);
368}
369
370float 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
403void tPeriod_setHopSize(tPeriod* p, int hs)
404{
405 p->hopSize = hs;
406}
407
408void tPeriod_setWindowSize(tPeriod* p, int ws)
409{
410 p->windowSize = ws;
411}
412
413void tPitchShift_setPitchFactor(tPitchShift* ps, float pf)
414{
415 ps->pitchFactor = pf;
416}
417
418static 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
444void 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
464void tPitchShift_free(tPitchShift* const ps)
465{
466 tSOLAD_free(&ps->sola);
467 tHighpass_free(&ps->hp);
468}
469
470float 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
499float 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
529float 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}
LEAF/Src/leaf-reverb.c+32−32
@@ -18,8 +18,8 @@ · 17 unmodified lines
18 18
19#endif19#endif
20 20
21// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //21// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
22void tPRCRev_init(tPRCRev* const r, float t60)22void tPRCReverb_init(tPRCReverb* const r, float t60)
23{23{
24 if (t60 <= 0.0f) t60 = 0.001f;24 if (t60 <= 0.0f) t60 = 0.001f;
25 25
@@ -47,20 +47,20 @@ void tPRCRev_init(tPRCRev* const r, float t60) · 21 unmodified lines
47 tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2);47 tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2);
48 tDelay_init(&r->combDelay, lengths[2], lengths[2] * 2);48 tDelay_init(&r->combDelay, lengths[2], lengths[2] * 2);
49 49
50 tPRCRev_setT60(r, t60);50 tPRCReverb_setT60(r, t60);
51 51
52 r->allpassCoeff = 0.7f;52 r->allpassCoeff = 0.7f;
53 r->mix = 0.5f;53 r->mix = 0.5f;
54}54}
55 55
56void tPRCRev_free(tPRCRev* const r)56void tPRCReverb_free(tPRCReverb* const r)
57{57{
58 tDelay_free(&r->allpassDelays[0]);58 tDelay_free(&r->allpassDelays[0]);
59 tDelay_free(&r->allpassDelays[1]);59 tDelay_free(&r->allpassDelays[1]);
60 tDelay_free(&r->combDelay);60 tDelay_free(&r->combDelay);
61}61}
62 62
63void tPRCRev_setT60(tPRCRev* const r, float t60)63void tPRCReverb_setT60(tPRCReverb* const r, float t60)
64{64{
65 if ( t60 <= 0.0f ) t60 = 0.001f;65 if ( t60 <= 0.0f ) t60 = 0.001f;
66 66
@@ -70,12 +70,12 @@ void tPRCRev_setT60(tPRCRev* const r, float t60) · 3 unmodified lines
70 70
71}71}
72 72
73void tPRCRev_setMix(tPRCRev* const r, float mix)73void tPRCReverb_setMix(tPRCReverb* const r, float mix)
74{74{
75 r->mix = mix;75 r->mix = mix;
76}76}
77 77
78float tPRCRev_tick(tPRCRev* const r, float input)78float tPRCReverb_tick(tPRCReverb* const r, float input)
79{79{
80 float temp, temp0, temp1, temp2;80 float temp, temp0, temp1, temp2;
81 float out;81 float out;
@@ -107,13 +107,13 @@ float tPRCRev_tick(tPRCRev* const r, float input) · 25 unmodified lines
107 return out;107 return out;
108}108}
109 109
110void tPRCRevSampleRateChanged (tPRCRev* const r)110void tPRCReverbSampleRateChanged (tPRCReverb* const r)
111{111{
112 r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 ));112 r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 ));
113}113}
114 114
115/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */115/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
116void tNRev_init(tNRev* const r, float t60)116void tNReverb_init(tNReverb* const r, float t60)
117{117{
118 if (t60 <= 0.0f) t60 = 0.001f;118 if (t60 <= 0.0f) t60 = 0.001f;
119 119
@@ -150,12 +150,12 @@ void tNRev_init(tNRev* const r, float t60) · 30 unmodified lines
150 tDelay_setDelay(&r->combDelays[i], lengths[i+2]);150 tDelay_setDelay(&r->combDelays[i], lengths[i+2]);
151 }151 }
152 152
153 tNRev_setT60(r, t60);153 tNReverb_setT60(r, t60);
154 r->allpassCoeff = 0.7f;154 r->allpassCoeff = 0.7f;
155 r->mix = 0.3f;155 r->mix = 0.3f;
156}156}
157 157
158void tNRev_free(tNRev* const r)158void tNReverb_free(tNReverb* const r)
159{159{
160 for (int i = 0; i < 6; i++)160 for (int i = 0; i < 6; i++)
161 {161 {
@@ -168,7 +168,7 @@ void tNRev_free(tNRev* const r) · 6 unmodified lines
168 }168 }
169}169}
170 170
171void tNRev_setT60(tNRev* const r, float t60)171void tNReverb_setT60(tNReverb* const r, float t60)
172{172{
173 if (t60 <= 0.0f) t60 = 0.001f;173 if (t60 <= 0.0f) t60 = 0.001f;
174 174
@@ -178,12 +178,12 @@ void tNRev_setT60(tNRev* const r, float t60) · 3 unmodified lines
178 178
179}179}
180 180
181void tNRev_setMix(tNRev* const r, float mix)181void tNReverb_setMix(tNReverb* const r, float mix)
182{182{
183 r->mix = mix;183 r->mix = mix;
184}184}
185 185
186float tNRev_tick(tNRev* const r, float input)186float tNReverb_tick(tNReverb* const r, float input)
187{187{
188 r->lastIn = input;188 r->lastIn = input;
189 189
@@ -221,10 +221,10 @@ float tNRev_tick(tNRev* const r, float input) · 31 unmodified lines
221 out = r->mix * ( -( r->allpassCoeff * temp2 ) + temp );221 out = r->mix * ( -( r->allpassCoeff * temp2 ) + temp );
222 222
223 /*223 /*
224 temp = tDelayLGetLastOut(&r->allpassDelays[5]);224 temp = tLinearDelayGetLastOut(&r->allpassDelays[5]);
225 temp3 = r->allpassCoeff * temp;225 temp3 = r->allpassCoeff * temp;
226 temp3 += temp1;226 temp3 += temp1;
227 tDelayLTick(&r->allpassDelays[5], temp3 );227 tLinearDelayTick(&r->allpassDelays[5], temp3 );
228 lastFrame_[1] = effectMix_*( - ( r->allpassCoeff * temp3 ) + temp );228 lastFrame_[1] = effectMix_*( - ( r->allpassCoeff * temp3 ) + temp );
229 */229 */
230 230
@@ -237,7 +237,7 @@ float tNRev_tick(tNRev* const r, float input) · 6 unmodified lines
237 return out;237 return out;
238}238}
239 239
240void tNRevSampleRateChanged (tNRev* const r)240void tNReverbSampleRateChanged (tNReverb* const r)
241{241{
242 for (int i=0; i<6; i++) r->combCoeffs[i] = pow(10.0, (-3.0 * tDelay_getDelay(&r->combDelays[i]) * leaf.invSampleRate / r->t60 ));242 for (int i=0; i<6; i++) r->combCoeffs[i] = pow(10.0, (-3.0 * tDelay_getDelay(&r->combDelays[i]) * leaf.invSampleRate / r->t60 ));
243}243}
@@ -250,7 +250,7 @@ float in_allpass_delays[4] = { 4.771f, 3.595f, 12.73f, 9.307f }; · 6 unmodified lines
250float in_allpass_gains[4] = { 0.75f, 0.75f, 0.625f, 0.625f };250float in_allpass_gains[4] = { 0.75f, 0.75f, 0.625f, 0.625f };
251 251
252 252
253void tDattorro_init (tDattorro* const r)253void tDattorroReverb_init (tDattorroReverb* const r)
254{254{
255 r->size_max = 2.0f;255 r->size_max = 2.0f;
256 r->size = 1.f;256 r->size = 1.f;
@@ -298,20 +298,20 @@ void tDattorro_init (tDattorro* const r) · 41 unmodified lines
298 298
299 299
300 // PARAMETERS300 // 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
314void tDattorro_free (tDattorro* const r)314void tDattorroReverb_free (tDattorroReverb* const r)
315{315{
316 // INPUT316 // INPUT
317 tTapeDelay_free(&r->in_delay);317 tTapeDelay_free(&r->in_delay);
@@ -349,7 +349,7 @@ void tDattorro_free (tDattorro* const r) · 31 unmodified lines
349 tCycle_free(&r->f2_lfo);349 tCycle_free(&r->f2_lfo);
350}350}
351 351
352float tDattorro_tick (tDattorro* const r, float input)352float tDattorroReverb_tick (tDattorroReverb* const r, float input)
353{353{
354 // INPUT354 // INPUT
355 float in_sample = tTapeDelay_tick(&r->in_delay, input);355 float in_sample = tTapeDelay_tick(&r->in_delay, input);
@@ -449,12 +449,12 @@ float tDattorro_tick (tDattorro* const r, float input) · 93 unmodified lines
449 return (input * (1.0f - r->mix) + sample * r->mix);449 return (input * (1.0f - r->mix) + sample * r->mix);
450}450}
451 451
452void tDattorro_setMix (tDattorro* const r, float mix)452void tDattorroReverb_setMix (tDattorroReverb* const r, float mix)
453{453{
454 r->mix = LEAF_clip(0.0f, mix, 1.0f);454 r->mix = LEAF_clip(0.0f, mix, 1.0f);
455}455}
456 456
457void tDattorro_setSize (tDattorro* const r, float size)457void tDattorroReverb_setSize (tDattorroReverb* const r, float size)
458{458{
459 r->size = LEAF_clip(0.01f, size*r->size_max, r->size_max);459 r->size = LEAF_clip(0.01f, size*r->size_max, r->size_max);
460 r->t = r->size * leaf.sampleRate * 0.001f;460 r->t = r->size * leaf.sampleRate * 0.001f;
@@ -483,21 +483,21 @@ void tDattorro_setSize (tDattorro* const r, float size) · 22 unmodified lines
483 tTapeDelay_setDelay(&r->f2_delay_3, SAMP(106.28f));483 tTapeDelay_setDelay(&r->f2_delay_3, SAMP(106.28f));
484}484}
485 485
486void tDattorro_setInputDelay (tDattorro* const r, float preDelay)486void tDattorroReverb_setInputDelay (tDattorroReverb* const r, float preDelay)
487{487{
488 r->predelay = LEAF_clip(0.0f, preDelay, 200.0f);488 r->predelay = LEAF_clip(0.0f, preDelay, 200.0f);
489 489
490 tTapeDelay_setDelay(&r->in_delay, SAMP(r->predelay));490 tTapeDelay_setDelay(&r->in_delay, SAMP(r->predelay));
491}491}
492 492
493void tDattorro_setInputFilter (tDattorro* const r, float freq)493void tDattorroReverb_setInputFilter (tDattorroReverb* const r, float freq)
494{494{
495 r->input_filter = LEAF_clip(0.0f, freq, 20000.0f);495 r->input_filter = LEAF_clip(0.0f, freq, 20000.0f);
496 496
497 tOnePole_setFreq(&r->in_filter, r->input_filter);497 tOnePole_setFreq(&r->in_filter, r->input_filter);
498}498}
499 499
500void tDattorro_setFeedbackFilter (tDattorro* const r, float freq)500void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const r, float freq)
501{501{
502 r->feedback_filter = LEAF_clip(0.0f, freq, 20000.0f);502 r->feedback_filter = LEAF_clip(0.0f, freq, 20000.0f);
503 503
@@ -505,7 +505,7 @@ void tDattorro_setFeedbackFilter (tDattorro* const r, float freq) · 1 unmodified line
505 tOnePole_setFreq(&r->f2_filter, r->feedback_filter);505 tOnePole_setFreq(&r->f2_filter, r->feedback_filter);
506}506}
507 507
508void tDattorro_setFeedbackGain (tDattorro* const r, float gain)508void tDattorroReverb_setFeedbackGain (tDattorroReverb* const r, float gain)
509{509{
510 r->feedback_gain = gain;510 r->feedback_gain = gain;
511}511}
LEAF/Src/leaf-sampling.crenamed from LEAF/Src/leaf-sample.c+3−3
@@ -1,7 +1,7 @@
1/*1/*
2 ==============================================================================2 ==============================================================================
3 3
4 leaf-sample.c4 leaf-sampling.c
5 Created: 20 Jan 2017 12:02:17pm5 Created: 20 Jan 2017 12:02:17pm
6 Author: Michael R Mulshine6 Author: Michael R Mulshine
7 7
@@ -11,12 +11,12 @@ · 3 unmodified lines
11 11
12#if _WIN32 || _WIN6412#if _WIN32 || _WIN64
13 13
14#include "..\Inc\leaf-sample.h"14#include "..\Inc\leaf-sampling.h"
15#include "..\leaf.h"15#include "..\leaf.h"
16 16
17#else17#else
18 18
19#include "../Inc/leaf-sample.h"19#include "../Inc/leaf-sampling.h"
20#include "../leaf.h"20#include "../leaf.h"
21 21
22#endif22#endif
LEAF/Src/leaf-string.c+0−289
@@ -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 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
20void 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
35void 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
43float tPluck_getLastOut (tPluck *p)
44{
45 return p->lastOut;
46}
47
48float 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
53void 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.;
67void 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).
75void 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.
84void 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).
100void tPluck_controlChange (tPluck* const p, int number, float value)
101{
102 return;
103}
104
105void tPluckSampleRateChanged(tPluck* const p)
106{
107 //tPluckSetFrequency(p, p->lastFreq);
108}
109
110/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tStifKarp ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
111void 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
139void 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
152float tStifKarp_getLastOut (tStifKarp* const p)
153{
154 return p->lastOut;
155}
156
157float 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
174void 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.;
190void 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).
197void 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.
206void 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).
226void 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).
251void 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.
261void 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).
269void 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
285void tStifKarpSampleRateChanged (tStifKarp* const c)
286{
287 tStifKarp_setFrequency(c, c->lastFrequency);
288 tStifKarp_setStretch(c, c->stretching);
289}
LEAF/Src/leaf-utilities.c+0−2227
@@ -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
30float 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
37float ftom(float f)
38{
39 return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f);
40}
41
42float 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
52float 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
62float 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
74float 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. ----------------- */
87void 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
127void tEnv_free (tEnv* const x)
128{
129
130}
131
132float tEnv_tick (tEnv* const x)
133{
134 return powtodb(x->x_result);
135}
136
137void 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/*
174tCompressor* 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*/
194void 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
207void tCompressor_free(tCompressor* const c)
208{
209
210}
211
212int ccount = 0;
213float 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 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
273void 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
312void tEnvelope_free(tEnvelope* const env)
313{
314
315}
316
317int 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
334int 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
351int tEnvelope_loop(tEnvelope* const env, oBool loop)
352{
353 env->loop = loop;
354
355 return 0;
356}
357
358
359int 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
381float 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 */
452void 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
506void tADSR_free(tADSR* const adsr)
507{
508
509}
510
511int 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
528int 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
545int 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
554int 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
571int 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
595int 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
609float 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 */
689void 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
696void tEnvelopeFollower_free(tEnvelopeFollower* const e)
697{
698
699}
700
701float 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
716int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff)
717{
718 return ef->d_coeff = decayCoeff;
719}
720
721int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attackThresh)
722{
723 return ef->a_thresh = attackThresh;
724}
725
726/* Ramp */
727void 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
747void tRamp_free(tRamp* const ramp)
748{
749
750}
751
752int 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
766int 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
773int 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
780float 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
791float tRamp_sample(tRamp* const r) {
792
793 return r->curr;
794}
795
796void 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 */
804void 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
814void tExpSmooth_free(tExpSmooth* const smooth)
815{
816
817}
818
819int 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
830int tExpSmooth_setDest(tExpSmooth* const smooth, float dest)
831{
832 smooth->dest=dest;
833 return 0;
834}
835
836int tExpSmooth_setVal(tExpSmooth* const smooth, float val)
837{
838 smooth->curr=val;
839 return 0;
840}
841
842float tExpSmooth_tick(tExpSmooth* const smooth)
843{
844 smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr;
845 return smooth->curr;
846}
847
848float tExpSmooth_sample(tExpSmooth* const smooth)
849{
850 return smooth->curr;
851}
852
853
854/* Power Follower */
855
856void 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
863void tPwrFollow_free(tPwrFollow* const p)
864{
865
866}
867
868int 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
877float 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
883float tPwrFollow_sample(tPwrFollow* const p)
884{
885 return p->curr;
886}
887
888/* Feedback Leveler */
889
890void 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
899void tFBleveller_free(tFBleveller* const p)
900{
901 tPwrFollow_free(&p->pwrFlw);
902}
903
904int 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
911int tFBleveller_setFactor(tFBleveller* const p, float factor)
912{
913 tPwrFollow_setFactor(&p->pwrFlw,factor);
914 return 0;
915}
916
917int 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
923float 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
931float tFBleveller_sample(tFBleveller* const p)
932{
933 return p->curr;
934}
935
936
937int 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
945void tReedTable_init (tReedTable* const p, float offset, float slope)
946{
947 p->offset = offset;
948 p->slope = slope;
949}
950
951void tReedTable_free (tReedTable* const p)
952{
953 ;
954}
955
956float 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
973float 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
983void tReedTable_setOffset (tReedTable* const p, float offset)
984{
985 p->offset = offset;
986}
987
988void tReedTable_setSlope (tReedTable* const p, float slope)
989{
990 p->slope = slope;
991}
992
993
994
995/* Simple Living String*/
996
997void 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
1010void 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
1019int 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
1028int 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
1037int tSimpleLivingString_setDampFreq(tSimpleLivingString* const p, float dampFreq)
1038{
1039 tOnePole_setFreq(&p->bridgeFilter, dampFreq);
1040 return 0;
1041}
1042
1043int tSimpleLivingString_setDecay(tSimpleLivingString* const p, float decay)
1044{
1045 p->decay=decay;
1046 return 0;
1047}
1048
1049int tSimpleLivingString_setTargetLev(tSimpleLivingString* const p, float targetLev)
1050{
1051 tFBleveller_setTargetLevel(&p->fbLev, targetLev);
1052 return 0;
1053}
1054
1055int tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor)
1056{
1057 tFBleveller_setFactor(&p->fbLev, levSmoothFactor);
1058 return 0;
1059}
1060
1061int tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength)
1062{
1063 tFBleveller_setStrength(&p->fbLev, levStrength);
1064 return 0;
1065}
1066
1067int tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode)
1068{
1069 tFBleveller_setMode(&p->fbLev, levMode);
1070 p->levMode=levMode;
1071 return 0;
1072}
1073
1074float 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
1084float tSimpleLivingString_sample(tSimpleLivingString* const p)
1085{
1086 return p->curr;
1087}
1088
1089/* Living String*/
1090
1091void 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
1115void 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
1133int 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
1142int 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
1151int 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
1160int 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
1168int 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
1177int tLivingString_setDecay(tLivingString* const p, float decay)
1178{
1179 p->decay=decay;
1180 return 0;
1181}
1182
1183int 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
1190int 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
1197int 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
1204int 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
1212float 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
1246float tLivingString_sample(tLivingString* const p)
1247{
1248 return p->curr;
1249}
1250
1251
1252/* Stack */
1253
1254void 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
1264void tStack_free(tStack* const ns)
1265{
1266
1267}
1268
1269// If stack contains note, returns index. Else returns -1;
1270int 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
1279void 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
1311int 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
1354int 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
1390void 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
1414int tStack_getSize(tStack* const ns)
1415{
1416 return ns->size;
1417}
1418
1419void 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.
1430int 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
1453int tStack_get(tStack* const ns, int which)
1454{
1455 return ns->data[which];
1456}
1457
1458int tStack_first(tStack* const ns)
1459{
1460 return ns->data[0];
1461}
1462/******************************************************************************/
1463/***************** static function declarations *******************************/
1464/******************************************************************************/
1465
1466static void solad_init(tSOLAD *w);
1467static inline float read_sample(tSOLAD *w, float floatindex);
1468static void pitchdown(tSOLAD *w, float *out);
1469static void pitchup(tSOLAD *w, float *out);
1470
1471/******************************************************************************/
1472/***************** public access functions ************************************/
1473/******************************************************************************/
1474
1475// init
1476void 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
1483void tSOLAD_free(tSOLAD* const w)
1484{
1485}
1486
1487// send one block of input samples, receive one block of output samples
1488void 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
1504void 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
1511void 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
1519void 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
1532void 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
1573static 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 */
1691static 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
1757static 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
1767static 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
1783static void snac_analyzeframe(tSNAC* const s);
1784static void snac_autocorrelation(tSNAC* const s);
1785static void snac_normalize(tSNAC* const s);
1786static void snac_pickpeak(tSNAC* const s);
1787static void snac_periodandfidelity(tSNAC* const s);
1788static void snac_biasbuf(tSNAC* const s);
1789static float snac_spectralpeak(tSNAC* const s, float periodlength);
1790
1791
1792/******************************************************************************/
1793/******************************** constructor, destructor *********************/
1794/******************************************************************************/
1795
1796
1797void 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
1816void 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
1828void 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
1848void 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
1855void 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
1865void 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
1874float tSNAC_getPeriod(tSNAC* const s)
1875{
1876 return(s->periodlength);
1877}
1878
1879
1880float tSNAC_getFidelity(tSNAC* const s)
1881{
1882 return(s->fidelity);
1883}
1884
1885
1886/******************************************************************************/
1887/***************************** private procedures *****************************/
1888/******************************************************************************/
1889
1890
1891// main analysis function
1892static 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
1921static 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
1954static 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
1991static 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
2007static 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
2049static 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
2093static 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**********/
2112static void atkdtk_init(tAtkDtk* const a, int blocksize, int atk, int rel);
2113static void atkdtk_envelope(tAtkDtk* const a, float *in);
2114
2115/********Constructor/Destructor***************/
2116
2117void tAtkDtk_init(tAtkDtk* const a, int blocksize)
2118{
2119 atkdtk_init(a, blocksize, DEFATTACK, DEFRELEASE);
2120}
2121
2122void tAtkDtk_init_expanded(tAtkDtk* const a, int blocksize, int atk, int rel)
2123{
2124 atkdtk_init(a, blocksize, atk, rel);
2125}
2126
2127void tAtkDtk_free(tAtkDtk *a)
2128{
2129
2130}
2131
2132/*******Public Functions***********/
2133
2134
2135void 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
2146void 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
2157void tAtkDtk_setThreshold(tAtkDtk* const a, float thres)
2158{
2159 a->threshold = thres;
2160 return;
2161}
2162
2163void 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
2171void 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
2180int 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
2199static 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
2213static 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
LEAF/Src/leaf-vocoder.c+0−400
@@ -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
29void 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
47void 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
56void 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
83void 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
103void 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
138void 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
167float 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
222void 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
228void 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
242void tVocoder_free (tVocoder* const v)
243{
244
245}
246
247void 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
329float 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
392void 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
LEAF/Src/leaf-wavefolder.c+0−114
@@ -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
19void tLockhartWavefolder_init(tLockhartWavefolder* const w)
20{
21 w->Ln1 = 0.0;
22 w->Fn1 = 0.0;
23 w->xn1 = 0.0f;
24}
25
26void tLockhardWavefolder_free(tLockhartWavefolder* const w)
27{
28
29}
30
31double 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
61float 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}
LEAF/leaf.h+24−27
@@ -22,45 +22,42 @@ · 21 unmodified lines
22#include ".\Inc\leaf-global.h"22#include ".\Inc\leaf-global.h"
23#include ".\Inc\leaf-math.h"23#include ".\Inc\leaf-math.h"
24#include ".\Inc\leaf-mempool.h"24#include ".\Inc\leaf-mempool.h"
25#include ".\Inc\leaf-utilities.h"25#include ".\Inc\leaf-tables.h"
26#include ".\Inc\leaf-tables.h"
27#include ".\Inc\leaf-oscillators.h"
28#include ".\Inc\leaf-filters.h"
26#include ".\Inc\leaf-delay.h"29#include ".\Inc\leaf-delay.h"
27#include ".\Inc\leaf-filter.h"
28#include ".\Inc\leaf-oscillator.h"
29#include ".\Inc\leaf-oversampler.h"
30#include ".\Inc\leaf-reverb.h"30#include ".\Inc\leaf-reverb.h"
31#include ".\Inc\leaf-vocoder.h"31#include ".\Inc\leaf-effects.h"
32#include ".\Inc\leaf-808.h"32#include ".\Inc\leaf-envelopes.h"
33#include ".\Inc\leaf-string.h"33#include ".\Inc\leaf-dynamics.h"
34#include ".\Inc\leaf-pitch.h"34#include ".\Inc\leaf-analysis.h"
35#include ".\Inc\leaf-formant.h"35#include ".\Inc\leaf-instruments.h"
36#include ".\Inc\leaf-midi.h"36#include ".\Inc\leaf-midi.h"
37#include ".\Inc\leaf-sample.h"37#include ".\Inc\leaf-sampling.h"
38#include ".\Inc\leaf-crusher.h"38#include ".\Inc\leaf-physical.h"
39#include ".\Inc\leaf-wavefolder.h"39#include ".\Inc\leaf-electrical.h"
40#include ".\Inc\leaf-tables.h"
41 40
42#else41#else
43 42
44#include "./Inc/leaf-global.h"43#include "./Inc/leaf-global.h"
45#include "./Inc/leaf-math.h"44#include "./Inc/leaf-math.h"
46#include "./Inc/leaf-mempool.h"45#include "./Inc/leaf-mempool.h"
47#include "./Inc/leaf-utilities.h"46#include "./Inc/leaf-tables.h"
47#include "./Inc/leaf-tables.h"
48#include "./Inc/leaf-oscillators.h"
49#include "./Inc/leaf-filters.h"
48#include "./Inc/leaf-delay.h"50#include "./Inc/leaf-delay.h"
49#include "./Inc/leaf-filter.h"
50#include "./Inc/leaf-oscillator.h"
51#include "./Inc/leaf-oversampler.h"
52#include "./Inc/leaf-reverb.h"51#include "./Inc/leaf-reverb.h"
53#include "./Inc/leaf-vocoder.h"52#include "./Inc/leaf-effects.h"
54#include "./Inc/leaf-808.h"53#include "./Inc/leaf-envelopes.h"
55#include "./Inc/leaf-string.h"54#include "./Inc/leaf-dynamics.h"
56#include "./Inc/leaf-pitch.h"55#include "./Inc/leaf-analysis.h"
57#include "./Inc/leaf-formant.h"56#include "./Inc/leaf-instruments.h"
58#include "./Inc/leaf-midi.h"57#include "./Inc/leaf-midi.h"
59#include "./Inc/leaf-sample.h"58#include "./Inc/leaf-sampling.h"
60#include "./Inc/leaf-crusher.h"59#include "./Inc/leaf-physical.h"
61#include "./Inc/leaf-wavefolder.h"60#include "./Inc/leaf-electrical.h"
62#include "./Inc/leaf-tables.h"
63#include "./Inc/leaf-WDF.h"
64 61
65#endif62#endif
66 63
LEAF_JUCEPlugin/LEAF.jucer+38−40
@@ -26,53 +26,51 @@ · 25 unmodified lines
26 <FILE id="IwBoc4" name="leaf-global.h" compile="0" resource="0" file="../LEAF/Inc/leaf-global.h"/>26 <FILE id="IwBoc4" name="leaf-global.h" compile="0" resource="0" file="../LEAF/Inc/leaf-global.h"/>
27 <FILE id="cmehFw" name="leaf-math.h" compile="0" resource="0" file="../LEAF/Inc/leaf-math.h"/>27 <FILE id="cmehFw" name="leaf-math.h" compile="0" resource="0" file="../LEAF/Inc/leaf-math.h"/>
28 <FILE id="XQTGHV" name="leaf-mempool.h" compile="0" resource="0" file="../LEAF/Inc/leaf-mempool.h"/>28 <FILE id="XQTGHV" name="leaf-mempool.h" compile="0" resource="0" file="../LEAF/Inc/leaf-mempool.h"/>
29 <FILE id="k0yQ8k" name="leaf-808.h" compile="0" resource="0" file="../LEAF/Inc/leaf-808.h"/>29 <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/>
30 <FILE id="ZBcTKF" name="leaf-oscillators.h" compile="0" resource="0"
31 file="../LEAF/Inc/leaf-oscillators.h"/>
32 <FILE id="EnRmjE" name="leaf-filters.h" compile="0" resource="0" file="../LEAF/Inc/leaf-filters.h"/>
30 <FILE id="wn8tAr" name="leaf-delay.h" compile="0" resource="0" file="../LEAF/Inc/leaf-delay.h"/>33 <FILE id="wn8tAr" name="leaf-delay.h" compile="0" resource="0" file="../LEAF/Inc/leaf-delay.h"/>
31 <FILE id="EnRmjE" name="leaf-filter.h" compile="0" resource="0" file="../LEAF/Inc/leaf-filter.h"/>
32 <FILE id="dWHebV" name="leaf-formant.h" compile="0" resource="0" file="../LEAF/Inc/leaf-formant.h"/>
33 <FILE id="pXe6b5" name="leaf-midi.h" compile="0" resource="0" file="../LEAF/Inc/leaf-midi.h"/>
34 <FILE id="ZBcTKF" name="leaf-oscillator.h" compile="0" resource="0"
35 file="../LEAF/Inc/leaf-oscillator.h"/>
36 <FILE id="LPMRGU" name="leaf-oversampler.h" compile="0" resource="0"
37 file="../LEAF/Inc/leaf-oversampler.h"/>
38 <FILE id="NekKkK" name="leaf-pitch.h" compile="0" resource="0" file="../LEAF/Inc/leaf-pitch.h"/>
39 <FILE id="XmL4ZE" name="leaf-reverb.h" compile="0" resource="0" file="../LEAF/Inc/leaf-reverb.h"/>34 <FILE id="XmL4ZE" name="leaf-reverb.h" compile="0" resource="0" file="../LEAF/Inc/leaf-reverb.h"/>
40 <FILE id="KQca5l" name="leaf-string.h" compile="0" resource="0" file="../LEAF/Inc/leaf-string.h"/>35 <FILE id="dWHebV" name="leaf-distortion.h" compile="0" resource="0"
41 <FILE id="OS2D83" name="leaf-utilities.h" compile="0" resource="0"36 file="../LEAF/Inc/leaf-distortion.h"/>
42 file="../LEAF/Inc/leaf-utilities.h"/>37 <FILE id="Szb5LP" name="leaf-effects.h" compile="0" resource="0" file="../LEAF/Inc/leaf-effects.h"/>
43 <FILE id="Szb5LP" name="leaf-vocoder.h" compile="0" resource="0" file="../LEAF/Inc/leaf-vocoder.h"/>38 <FILE id="OS2D83" name="leaf-envelopes.h" compile="0" resource="0"
44 <FILE id="T6KXi7" name="leaf-sample.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sample.h"/>39 file="../LEAF/Inc/leaf-envelopes.h"/>
45 <FILE id="bpUZCA" name="leaf-crusher.h" compile="0" resource="0" file="../LEAF/Inc/leaf-crusher.h"/>40 <FILE id="PRkOp2" name="leaf-dynamics.h" compile="0" resource="0" file="../LEAF/Inc/leaf-dynamics.h"/>
46 <FILE id="PRkOp2" name="leaf-wavefolder.h" compile="0" resource="0"41 <FILE id="LPMRGU" name="leaf-analysis.h" compile="0" resource="0" file="../LEAF/Inc/leaf-analysis.h"/>
47 file="../LEAF/Inc/leaf-wavefolder.h"/>42 <FILE id="k0yQ8k" name="leaf-instruments.h" compile="0" resource="0"
48 <FILE id="lJdTFA" name="leaf-WDF.h" compile="0" resource="0" file="../LEAF/Inc/leaf-WDF.h"/>43 file="../LEAF/Inc/leaf-instruments.h"/>
49 <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/>44 <FILE id="pXe6b5" name="leaf-midi.h" compile="0" resource="0" file="../LEAF/Inc/leaf-midi.h"/>
45 <FILE id="T6KXi7" name="leaf-sampling.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sampling.h"/>
46 <FILE id="KQca5l" name="leaf-physical.h" compile="0" resource="0" file="../LEAF/Inc/leaf-physical.h"/>
47 <FILE id="lJdTFA" name="leaf-electrical.h" compile="0" resource="0"
48 file="../LEAF/Inc/leaf-electrical.h"/>
50 </GROUP>49 </GROUP>
51 <GROUP id="{A3AE8C8C-29BA-ADB3-DD7D-EEDC2F7B58F3}" name="Src">50 <GROUP id="{A3AE8C8C-29BA-ADB3-DD7D-EEDC2F7B58F3}" name="Src">
52 <FILE id="HbG7LO" name="leaf-808.c" compile="1" resource="0" file="../LEAF/Src/leaf-808.c"/>51 <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/>
53 <FILE id="lLb7eq" name="leaf-delay.c" compile="1" resource="0" file="../LEAF/Src/leaf-delay.c"/>
54 <FILE id="nh9xAo" name="leaf-filter.c" compile="1" resource="0" file="../LEAF/Src/leaf-filter.c"/>
55 <FILE id="DPGZGc" name="leaf-formant.c" compile="1" resource="0" file="../LEAF/Src/leaf-formant.c"/>
56 <FILE id="g41P2E" name="leaf-math.c" compile="1" resource="0" file="../LEAF/Src/leaf-math.c"/>52 <FILE id="g41P2E" name="leaf-math.c" compile="1" resource="0" file="../LEAF/Src/leaf-math.c"/>
57 <FILE id="Uc4jO6" name="leaf-mempool.c" compile="1" resource="0" file="../LEAF/Src/leaf-mempool.c"/>53 <FILE id="Uc4jO6" name="leaf-mempool.c" compile="1" resource="0" file="../LEAF/Src/leaf-mempool.c"/>
58 <FILE id="LuoIDh" name="leaf-midi.c" compile="1" resource="0" file="../LEAF/Src/leaf-midi.c"/>
59 <FILE id="q5y59A" name="leaf-oscillator.c" compile="1" resource="0"
60 file="../LEAF/Src/leaf-oscillator.c"/>
61 <FILE id="E8JjWS" name="leaf-oversampler.c" compile="1" resource="0"
62 file="../LEAF/Src/leaf-oversampler.c"/>
63 <FILE id="eHUTvP" name="leaf-pitch.c" compile="1" resource="0" file="../LEAF/Src/leaf-pitch.c"/>
64 <FILE id="uyYwEd" name="leaf-reverb.c" compile="1" resource="0" file="../LEAF/Src/leaf-reverb.c"/>
65 <FILE id="dgAVr5" name="leaf-string.c" compile="1" resource="0" file="../LEAF/Src/leaf-string.c"/>
66 <FILE id="uKHzgz" name="leaf-utilities.c" compile="1" resource="0"
67 file="../LEAF/Src/leaf-utilities.c"/>
68 <FILE id="u1aLLR" name="leaf-vocoder.c" compile="1" resource="0" file="../LEAF/Src/leaf-vocoder.c"/>
69 <FILE id="nmtoFJ" name="leaf-sample.c" compile="1" resource="0" file="../LEAF/Src/leaf-sample.c"/>
70 <FILE id="Oymcac" name="leaf-crusher.c" compile="1" resource="0" file="../LEAF/Src/leaf-crusher.c"/>
71 <FILE id="LVoaGm" name="leaf-wavefolder.c" compile="1" resource="0"
72 file="../LEAF/Src/leaf-wavefolder.c"/>
73 <FILE id="Oh72PT" name="leaf-WDF.c" compile="1" resource="0" file="../LEAF/Src/leaf-WDF.c"/>
74 <FILE id="TxA1Gg" name="leaf-tables.c" compile="1" resource="0" file="../LEAF/Src/leaf-tables.c"/>54 <FILE id="TxA1Gg" name="leaf-tables.c" compile="1" resource="0" file="../LEAF/Src/leaf-tables.c"/>
75 <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/>55 <FILE id="q5y59A" name="leaf-oscillators.c" compile="1" resource="0"
56 file="../LEAF/Src/leaf-oscillators.c"/>
57 <FILE id="nh9xAo" name="leaf-filters.c" compile="1" resource="0" file="../LEAF/Src/leaf-filters.c"/>
58 <FILE id="lLb7eq" name="leaf-delay.c" compile="1" resource="0" file="../LEAF/Src/leaf-delay.c"/>
59 <FILE id="uyYwEd" name="leaf-reverb.c" compile="1" resource="0" file="../LEAF/Src/leaf-reverb.c"/>
60 <FILE id="E8JjWS" name="leaf-distortion.c" compile="1" resource="0"
61 file="../LEAF/Src/leaf-distortion.c"/>
62 <FILE id="u1aLLR" name="leaf-effects.c" compile="1" resource="0" file="../LEAF/Src/leaf-effects.c"/>
63 <FILE id="uKHzgz" name="leaf-envelopes.c" compile="1" resource="0"
64 file="../LEAF/Src/leaf-envelopes.c"/>
65 <FILE id="Oymcac" name="leaf-dynamics.c" compile="1" resource="0" file="../LEAF/Src/leaf-dynamics.c"/>
66 <FILE id="LVoaGm" name="leaf-analysis.c" compile="1" resource="0" file="../LEAF/Src/leaf-analysis.c"/>
67 <FILE id="HbG7LO" name="leaf-instruments.c" compile="1" resource="0"
68 file="../LEAF/Src/leaf-instruments.c"/>
69 <FILE id="LuoIDh" name="leaf-midi.c" compile="1" resource="0" file="../LEAF/Src/leaf-midi.c"/>
70 <FILE id="nmtoFJ" name="leaf-sampling.c" compile="1" resource="0" file="../LEAF/Src/leaf-sampling.c"/>
71 <FILE id="dgAVr5" name="leaf-physical.c" compile="1" resource="0" file="../LEAF/Src/leaf-physical.c"/>
72 <FILE id="Oh72PT" name="leaf-electrical.c" compile="1" resource="0"
73 file="../LEAF/Src/leaf-electrical.c"/>
76 </GROUP>74 </GROUP>
77 <FILE id="dmljDQ" name="leaf.h" compile="0" resource="0" file="../LEAF/leaf.h"/>75 <FILE id="dmljDQ" name="leaf.h" compile="0" resource="0" file="../LEAF/leaf.h"/>
78 </GROUP>76 </GROUP>
LEAF_JUCEPlugin/Source/MyTest.cpp+3−1
@@ -37,6 +37,8 @@ void LEAFTest_init (float sampleRate, int blockSize) · 36 unmodified lines
37 tCycle_init(&sine);37 tCycle_init(&sine);
38 tCycle_setFreq(&sine, 200);38 tCycle_setFreq(&sine, 200);
39 tDelay_init(&delay, 44100, 44100);39 tDelay_init(&delay, 44100, 44100);
40 tDelay_free(&delay); //most basic free test
41 tDelay_init(&delay, 44100, 44100);
40}42}
41 43
42float LEAFTest_tick (float input)44float LEAFTest_tick (float input)
@@ -98,7 +100,7 @@ void leaf_pool_report(void) · 55 unmodified lines
98void leaf_pool_dump(void)100void leaf_pool_dump(void)
99{101{
100 float* buff = (float*)leaf_pool_get_pool();102 float* buff = (float*)leaf_pool_get_pool();
101 int siz = leaf_pool_get_size();103 unsigned long siz = leaf_pool_get_size();
102 siz /= sizeof(float);104 siz /= sizeof(float);
103 for (int i = 0; i < siz; i++)105 for (int i = 0; i < siz; i++)
104 {106 {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t