annotate examples/airharp/render.cpp @ 380:9dc5a0ccad25 prerelease

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