diff --git a/UI.hpp b/UI.hpp index 7f98bed..89fd2d0 100644 --- a/UI.hpp +++ b/UI.hpp @@ -418,7 +418,7 @@ const char effects_text11[] PROGMEM = "Rev. Damping"; const char effects_text12[] PROGMEM = "Rev. Level"; const char effects_text13[] PROGMEM = "Chorus Freq."; const char effects_text14[] PROGMEM = "Chorus Delay"; -const char effects_text15[] PROGMEM = "Chorus Intensity"; +const char effects_text15[] PROGMEM = "Chorus Intens."; const char effects_text16[] PROGMEM = "Chorus Level"; const char effects_text17[] PROGMEM = "Bass LR Level"; const char effects_text18[] PROGMEM = "Bass M Level"; diff --git a/config.h b/config.h index a3c53da..ac60c49 100644 --- a/config.h +++ b/config.h @@ -61,6 +61,7 @@ #define SAMPLE_RATE 44100 #define REDUCE_LOUDNESS 0 #define USE_XFADE_DATA 1 +#define SPLINE_WINDOW_SIZE 7 // For chorus, only odd numbers! //************************************************************************************************* //* DEBUG OUTPUT SETTINGS diff --git a/effect_modulated_chorus.cpp b/effect_modulated_chorus.cpp index d7203e5..a11ae2b 100644 --- a/effect_modulated_chorus.cpp +++ b/effect_modulated_chorus.cpp @@ -24,6 +24,8 @@ #include #include "limits.h" #include "effect_modulated_chorus.h" +#include "spline.h" +#include "config.h" /******************************************************************/ @@ -67,10 +69,10 @@ void AudioModulatedEffectChorus::update(void) short *bp; short *mp; float mod_idx; - int x1; - int x2; - int y1; - int y2; + /* int x1; + int x2; + int y1; + int y2;*/ if (l_delayline == NULL) return; @@ -113,32 +115,70 @@ void AudioModulatedEffectChorus::update(void) if (block && modulation) { + uint8_t j; + int16_t spline_idx; + Spline modulation_spline; + modulation_spline.setDegree(Catmull); + 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]; + + // write data into circular buffer if (l_circ_idx >= delay_length) l_circ_idx = 0; l_delayline[l_circ_idx] = *bp; // write signal into circular buffer + // calculate modulation index mod_idx = float(*mp) / SHRT_MAX * delay_length_half + l_circ_idx; // calculate index with modulation as a float - if (mod_idx > delay_length) mod_idx = mod_idx - delay_length; else if (mod_idx < 0) mod_idx = delay_length + mod_idx; - // linear interpolation - x1 = int(mod_idx); - y1 = l_delayline[x1]; - if (x1 + 1 >= delay_length) + // get value with spline interpolation + for (j = 0; j < SPLINE_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); + } + 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 + 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 + 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 + + */ + bp++; mp++; l_circ_idx++; diff --git a/spline.cpp b/spline.cpp new file mode 100644 index 0000000..045f8c1 --- /dev/null +++ b/spline.cpp @@ -0,0 +1,124 @@ +/* + 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 new file mode 100644 index 0000000..2729f58 --- /dev/null +++ b/spline.h @@ -0,0 +1,45 @@ +/* + 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