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