annotate projects/airharp/Waveguide.cpp @ 269:ac8eb07afcf5

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