From 711f4be2ff5ae1c6b329e37075be1d50215f23e4 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Mon, 3 Jun 2019 12:47:56 +0200 Subject: [PATCH] Replaced spline interpolation with interpolation from https://github.com/tuxcell/interpolationArduino --- config.h | 3 +- effect_modulated_chorus.cpp | 122 ++++++++------------- interpolation.cpp | 209 ++++++++++++++++++++++++++++++++++++ interpolation.h | 79 ++++++++++++++ spline.cpp | 124 --------------------- spline.h | 45 -------- 6 files changed, 333 insertions(+), 249 deletions(-) create mode 100644 interpolation.cpp create mode 100644 interpolation.h delete mode 100644 spline.cpp delete mode 100644 spline.h diff --git a/config.h b/config.h index ac60c49..68651e2 100644 --- a/config.h +++ b/config.h @@ -61,7 +61,8 @@ #define SAMPLE_RATE 44100 #define REDUCE_LOUDNESS 0 #define USE_XFADE_DATA 1 -#define SPLINE_WINDOW_SIZE 7 // For chorus, only odd numbers! +#define INTERPOLATION_WINDOW_SIZE 7 // For chorus, only odd numbers! +#define INTERPOLATE CUBIC // LINEAR COSINE LAGRANGE QUADRATIC //************************************************************************************************* //* DEBUG OUTPUT SETTINGS diff --git a/effect_modulated_chorus.cpp b/effect_modulated_chorus.cpp index a11ae2b..67b752b 100644 --- a/effect_modulated_chorus.cpp +++ b/effect_modulated_chorus.cpp @@ -24,7 +24,7 @@ #include #include "limits.h" #include "effect_modulated_chorus.h" -#include "spline.h" +#include "interpolation.h" #include "config.h" /******************************************************************/ @@ -69,64 +69,31 @@ void AudioModulatedEffectChorus::update(void) short *bp; short *mp; float mod_idx; - /* int x1; - int x2; - int y1; - int y2;*/ if (l_delayline == NULL) return; - /* - block = receiveWritable(0); - if (block) - { - bp = block->data; - uint32_t tmp = delay_length / (num_chorus - 1) - 1; - for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) - { - l_circ_idx++; - if (l_circ_idx >= delay_length) - { - l_circ_idx = 0; - } - l_delayline[l_circ_idx] = *bp; - sum = 0; - c_idx = l_circ_idx; - for (int k = 0; k < num_chorus; k++) - { - sum += l_delayline[c_idx]; - if (num_chorus > 1)c_idx -= tmp; - if (c_idx < 0) - { - c_idx += delay_length; - } - } - bp++ = sum / num_chorus; - } - // transmit the block - transmit(block, 0); - release(block); - } - */ - block = receiveWritable(0); modulation = receiveReadOnly(1); if (block && modulation) { +#ifdef INTERPOLATE uint8_t j; - int16_t spline_idx; - Spline modulation_spline; - modulation_spline.setDegree(Catmull); + int16_t interpolation_idx; + interpolation modulation_interpolate; + modulation_interpolate.valuelenXY(INTERPOLATION_WINDOW_SIZE); +#endif bp = block->data; mp = modulation->data; for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) { - float x[SPLINE_WINDOW_SIZE]; - float y[SPLINE_WINDOW_SIZE]; +#ifdef INTERPOLATE + float x[INTERPOLATION_WINDOW_SIZE]; + float y[INTERPOLATION_WINDOW_SIZE]; +#endif // write data into circular buffer if (l_circ_idx >= delay_length) @@ -140,44 +107,41 @@ void AudioModulatedEffectChorus::update(void) else if (mod_idx < 0) mod_idx = delay_length + mod_idx; - // get value with spline interpolation - for (j = 0; j < SPLINE_WINDOW_SIZE; j++) +#ifdef INTERPOLATE + // get value with interpolation + for (j = 0; j < INTERPOLATION_WINDOW_SIZE; j++) { - spline_idx = mod_idx + (SPLINE_WINDOW_SIZE / -2) + j; - if (spline_idx > delay_length) - spline_idx = spline_idx - delay_length; - else if (spline_idx < 0) - spline_idx = delay_length + spline_idx; - - x[j] = spline_idx; - y[j] = l_delayline[spline_idx]; - - Serial.print(j, DEC); - Serial.print(": X="); - Serial.print(x[j], DEC); - Serial.print(" Y="); - Serial.println(y[j], DEC); + interpolation_idx = mod_idx + (INTERPOLATION_WINDOW_SIZE / -2) + j; + if (interpolation_idx > delay_length) + interpolation_idx = interpolation_idx - delay_length; + else if (interpolation_idx < 0) + interpolation_idx = delay_length + interpolation_idx; + + x[j] = interpolation_idx; + y[j] = l_delayline[interpolation_idx]; } - modulation_spline.setPoints(x, y, SPLINE_WINDOW_SIZE); - *bp = int(modulation_spline.value(mod_idx) + 0.5); - - Serial.print(" SPLINE="); - Serial.println(*bp, DEC); - delay(200); - /* - - // linear interpolation - x1 = int(mod_idx); - y1 = l_delayline[x1]; - if (x1 + 1 >= delay_length) - x2 = 0; - else - x2 = x1 + 1; - y2 = l_delayline[x2]; - - bp = (int((float(y2 - y1) / (x2 - x1) * (mod_idx - x1) + y1) + 0.5) >> 1); // mix original signal 1:1 with modulated signal - - */ + modulation_interpolate.valueX(x); + modulation_interpolate.valueY(y); + modulation_interpolate.valueI(mod_idx); + +#if INTERPOLATE == CUBIC + *bp = int(modulation_interpolate.CubicInterpolate() + 0.5); +#elif INTERPOLATE == LINEAR + *bp = int(modulation_interpolate.LinearInterpolate() + 0.5); +#elif INTERPOLATE == COSINE + *bp = int(modulation_interpolate.CosineInterpolate() + 0.5); +#elif INTERPOLATE == LAGRANGE + *bp = int(modulation_interpolate.LagrangeInterpolate() + 0.5); +#elif INTERPOLATE == QUDRATIC + *bp = int(modulation_interpolate.QuadraticInterpolate() + 0.5); +#else + // No interpolation - should sound really bad... + *bp = int(mod_idx + 0.5); +#endif +#else + // No interpolation - should sound really bad... + *bp = int(mod_idx + 0.5); +#endif bp++; mp++; diff --git a/interpolation.cpp b/interpolation.cpp new file mode 100644 index 0000000..65340bb --- /dev/null +++ b/interpolation.cpp @@ -0,0 +1,209 @@ +/* +* interpolation.h +* +* interpolation - An interpolation library for Arduino. +* Author: Jose Gama 2015 + +* +* This library is free software; you can redistribute it +* and/or modify it under the terms of the GNU Lesser +* General Public License as published by the Free Software +* Foundation; either version 3 of the License, or (at +* your option) any later version. +* +* This library is distributed in the hope that it will +* be useful, but WITHOUT ANY WARRANTY; without even the +* implied warranty of MERCHANTABILITY or FITNESS FOR A +* PARTICULAR PURPOSE. See the GNU Lesser General Public +* License for more details. +* +* You should have received a copy of the GNU Lesser +* General Public License along with this library; if not, +* write to the Free Software Foundation, Inc., +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +/* + * From: https://github.com/tuxcell/interpolationArduino + * replaced all doubles by float (wirtz@parasitstudio.de) + */ + +#include "interpolation.h" + +interpolation::interpolation(void) { + _valInterp = 0; + _lenXY = 0; +} +interpolation::interpolation( float x[], float y[], int lenXY){ + _x = x;_y = y;_lenXY = lenXY; + _valInterp = 0; +} +interpolation::interpolation( float x[], float y[], int lenXY, float valInterp){ + _x = x;_y = y;_lenXY = lenXY; + _valInterp = valInterp; +} + +void interpolation::valueI( float valInterp ) { + _valInterp = valInterp; +} +void interpolation::valuelenXY( int lenXY ) { + _lenXY = lenXY; +} +void interpolation::valueX( float x[]) { + _x = x; +} +void interpolation::valueY( float y[]) { + _y = y; +} +void interpolation::valueXM( float XM[]) { + _XM = XM; +} +void interpolation::valueZ( float Z[]) { + _Z = Z; +} +float interpolation::LinearInterpolate() {return(LinearInterp( _x, _y, _lenXY, _valInterp));} +float interpolation::CosineInterpolate() {return(CosineInterp( _x, _y, _lenXY, _valInterp));} +float interpolation::CubicInterpolate() {return(CubicInterp( _x, _y, _lenXY, _valInterp));} +float interpolation::LagrangeInterpolate() {return(LagrangeInterp( _x, _y, _lenXY, _valInterp));} +float interpolation::QuadraticInterpolate() {return(QuadraticInterp( _x, _y, _lenXY, _valInterp));} +float interpolation::AkimaInterpolate() {return(AkimaInterp( _x, _y, _XM, _Z, _lenXY, _valInterp));} + + +float interpolation::LinearInterp( float* x, float* y, int n, float p ) +{ + //http://paulbourke.net/miscellaneous/interpolation/ + int i; + float mu; + for( i = 0; i < n-1; i++ ) + { + if (( x[i] <= p && x[i+1] >= p )||( x[i] >= p && x[i+1] <= p )) + { + mu=(p - x[i])/(x[i] - x[i+1]); + if (mu<0) mu=-mu; + return(y[i]*(1-mu)+y[i+1]*mu); + } + } + return 0; // Not in Range +} + +float interpolation::CosineInterp (float* x, float* y, int n, float p ) +{ + int i; + float mu, mu2; + for( i = 0; i < n-1; i++ ) + { + if (( x[i] <= p && x[i+1] >= p )||( x[i] >= p && x[i+1] <= p )) + { + mu=(p - x[i])/(x[i] - x[i+1]); + if (mu<0) mu=-mu; + mu2 = (1.0-cos(3.1415926535897*mu))/2.0; + return(y[i]*(1.0-mu2)+y[i+1]*mu2); + } + } + return 0; // Not in Range +} + +float interpolation::CubicInterp(float* x, float* y, int n, float p ) +{ + int i; + float a0,a1,a2,a3,mu, mu2; + for( i = 0; i < n-1; i++ ) + { + if (( x[i] <= p && x[i+1] >= p )||( x[i] >= p && x[i+1] <= p )) + { + mu=(p - x[i])/(x[i] - x[i+1]); + if (mu<0) mu=-mu; + mu2 = mu*mu; + a0 = y[i+2] - y[i+1] - y[i-1] + y[i]; + a1 = y[i-1] - y[i] - a0; + a2 = y[i+1] - y[i-1]; + a3 = y[i]; + return(a0*mu*mu2+a1*mu2+a2*mu+a3); + } + } + return 0; // Not in Range +} + +float interpolation::LagrangeInterp( float* x, float* y, int n, float p ) +{ + //http://www.dailyfreecode.com/code/lagranges-interpolation-method-finding-2376.aspx + int i, j, k; + float t, r=0; + for(i=0;i= p )||( x[i] >= p && x[i+1] <= p )) + { + if (i<(n-3)) xi2=x[i+2]; else xi2=0; + k = y[i]*(p - x[i+1])*(p - xi2)/((x[i] - x[i+1])*(x[i] - xi2)); + k += y[i+1]*(p - x[i])*(p - xi2)/((x[i+1] - x[i])*(x[i+1] - xi2)); + k += y[i+2]*(p - x[i])*(p - x[i+1])/((xi2 - x[i])*(xi2 - x[i+1])); + return(k); + } + } + return 0; // Not in Range +} + +float interpolation::AkimaInterp( float* x, float* y, float* XM, float* Z, int n, float p ) { + //http://jean-pierre.moreau.pagesperso-orange.fr/Cplus/akima_cpp.txt + int i; + float a,b,r; + //special case p=0 + if (p==0.0) { + return(0); + } + //Check to see if interpolation point is correct + if (p=x[n-3]) { + return(-330); + } + x[0]=2.0*x[1]-x[2]; + //Calculate Akima coefficients, a and b + for (i=1; ix[i]) i++; + i--; + + //Begin interpolation + b=x[i+1]-x[i]; + a=p-x[i]; + r=y[i]+Z[i]*a+(3.0*XM[i+2]-2.0*Z[i]-Z[i+1])*a*a/b; + r=r+(Z[i]+Z[i+1]-2.0*XM[i+2])*a*a*a/(b*b); + return(r); +} diff --git a/interpolation.h b/interpolation.h new file mode 100644 index 0000000..d07e075 --- /dev/null +++ b/interpolation.h @@ -0,0 +1,79 @@ +/* +* interpolation.h +* +* interpolation - An interpolation library for Arduino. +* Author: Jose Gama 2015 + +* +* This library is free software; you can redistribute it +* and/or modify it under the terms of the GNU Lesser +* General Public License as published by the Free Software +* Foundation; either version 3 of the License, or (at +* your option) any later version. +* +* This library is distributed in the hope that it will +* be useful, but WITHOUT ANY WARRANTY; without even the +* implied warranty of MERCHANTABILITY or FITNESS FOR A +* PARTICULAR PURPOSE. See the GNU Lesser General Public +* License for more details. +* +* You should have received a copy of the GNU Lesser +* General Public License along with this library; if not, +* write to the Free Software Foundation, Inc., +* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +/* + * From: https://github.com/tuxcell/interpolationArduino + * replaced all doubles by float (wirtz@parasitstudio.de) + */ + +#ifndef interpolation_h +#define interpolation_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +class interpolation +{ + public: + // constructor + interpolation( void ); + interpolation( float x[], float y[], int lenXY); + interpolation( float x[], float y[], int lenXY, float valInterp); + + void valueI( float valInterp ); + void valuelenXY( int lenXY ); + void valueX( float x[]); + void valueY( float y[]); + void valueXM( float XM[]); + void valueZ( float Z[]); + float LinearInterpolate(); + float CosineInterpolate(); + float CubicInterpolate(); + float LagrangeInterpolate(); + float QuadraticInterpolate(); + float AkimaInterpolate(); + + private: + float* _x; + float* _y; + float* _XM; + float* _Z; + int _lenXY; + float _valInterp; + + float LinearInterp( float x[], float y[], int n, float p ); + float CosineInterp( float x[], float y[], int n, float p ); + float CubicInterp( float x[], float y[], int n, float p ); + float LagrangeInterp( float x[], float y[], int n, float p ); + float QuadraticInterp( float x[], float y[], int n, float p ); + float AkimaInterp( float x[], float y[], float XM[], float Z[], int n, float p ); + +}; + +#endif diff --git a/spline.cpp b/spline.cpp deleted file mode 100644 index 045f8c1..0000000 --- a/spline.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - From: https://raw.githubusercontent.com/kerinin/arduino-splines -*/ - -#include "Arduino.h" -#include "spline.h" -#include - -Spline::Spline(void) { - _prev_point = 0; -} - -Spline::Spline( float x[], float y[], int numPoints, int degree ) -{ - setPoints(x, y, numPoints); - setDegree(degree); - _prev_point = 0; -} - -Spline::Spline( float x[], float y[], float m[], int numPoints ) -{ - setPoints(x, y, m, numPoints); - setDegree(Hermite); - _prev_point = 0; -} - -void Spline::setPoints( float x[], float y[], int numPoints ) { - _x = x; - _y = y; - _length = numPoints; -} - -void Spline::setPoints( float x[], float y[], float m[], int numPoints ) { - _x = x; - _y = y; - _m = m; - _length = numPoints; -} - -void Spline::setDegree( int degree ) { - _degree = degree; -} - -float Spline::value( float x ) -{ - if ( _x[0] > x ) { - return _y[0]; - } - else if ( _x[_length - 1] < x ) { - return _y[_length - 1]; - } - else { - for (int i = 0; i < _length; i++ ) - { - int index = ( i + _prev_point ) % _length; - - if ( _x[index] == x ) { - _prev_point = index; - return _y[index]; - } else if ( (_x[index] < x) && (x < _x[index + 1]) ) { - _prev_point = index; - return calc( x, index ); - } - } - } - return (0.0); -} - -float Spline::calc( float x, int i ) -{ - switch ( _degree ) { - case 0: - return _y[i]; - case 1: - if ( _x[i] == _x[i + 1] ) { - // Avoids division by 0 - return _y[i]; - } else { - return _y[i] + (_y[i + 1] - _y[i]) * ( x - _x[i]) / ( _x[i + 1] - _x[i] ); - } - case Hermite: - return hermite( ((x - _x[i]) / (_x[i + 1] - _x[i])), _y[i], _y[i + 1], _m[i], _m[i + 1], _x[i], _x[i + 1] ); - case Catmull: - if ( i == 0 ) { - // x prior to spline start - first point used to determine tangent - return _y[1]; - } else if ( i == _length - 2 ) { - // x after spline end - last point used to determine tangent - return _y[_length - 2]; - } else { - float t = (x - _x[i]) / (_x[i + 1] - _x[i]); - float m0 = (i == 0 ? 0 : catmull_tangent(i) ); - float m1 = (i == _length - 1 ? 0 : catmull_tangent(i + 1) ); - return hermite( t, _y[i], _y[i + 1], m0, m1, _x[i], _x[i + 1]); - } - } - return(0.0); -} - -float Spline::hermite( float t, float p0, float p1, float m0, float m1, float x0, float x1 ) { - return (hermite_00(t) * p0) + (hermite_10(t) * (x1 - x0) * m0) + (hermite_01(t) * p1) + (hermite_11(t) * (x1 - x0) * m1); -} -float Spline::hermite_00( float t ) { - return (2 * pow(t, 3)) - (3 * pow(t, 2)) + 1; -} -float Spline::hermite_10( float t ) { - return pow(t, 3) - (2 * pow(t, 2)) + t; -} -float Spline::hermite_01( float t ) { - return (3 * pow(t, 2)) - (2 * pow(t, 3)); -} -float Spline::hermite_11( float t ) { - return pow(t, 3) - pow(t, 2); -} - -float Spline::catmull_tangent( int i ) -{ - if ( _x[i + 1] == _x[i - 1] ) { - // Avoids division by 0 - return 0; - } else { - return (_y[i + 1] - _y[i - 1]) / (_x[i + 1] - _x[i - 1]); - } -} diff --git a/spline.h b/spline.h deleted file mode 100644 index 2729f58..0000000 --- a/spline.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - From: https://github.com/kerinin/arduino-splines - - Library for 1-d splines - Copyright Ryan Michael - Licensed under the LGPLv3 -*/ - -#ifndef spline_h -#define spline_h - -#include "Arduino.h" - -#define Hermite 10 -#define Catmull 11 - -class Spline -{ - public: - Spline( void ); - Spline( float x[], float y[], int numPoints, int degree = 1 ); - Spline( float x[], float y[], float m[], int numPoints ); - float value( float x ); - void setPoints( float x[], float y[], int numPoints ); - void setPoints( float x[], float y[], float m[], int numPoints ); - void setDegree( int degree ); - - private: - float calc( float, int); - float* _x; - float* _y; - float* _m; - int _degree; - int _length; - int _prev_point; - - float hermite( float t, float p0, float p1, float m0, float m1, float x0, float x1 ); - float hermite_00( float t ); - float hermite_10( float t ); - float hermite_01( float t ); - float hermite_11( float t ); - float catmull_tangent( int i ); -}; - -#endif