andrewm@0
|
1 /*
|
andrewm@0
|
2 * FeedbackOscillator.cpp
|
andrewm@0
|
3 *
|
andrewm@0
|
4 * Recursive phase-shift oscillator implemented
|
andrewm@0
|
5 * on the matrix
|
andrewm@0
|
6 *
|
andrewm@0
|
7 * Andrew McPherson 2014
|
andrewm@0
|
8 */
|
andrewm@0
|
9
|
andrewm@0
|
10 #include "FeedbackOscillator.h"
|
andrewm@0
|
11 #include <cstdlib>
|
andrewm@0
|
12 #include <cmath>
|
andrewm@0
|
13
|
andrewm@0
|
14 #define COEFF_B0 0
|
andrewm@0
|
15 #define COEFF_B1 1
|
andrewm@0
|
16 #define COEFF_A1 2
|
andrewm@0
|
17
|
andrewm@0
|
18 FeedbackOscillator::FeedbackOscillator()
|
andrewm@0
|
19 : wavetable1(0), wavetable2(0)
|
andrewm@0
|
20 {
|
andrewm@0
|
21
|
andrewm@0
|
22 }
|
andrewm@0
|
23
|
andrewm@0
|
24 FeedbackOscillator::~FeedbackOscillator() {
|
andrewm@0
|
25 if(wavetable1 != 0)
|
andrewm@0
|
26 free(wavetable1);
|
andrewm@0
|
27 if(wavetable2 != 0)
|
andrewm@0
|
28 free(wavetable2);
|
andrewm@0
|
29
|
andrewm@0
|
30 }
|
andrewm@0
|
31
|
andrewm@0
|
32 // Initialise the settings for the feedback oscillator
|
andrewm@0
|
33 void FeedbackOscillator::initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate) {
|
andrewm@0
|
34 wavetableMaxLength = maxTableSize;
|
andrewm@0
|
35 if(wavetable1 != 0)
|
andrewm@0
|
36 free(wavetable1);
|
andrewm@0
|
37 if(wavetable2 != 0)
|
andrewm@0
|
38 free(wavetable2);
|
andrewm@0
|
39
|
andrewm@0
|
40 wavetable1 = (float *)malloc(maxTableSize * sizeof(float));
|
andrewm@0
|
41 wavetable2 = (float *)malloc(maxTableSize * sizeof(float));
|
andrewm@0
|
42
|
andrewm@0
|
43 float omega = tan(M_PI * hpfCutoffFrequency / matrixSampleRate);
|
andrewm@0
|
44 float n = 1.0f / (1.0f + omega);
|
andrewm@0
|
45
|
andrewm@0
|
46 coeffs[COEFF_A1] = (omega - 1.0f) * n;
|
andrewm@0
|
47 coeffs[COEFF_B0] = n;
|
andrewm@0
|
48 coeffs[COEFF_B1] = -n;
|
andrewm@0
|
49
|
andrewm@0
|
50 for(int n = 0; n < maxTableSize; n++)
|
andrewm@0
|
51 wavetable1[n] = wavetable2[n] = 0;
|
andrewm@0
|
52
|
andrewm@0
|
53 wavetableRead = wavetable1;
|
andrewm@0
|
54 wavetableWrite = wavetable2;
|
andrewm@0
|
55 wavetableWritePointer = 0;
|
andrewm@0
|
56 sampleCount = lastTriggerCount = 0;
|
andrewm@0
|
57 }
|
andrewm@0
|
58
|
andrewm@0
|
59 // Process one sample and store the output value
|
andrewm@0
|
60 // Returns true if the wavetable needs rendering
|
andrewm@0
|
61 int FeedbackOscillator::process(uint16_t input, uint16_t *output) {
|
andrewm@0
|
62 float inFloat = input / 65536.0;
|
andrewm@0
|
63 float outFloat = coeffs[COEFF_B0] * inFloat + coeffs[COEFF_B1] * lastInput - coeffs[COEFF_A1] * lastOutput;
|
andrewm@0
|
64 int requestRenderLength = 0;
|
andrewm@0
|
65
|
andrewm@0
|
66 //outFloat *= 2.0;
|
andrewm@0
|
67
|
andrewm@0
|
68 int intOut = outFloat * 65536.0 + 32768;
|
andrewm@0
|
69 if(intOut > 65535)
|
andrewm@0
|
70 intOut = 65535;
|
andrewm@0
|
71 if(intOut < 0)
|
andrewm@0
|
72 intOut = 0;
|
andrewm@0
|
73 //intOut = (intOut & 0xFF) << 8;
|
andrewm@0
|
74 //if(intOut > 65535)
|
andrewm@0
|
75 // intOut = 65535;
|
andrewm@0
|
76
|
andrewm@0
|
77 *output = (uint16_t)intOut;
|
andrewm@0
|
78
|
andrewm@0
|
79 if(canTrigger && outFloat > 0 && lastOutput <= 0) {
|
andrewm@0
|
80 triggered = true;
|
andrewm@0
|
81 requestRenderLength = wavetableWritePointer; // How many samples stored thus far?
|
andrewm@0
|
82 if(requestRenderLength < 4)
|
andrewm@0
|
83 requestRenderLength = 0; // Ignore anything with fewer than 4 points
|
andrewm@0
|
84
|
andrewm@0
|
85 lastTriggerCount = sampleCount;
|
andrewm@0
|
86 canTrigger = false;
|
andrewm@0
|
87 wavetableWritePointer = 0;
|
andrewm@0
|
88
|
andrewm@0
|
89 // Swap buffers
|
andrewm@0
|
90 float *temp = wavetableWrite;
|
andrewm@0
|
91 wavetableWrite = wavetableRead;
|
andrewm@0
|
92 wavetableRead = temp;
|
andrewm@0
|
93 }
|
andrewm@0
|
94
|
andrewm@0
|
95 if(triggered) {
|
andrewm@0
|
96 wavetableWrite[wavetableWritePointer] = outFloat;
|
andrewm@0
|
97 if(++wavetableWritePointer >= wavetableMaxLength) {
|
andrewm@0
|
98 triggered = false;
|
andrewm@0
|
99 wavetableWritePointer = 0;
|
andrewm@0
|
100 }
|
andrewm@0
|
101 }
|
andrewm@0
|
102
|
andrewm@0
|
103 if(sampleCount - lastTriggerCount > 40)
|
andrewm@0
|
104 canTrigger = true;
|
andrewm@0
|
105
|
andrewm@0
|
106 sampleCount++;
|
andrewm@0
|
107
|
andrewm@0
|
108 lastOutput = outFloat;
|
andrewm@0
|
109 lastInput = inFloat;
|
andrewm@0
|
110
|
andrewm@0
|
111 return requestRenderLength;
|
andrewm@0
|
112 }
|