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