comparison projects/airharp/render.cpp @ 164:40badaff5729 heavy-updated

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