annotate examples/10-Instruments/airharp/render.cpp @ 543:8f8809c77dda prerelease

updated basics, digital, instruments, extras examples
author chnrx <chris.heinrichs@gmail.com>
date Fri, 24 Jun 2016 13:19:52 +0100
parents 8fcfbfb32aa0
children
rev   line source
chris@543 1 /*
chris@543 2 ____ _____ _ _
chris@543 3 | __ )| ____| | / \
chris@543 4 | _ \| _| | | / _ \
chris@543 5 | |_) | |___| |___ / ___ \
chris@543 6 |____/|_____|_____/_/ \_\
chris@543 7
chris@543 8 The platform for ultra-low latency audio and sensor processing
chris@543 9
chris@543 10 http://bela.io
chris@543 11
chris@543 12 A project of the Augmented Instruments Laboratory within the
chris@543 13 Centre for Digital Music at Queen Mary University of London.
chris@543 14 http://www.eecs.qmul.ac.uk/~andrewm
chris@543 15
chris@543 16 (c) 2016 Augmented Instruments Laboratory: Andrew McPherson,
chris@543 17 Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack,
chris@543 18 Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved.
chris@543 19
chris@543 20 The Bela software is distributed under the GNU Lesser General Public License
chris@543 21 (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt
chris@543 22 */
chris@543 23
chris@543 24
robert@464 25 /*
robert@464 26 * AIR-HARP
robert@464 27 * Physically modelled strings using waveguide junctions and mass-spring-dampers
chris@543 28 * controllable using an accelerometer
robert@464 29 *
robert@464 30 * render.cpp
robert@464 31 *
robert@464 32 * Christian Heinrichs 04/2015
robert@464 33 *
robert@464 34 */
robert@464 35
robert@464 36
robert@464 37 #include "MassSpringDamper.h"
robert@464 38 #include "String.h"
robert@464 39 #include "Plectrum.h"
robert@464 40
robert@464 41 #include <Bela.h>
robert@464 42 #include <cmath>
robert@464 43 #include <stdio.h>
robert@464 44 #include <cstdlib>
robert@464 45 #include <rtdk.h>
robert@464 46
robert@464 47 #define ACCEL_BUF_SIZE 8
robert@464 48 #define NUMBER_OF_STRINGS 9
robert@464 49
robert@464 50 // PENTATONIC SCALE
robert@464 51 float gMidinotes[NUMBER_OF_STRINGS] = {40,45,50,55,57,60,62,64,67};
robert@464 52
robert@464 53 float gInverseSampleRate;
robert@464 54
robert@464 55 float out_gain = 5.0;
robert@464 56
robert@464 57 int accelPin_x = 0;
robert@464 58 int accelPin_y = 1;
robert@464 59 int accelPin_z = 2;
robert@464 60
robert@464 61 MassSpringDamper msd = MassSpringDamper(1,0.1,10);// (10,0.001,10);
robert@464 62 String strings[NUMBER_OF_STRINGS];
robert@464 63 Plectrum plectrums[NUMBER_OF_STRINGS];
robert@464 64
robert@464 65 float gPlectrumDisplacement = 0;
robert@464 66
robert@464 67 float gAccel_x[ACCEL_BUF_SIZE] = {0};
robert@464 68 int gAccelReadPtr = 0;
robert@464 69
robert@464 70 // DC BLOCK BUTTERWORTH
robert@464 71
chris@543 72 // Coefficients for 100hz high-pass centre frequency
robert@464 73 float a0_l = 0.9899759179893742;
robert@464 74 float a1_l = -1.9799518359787485;
robert@464 75 float a2_l = 0.9899759179893742;
robert@464 76 float a3_l = -1.979851353142371;
robert@464 77 float a4_l = 0.9800523188151258;
robert@464 78
robert@464 79 float a0_r = a0_l;
robert@464 80 float a1_r = a1_l;
robert@464 81 float a2_r = a2_l;
robert@464 82 float a3_r = a3_l;
robert@464 83 float a4_r = a4_l;
robert@464 84
robert@464 85 float x1_l = 0;
robert@464 86 float x2_l = 0;
robert@464 87 float y1_l = 0;
robert@464 88 float y2_l = 0;
robert@464 89
robert@464 90 float x1_r = 0;
robert@464 91 float x2_r = 0;
robert@464 92 float y1_r = 0;
robert@464 93 float y2_r = 0;
robert@464 94
robert@464 95
robert@464 96 bool setup(BelaContext *context, void *userData)
robert@464 97 {
robert@464 98
robert@464 99 gInverseSampleRate = 1.0 / context->audioSampleRate;
robert@464 100
robert@464 101 // initialise strings & plectrums
robert@464 102 for(int i=0;i<NUMBER_OF_STRINGS;i++) {
robert@464 103
robert@464 104 plectrums[i] = Plectrum();
robert@464 105 plectrums[i].setup(250,0.25,0.05);
robert@464 106
robert@464 107 strings[i] = String();
robert@464 108 strings[i].setMidinote(gMidinotes[i]);
robert@464 109
robert@464 110 float spacing = 2.0 / (NUMBER_OF_STRINGS+1);
robert@464 111
robert@464 112 strings[i].setGlobalPosition( -1 + spacing*(i+1) );
robert@464 113
robert@464 114 rt_printf("STRING %d // midinote: %f position: %f\n",i,gMidinotes[i],( -1 + spacing*(i+1) ));
robert@464 115
robert@464 116 }
robert@464 117
robert@464 118 return true;
robert@464 119 }
robert@464 120
robert@464 121 void render(BelaContext *context, void *userData)
robert@464 122 {
robert@464 123
robert@464 124 float lastAccel = 0;
robert@464 125
robert@464 126 for(int n = 0; n < context->audioFrames; n++) {
robert@464 127
robert@464 128 /*
robert@464 129 *
robert@464 130 * ACCELEROMETER DATA
robert@464 131 *
robert@464 132 */
robert@464 133
robert@464 134 // Read accelerometer data from analog input
robert@464 135 float accel_x = 0;
robert@464 136 if(n%2) {
robert@464 137 accel_x = (float)context->analogIn[(n/2)*8+accelPin_x] * 2 - 1; // 15800 - 28300 - 41500
robert@464 138 lastAccel = accel_x;
robert@464 139 } else {
robert@464 140 // grab previous value if !n%2
robert@464 141 accel_x = lastAccel;
robert@464 142 }
robert@464 143
robert@464 144 // Dead-zone avoids noise when box is lying horizontally on a surface
robert@464 145
robert@464 146 float accelDeadZone = 0.1;
robert@464 147
robert@464 148 if(accel_x <= accelDeadZone && accel_x >= -accelDeadZone)
robert@464 149 accel_x = 0;
robert@464 150
robert@464 151 // Perform smoothing (moving average) on acceleration value
robert@464 152 if(++gAccelReadPtr >= ACCEL_BUF_SIZE)
robert@464 153 gAccelReadPtr = 0;
robert@464 154 gAccel_x[gAccelReadPtr] = accel_x;
robert@464 155 float gravity = 0;
robert@464 156 for(int i=0;i<ACCEL_BUF_SIZE;i++) {
robert@464 157 gravity = gAccel_x[(gAccelReadPtr-i+ACCEL_BUF_SIZE)%ACCEL_BUF_SIZE];
robert@464 158 }
robert@464 159 gravity /= ACCEL_BUF_SIZE;
robert@464 160
robert@464 161 /*
robert@464 162 *
robert@464 163 * PHYSICS SIMULATION
robert@464 164 *
robert@464 165 */
robert@464 166
robert@464 167 // The horizontal force (which can be gravity if box is tipped on its side)
robert@464 168 // is used as the input to a Mass-Spring-Damper model
robert@464 169 // Plectrum displacement (i.e. when interacting with string) is included
robert@464 170 float massPosition = (float)msd.update(gravity - gPlectrumDisplacement);
robert@464 171
robert@464 172 float out_l = 0;
robert@464 173 float out_r = 0;
robert@464 174 // Use this parameter to quickly adjust output gain
robert@464 175 float gain = 0.0015; // 0.0015 is a good value or 12 strings
robert@464 176 gPlectrumDisplacement = 0;
robert@464 177
robert@464 178 for(int s=0;s<NUMBER_OF_STRINGS;s++) {
robert@464 179
robert@464 180 float stringPosition = strings[s].getGlobalPosition();
robert@464 181
robert@464 182 float plectrumForce = plectrums[s].update(massPosition, stringPosition);
robert@464 183 gPlectrumDisplacement += strings[s].getPlectrumDisplacement();
robert@464 184
robert@464 185 // calculate panning based on string position (-1->left / 1->right)
robert@464 186 float panRight = map(stringPosition,1,-1,0.1,1);
robert@464 187 float panLeft = map(stringPosition,-1,1,0.1,1);
robert@464 188 panRight *= panRight;
robert@464 189 panLeft *= panLeft;
robert@464 190
robert@464 191 float out = strings[s].update(plectrumForce)*gain;
robert@464 192
robert@464 193 out_l += out*panLeft;
robert@464 194 out_r += out*panRight;
robert@464 195
robert@464 196 }
robert@464 197
robert@464 198 // APPLY DC-BLOCK FILTER TO OUTPUTS
robert@464 199
robert@464 200 // LEFT CHANNEL
robert@464 201 float temp_in = out_l;
robert@464 202 /* compute result */
robert@464 203 out_l = a0_l * out_l + a1_l * x1_l + a2_l * x2_l - a3_l * y1_l - a4_l * y2_l;
robert@464 204 /* shift x1 to x2, sample to x1 */
robert@464 205 x2_l = x1_l;
robert@464 206 x1_l = temp_in;
robert@464 207 /* shift y1 to y2, result to y1 */
robert@464 208 y2_l = y1_l;
robert@464 209 y1_l = out_l;
robert@464 210
robert@464 211 // RIGHT CHANNEL
robert@464 212 temp_in = out_r;
robert@464 213 /* compute result */
robert@464 214 out_r = a0_r * out_r + a1_r * x1_r + a2_r * x2_r - a3_r * y1_r - a4_r * y2_r;
robert@464 215 /* shift x1 to x2, sample to x1 */
robert@464 216 x2_r = x1_r;
robert@464 217 x1_r = temp_in;
robert@464 218 /* shift y1 to y2, result to y1 */
robert@464 219 y2_r = y1_r;
robert@464 220 y1_r = out_r;
robert@464 221
chris@543 222 context->audioOut[n * context->audioOutChannels + 1] = out_l * out_gain;
chris@543 223 context->audioOut[n * context->audioOutChannels + 0] = out_r * out_gain;
robert@464 224
robert@464 225 }
robert@464 226
robert@464 227 }
robert@464 228
robert@464 229
robert@464 230 // cleanup_render() is called once at the end, after the audio has stopped.
robert@464 231 // Release any resources that were allocated in initialise_render().
robert@464 232
robert@464 233 void cleanup(BelaContext *context, void *userData)
robert@464 234 {
robert@464 235
robert@464 236 }