annotate examples/10-Instruments/airharp/Waveguide.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
rev   line source
robert@464 1 /*
robert@464 2 *
robert@464 3 * Simple 1-Dimensional Waveguide
robert@464 4 *
robert@464 5 */
robert@464 6
robert@464 7 #include "Waveguide.h"
robert@464 8 #include "../include/Utilities.h"
robert@464 9 #include <rtdk.h>
robert@464 10 #include <cmath>
robert@464 11 #include <stdio.h>
robert@464 12 #include <cstdlib>
robert@464 13
robert@464 14 #define DECAY 0.995//0.999
robert@464 15 #define DAMPING 0.01//0.05
robert@464 16
robert@464 17 // TODO: make damping and decay parametrisable
robert@464 18
robert@464 19 Waveguide::Waveguide() {
robert@464 20
robert@464 21 // initialize variables
robert@464 22 a1_lp = 0;
robert@464 23 a2_lp = 0;
robert@464 24 b0_lp = 0;
robert@464 25 b1_lp = 0;
robert@464 26 b2_lp = 0;
robert@464 27 _dt = 1.0/44100.0;
robert@464 28 setFrequency(440);
robert@464 29 updateFilterCoeffs(8000);
robert@464 30 _filterReadPtr=0;
robert@464 31 for(int i=0;i<FILTER_BUFFER_SIZE;i++) {
robert@464 32 _filterBuffer_x[i] = 0;
robert@464 33 _filterBuffer_y[i] = 0;
robert@464 34 }
robert@464 35 for(int i=0;i<WG_BUFFER_SIZE;i++) {
robert@464 36 _buffer[i] = 0;
robert@464 37 }
robert@464 38 _lastX = 0;
robert@464 39 _lastY = 0;
robert@464 40 _readPtr = 0;
robert@464 41
robert@464 42 }
robert@464 43
robert@464 44 void Waveguide::setup() {
robert@464 45
robert@464 46 }
robert@464 47
robert@464 48 float Waveguide::update(float in) {
robert@464 49
robert@464 50 // 1. advance delay buffer read pointer
robert@464 51
robert@464 52 if(++_readPtr>=WG_BUFFER_SIZE)
robert@464 53 _readPtr=0;
robert@464 54
robert@464 55 // 2. write input into buffer
robert@464 56
robert@464 57 _buffer[_readPtr] = in;
robert@464 58
robert@464 59 // 3. read delayed sample from buffer
robert@464 60
robert@464 61 float out = _buffer[(_readPtr-_periodInSamples+WG_BUFFER_SIZE)%WG_BUFFER_SIZE];
robert@464 62
robert@464 63 // 4. apply damping (low-pass) filter to output
robert@464 64
robert@464 65 if(++_filterReadPtr>=FILTER_BUFFER_SIZE)
robert@464 66 _filterReadPtr=0;
robert@464 67
robert@464 68 out = b0_lp*out +
robert@464 69 b1_lp*_filterBuffer_x[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] +
robert@464 70 b2_lp*_filterBuffer_x[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] -
robert@464 71 a1_lp*_filterBuffer_y[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] -
robert@464 72 a2_lp*_filterBuffer_y[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE];
robert@464 73
robert@464 74 // 5. Simple high-pass filter to block DC-offset
robert@464 75 // y[n] = x[n] - x[n-1] + a * y[n-1]
robert@464 76 float gain = 0.9999;
robert@464 77 float temp = out;
robert@464 78 out = out - _lastX + gain * _lastY;
robert@464 79 _lastY = out;
robert@464 80 _lastX = temp;
robert@464 81
robert@464 82 // 6. Apply intensity damping
robert@464 83 out *= DECAY;
robert@464 84
robert@464 85 _filterBuffer_x[_filterReadPtr] = in;
robert@464 86 _filterBuffer_y[_filterReadPtr] = out;
robert@464 87
robert@464 88 return out;
robert@464 89
robert@464 90 }
robert@464 91
robert@464 92 void Waveguide::setFrequency(float frequency) {
robert@464 93
robert@464 94 // NB: currently no interpolation, so may not be ideal for dynamically changing waveguide frequency
robert@464 95 _periodInMilliseconds = 1000.0/frequency;
robert@464 96 _periodInSamples = (int)(_periodInMilliseconds * 44.1);
robert@464 97
robert@464 98 }
robert@464 99
robert@464 100 void Waveguide::updateFilterCoeffs(float frequency) {
robert@464 101
robert@464 102 // FIXME: Butterworth filter doesn't work very well,
robert@464 103 // using simple FIR in the meantime
robert@464 104
robert@464 105 a1_lp = 0;
robert@464 106 a2_lp = 0;
robert@464 107 b0_lp = 1.0 - DAMPING;
robert@464 108 b1_lp = DAMPING;
robert@464 109 b2_lp = 0;
robert@464 110
robert@464 111 /*
robert@464 112 // 'w' for sake of resembling lower-case 'omega'
robert@464 113 float w = 2.0 * M_PI * frequency;
robert@464 114 float t = _dt;
robert@464 115 // The Q for a 2nd-order Butterworth is sqrt(2)/2
robert@464 116 float q = 0.707;//sqrt(2.0)/2.0;
robert@464 117
robert@464 118 // low-pass filter coefficients
robert@464 119 float a0_lp = w*w*t*t + 2*(w/q)*t + 4.0;
robert@464 120 float k = 1.0/a0_lp;
robert@464 121 a1_lp = (2.0*w*w*t*t - 8.0) * k;
robert@464 122 a2_lp = (4.0 - (w/q)*2.0*t + w*w*t*t) * k;
robert@464 123 b0_lp = (w*w*t*t) * k;
robert@464 124 b1_lp = (2.0*w*w*t*t) * k;
robert@464 125 b2_lp = (w*w*t*t) * k;
robert@464 126 */
robert@464 127
robert@464 128 }