comparison examples/10-Instruments/airharp/render.cpp @ 464:8fcfbfb32aa0 prerelease

Examples reorder with subdirectories. Added header to each project. Moved Doxygen to bottom of render.cpp.
author Robert Jack <robert.h.jack@gmail.com>
date Mon, 20 Jun 2016 16:20:38 +0100
parents
children 8f8809c77dda
comparison
equal deleted inserted replaced
463:c47709e8b5c9 464:8fcfbfb32aa0
1 /*
2 * AIR-HARP
3 * Physically modelled strings using waveguide junctions and mass-spring-dampers
4 *
5 * render.cpp
6 *
7 * Christian Heinrichs 04/2015
8 *
9 */
10
11
12 #include "MassSpringDamper.h"
13 #include "String.h"
14 #include "Plectrum.h"
15
16 #include <Bela.h>
17 #include <cmath>
18 #include <stdio.h>
19 #include <cstdlib>
20 #include <rtdk.h>
21
22 #define ACCEL_BUF_SIZE 8
23 #define NUMBER_OF_STRINGS 9
24
25 // PENTATONIC SCALE
26 float gMidinotes[NUMBER_OF_STRINGS] = {40,45,50,55,57,60,62,64,67};
27
28 float gInverseSampleRate;
29
30 float out_gain = 5.0;
31
32 int accelPin_x = 0;
33 int accelPin_y = 1;
34 int accelPin_z = 2;
35
36 MassSpringDamper msd = MassSpringDamper(1,0.1,10);// (10,0.001,10);
37 String strings[NUMBER_OF_STRINGS];
38 Plectrum plectrums[NUMBER_OF_STRINGS];
39
40 float gPlectrumDisplacement = 0;
41
42 float gAccel_x[ACCEL_BUF_SIZE] = {0};
43 int gAccelReadPtr = 0;
44
45 // DC BLOCK BUTTERWORTH
46
47 // Coefficients for 100hz cut-off
48 float a0_l = 0.9899759179893742;
49 float a1_l = -1.9799518359787485;
50 float a2_l = 0.9899759179893742;
51 float a3_l = -1.979851353142371;
52 float a4_l = 0.9800523188151258;
53
54 float a0_r = a0_l;
55 float a1_r = a1_l;
56 float a2_r = a2_l;
57 float a3_r = a3_l;
58 float a4_r = a4_l;
59
60 float x1_l = 0;
61 float x2_l = 0;
62 float y1_l = 0;
63 float y2_l = 0;
64
65 float x1_r = 0;
66 float x2_r = 0;
67 float y1_r = 0;
68 float y2_r = 0;
69
70
71 bool setup(BelaContext *context, void *userData)
72 {
73
74 gInverseSampleRate = 1.0 / context->audioSampleRate;
75
76 // initialise strings & plectrums
77 for(int i=0;i<NUMBER_OF_STRINGS;i++) {
78
79 plectrums[i] = Plectrum();
80 plectrums[i].setup(250,0.25,0.05);
81
82 strings[i] = String();
83 strings[i].setMidinote(gMidinotes[i]);
84
85 float spacing = 2.0 / (NUMBER_OF_STRINGS+1);
86
87 strings[i].setGlobalPosition( -1 + spacing*(i+1) );
88
89 rt_printf("STRING %d // midinote: %f position: %f\n",i,gMidinotes[i],( -1 + spacing*(i+1) ));
90
91 }
92
93 return true;
94 }
95
96 void render(BelaContext *context, void *userData)
97 {
98
99 float lastAccel = 0;
100
101 for(int n = 0; n < context->audioFrames; n++) {
102
103 /*
104 *
105 * ACCELEROMETER DATA
106 *
107 */
108
109 // Read accelerometer data from analog input
110 float accel_x = 0;
111 if(n%2) {
112 accel_x = (float)context->analogIn[(n/2)*8+accelPin_x] * 2 - 1; // 15800 - 28300 - 41500
113 lastAccel = accel_x;
114 } else {
115 // grab previous value if !n%2
116 accel_x = lastAccel;
117 }
118
119 // Dead-zone avoids noise when box is lying horizontally on a surface
120
121 float accelDeadZone = 0.1;
122
123 if(accel_x <= accelDeadZone && accel_x >= -accelDeadZone)
124 accel_x = 0;
125
126 // Perform smoothing (moving average) on acceleration value
127 if(++gAccelReadPtr >= ACCEL_BUF_SIZE)
128 gAccelReadPtr = 0;
129 gAccel_x[gAccelReadPtr] = accel_x;
130 float gravity = 0;
131 for(int i=0;i<ACCEL_BUF_SIZE;i++) {
132 gravity = gAccel_x[(gAccelReadPtr-i+ACCEL_BUF_SIZE)%ACCEL_BUF_SIZE];
133 }
134 gravity /= ACCEL_BUF_SIZE;
135
136 /*
137 *
138 * PHYSICS SIMULATION
139 *
140 */
141
142 // The horizontal force (which can be gravity if box is tipped on its side)
143 // is used as the input to a Mass-Spring-Damper model
144 // Plectrum displacement (i.e. when interacting with string) is included
145 float massPosition = (float)msd.update(gravity - gPlectrumDisplacement);
146
147 float out_l = 0;
148 float out_r = 0;
149 // Use this parameter to quickly adjust output gain
150 float gain = 0.0015; // 0.0015 is a good value or 12 strings
151 gPlectrumDisplacement = 0;
152
153 for(int s=0;s<NUMBER_OF_STRINGS;s++) {
154
155 float stringPosition = strings[s].getGlobalPosition();
156
157 float plectrumForce = plectrums[s].update(massPosition, stringPosition);
158 gPlectrumDisplacement += strings[s].getPlectrumDisplacement();
159
160 // calculate panning based on string position (-1->left / 1->right)
161 float panRight = map(stringPosition,1,-1,0.1,1);
162 float panLeft = map(stringPosition,-1,1,0.1,1);
163 panRight *= panRight;
164 panLeft *= panLeft;
165
166 float out = strings[s].update(plectrumForce)*gain;
167
168 out_l += out*panLeft;
169 out_r += out*panRight;
170
171 }
172
173 // APPLY DC-BLOCK FILTER TO OUTPUTS
174
175 // LEFT CHANNEL
176 float temp_in = out_l;
177 /* compute result */
178 out_l = a0_l * out_l + a1_l * x1_l + a2_l * x2_l - a3_l * y1_l - a4_l * y2_l;
179 /* shift x1 to x2, sample to x1 */
180 x2_l = x1_l;
181 x1_l = temp_in;
182 /* shift y1 to y2, result to y1 */
183 y2_l = y1_l;
184 y1_l = out_l;
185
186 // RIGHT CHANNEL
187 temp_in = out_r;
188 /* compute result */
189 out_r = a0_r * out_r + a1_r * x1_r + a2_r * x2_r - a3_r * y1_r - a4_r * y2_r;
190 /* shift x1 to x2, sample to x1 */
191 x2_r = x1_r;
192 x1_r = temp_in;
193 /* shift y1 to y2, result to y1 */
194 y2_r = y1_r;
195 y1_r = out_r;
196
197 context->audioOut[n * context->audioChannels + 1] = out_l * out_gain;
198 context->audioOut[n * context->audioChannels + 0] = out_r * out_gain;
199
200 }
201
202 }
203
204
205 // cleanup_render() is called once at the end, after the audio has stopped.
206 // Release any resources that were allocated in initialise_render().
207
208 void cleanup(BelaContext *context, void *userData)
209 {
210
211 }