robert@464
|
1 /*
|
robert@464
|
2 *
|
robert@464
|
3 * Simple 1-Dimensional Waveguide
|
robert@464
|
4 *
|
robert@464
|
5 */
|
robert@464
|
6
|
robert@464
|
7 #include "Waveguide.h"
|
robert@464
|
8 #include "../include/Utilities.h"
|
robert@464
|
9 #include <rtdk.h>
|
robert@464
|
10 #include <cmath>
|
robert@464
|
11 #include <stdio.h>
|
robert@464
|
12 #include <cstdlib>
|
robert@464
|
13
|
robert@464
|
14 #define DECAY 0.995//0.999
|
robert@464
|
15 #define DAMPING 0.01//0.05
|
robert@464
|
16
|
robert@464
|
17 // TODO: make damping and decay parametrisable
|
robert@464
|
18
|
robert@464
|
19 Waveguide::Waveguide() {
|
robert@464
|
20
|
robert@464
|
21 // initialize variables
|
robert@464
|
22 a1_lp = 0;
|
robert@464
|
23 a2_lp = 0;
|
robert@464
|
24 b0_lp = 0;
|
robert@464
|
25 b1_lp = 0;
|
robert@464
|
26 b2_lp = 0;
|
robert@464
|
27 _dt = 1.0/44100.0;
|
robert@464
|
28 setFrequency(440);
|
robert@464
|
29 updateFilterCoeffs(8000);
|
robert@464
|
30 _filterReadPtr=0;
|
robert@464
|
31 for(int i=0;i<FILTER_BUFFER_SIZE;i++) {
|
robert@464
|
32 _filterBuffer_x[i] = 0;
|
robert@464
|
33 _filterBuffer_y[i] = 0;
|
robert@464
|
34 }
|
robert@464
|
35 for(int i=0;i<WG_BUFFER_SIZE;i++) {
|
robert@464
|
36 _buffer[i] = 0;
|
robert@464
|
37 }
|
robert@464
|
38 _lastX = 0;
|
robert@464
|
39 _lastY = 0;
|
robert@464
|
40 _readPtr = 0;
|
robert@464
|
41
|
robert@464
|
42 }
|
robert@464
|
43
|
robert@464
|
44 void Waveguide::setup() {
|
robert@464
|
45
|
robert@464
|
46 }
|
robert@464
|
47
|
robert@464
|
48 float Waveguide::update(float in) {
|
robert@464
|
49
|
robert@464
|
50 // 1. advance delay buffer read pointer
|
robert@464
|
51
|
robert@464
|
52 if(++_readPtr>=WG_BUFFER_SIZE)
|
robert@464
|
53 _readPtr=0;
|
robert@464
|
54
|
robert@464
|
55 // 2. write input into buffer
|
robert@464
|
56
|
robert@464
|
57 _buffer[_readPtr] = in;
|
robert@464
|
58
|
robert@464
|
59 // 3. read delayed sample from buffer
|
robert@464
|
60
|
robert@464
|
61 float out = _buffer[(_readPtr-_periodInSamples+WG_BUFFER_SIZE)%WG_BUFFER_SIZE];
|
robert@464
|
62
|
robert@464
|
63 // 4. apply damping (low-pass) filter to output
|
robert@464
|
64
|
robert@464
|
65 if(++_filterReadPtr>=FILTER_BUFFER_SIZE)
|
robert@464
|
66 _filterReadPtr=0;
|
robert@464
|
67
|
robert@464
|
68 out = b0_lp*out +
|
robert@464
|
69 b1_lp*_filterBuffer_x[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] +
|
robert@464
|
70 b2_lp*_filterBuffer_x[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] -
|
robert@464
|
71 a1_lp*_filterBuffer_y[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] -
|
robert@464
|
72 a2_lp*_filterBuffer_y[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE];
|
robert@464
|
73
|
robert@464
|
74 // 5. Simple high-pass filter to block DC-offset
|
robert@464
|
75 // y[n] = x[n] - x[n-1] + a * y[n-1]
|
robert@464
|
76 float gain = 0.9999;
|
robert@464
|
77 float temp = out;
|
robert@464
|
78 out = out - _lastX + gain * _lastY;
|
robert@464
|
79 _lastY = out;
|
robert@464
|
80 _lastX = temp;
|
robert@464
|
81
|
robert@464
|
82 // 6. Apply intensity damping
|
robert@464
|
83 out *= DECAY;
|
robert@464
|
84
|
robert@464
|
85 _filterBuffer_x[_filterReadPtr] = in;
|
robert@464
|
86 _filterBuffer_y[_filterReadPtr] = out;
|
robert@464
|
87
|
robert@464
|
88 return out;
|
robert@464
|
89
|
robert@464
|
90 }
|
robert@464
|
91
|
robert@464
|
92 void Waveguide::setFrequency(float frequency) {
|
robert@464
|
93
|
robert@464
|
94 // NB: currently no interpolation, so may not be ideal for dynamically changing waveguide frequency
|
robert@464
|
95 _periodInMilliseconds = 1000.0/frequency;
|
robert@464
|
96 _periodInSamples = (int)(_periodInMilliseconds * 44.1);
|
robert@464
|
97
|
robert@464
|
98 }
|
robert@464
|
99
|
robert@464
|
100 void Waveguide::updateFilterCoeffs(float frequency) {
|
robert@464
|
101
|
robert@464
|
102 // FIXME: Butterworth filter doesn't work very well,
|
robert@464
|
103 // using simple FIR in the meantime
|
robert@464
|
104
|
robert@464
|
105 a1_lp = 0;
|
robert@464
|
106 a2_lp = 0;
|
robert@464
|
107 b0_lp = 1.0 - DAMPING;
|
robert@464
|
108 b1_lp = DAMPING;
|
robert@464
|
109 b2_lp = 0;
|
robert@464
|
110
|
robert@464
|
111 /*
|
robert@464
|
112 // 'w' for sake of resembling lower-case 'omega'
|
robert@464
|
113 float w = 2.0 * M_PI * frequency;
|
robert@464
|
114 float t = _dt;
|
robert@464
|
115 // The Q for a 2nd-order Butterworth is sqrt(2)/2
|
robert@464
|
116 float q = 0.707;//sqrt(2.0)/2.0;
|
robert@464
|
117
|
robert@464
|
118 // low-pass filter coefficients
|
robert@464
|
119 float a0_lp = w*w*t*t + 2*(w/q)*t + 4.0;
|
robert@464
|
120 float k = 1.0/a0_lp;
|
robert@464
|
121 a1_lp = (2.0*w*w*t*t - 8.0) * k;
|
robert@464
|
122 a2_lp = (4.0 - (w/q)*2.0*t + w*w*t*t) * k;
|
robert@464
|
123 b0_lp = (w*w*t*t) * k;
|
robert@464
|
124 b1_lp = (2.0*w*w*t*t) * k;
|
robert@464
|
125 b2_lp = (w*w*t*t) * k;
|
robert@464
|
126 */
|
robert@464
|
127
|
robert@464
|
128 }
|