@ -58,6 +58,12 @@ boolean AudioEffectModulatedDelay::begin(short *delayline, int d_length)
_delayline = delayline ;
_delayline = delayline ;
_delay_length = _max_delay_length = d_length ;
_delay_length = _max_delay_length = d_length ;
// init filter
filter . numStages = 1 ;
filter . pState = filter_state ;
filter . pCoeffs = filter_coeffs ;
calcModFilterCoeff ( 5000.0 , 0.0 , 5.0 ) ;
return ( true ) ;
return ( true ) ;
}
}
@ -66,16 +72,20 @@ void AudioEffectModulatedDelay::update(void)
audio_block_t * block ;
audio_block_t * block ;
audio_block_t * modulation ;
audio_block_t * modulation ;
int16_t * bp ;
int16_t * mp ;
float mod_idx ;
if ( _delayline = = NULL )
if ( _delayline = = NULL )
return ;
return ;
block = receiveWritable ( 0 ) ;
block = receiveWritable ( 0 ) ;
modulation = receiveReadOnly ( 1 ) ;
modulation = receiveReadOnly ( 1 ) ;
if ( block & & modulation )
{
int16_t * bp ;
float * mp ;
float mod_idx ;
float mod_number ;
float mod_fraction ;
# ifdef INTERPOLATE_MODE
# ifdef INTERPOLATE_MODE
int8_t j ;
int8_t j ;
float x [ INTERPOLATION_WINDOW_SIZE ] ;
float x [ INTERPOLATION_WINDOW_SIZE ] ;
@ -83,13 +93,11 @@ void AudioEffectModulatedDelay::update(void)
Spline s ( x , y , INTERPOLATION_WINDOW_SIZE , INTERPOLATE_MODE ) ;
Spline s ( x , y , INTERPOLATION_WINDOW_SIZE , INTERPOLATE_MODE ) ;
# endif
# endif
// (Filter implementation: https://web.fhnw.ch/technik/projekte/eit/Fruehling2016/MuelZum/html/parametric__equalizer__example_8c_source.html)
arm_q15_to_float ( modulation - > data , modulation_f32 , AUDIO_BLOCK_SAMPLES ) ;
arm_biquad_cascade_df1_f32 ( & filter , modulation_f32 , modulation_f32 , AUDIO_BLOCK_SAMPLES ) ;
bp = block - > data ;
bp = block - > data ;
mp = modulation - > data ;
mp = modulation_f32 ;
if ( block & & modulation )
{
float mod_number ;
float mod_fraction ;
for ( uint16_t i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i + + )
for ( uint16_t i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i + + )
{
{
@ -100,56 +108,7 @@ void AudioEffectModulatedDelay::update(void)
// Calculate modulation index as a float, for interpolation later.
// Calculate modulation index as a float, for interpolation later.
// The index is located around the half of the delay length multiplied by the current amount of the modulator
// The index is located around the half of the delay length multiplied by the current amount of the modulator
/**************************************************************************************************************
mod_idx = * mp * float ( _delay_length > > 1 ) ;
Use an IIR filter on the modulation for avoiding aliasing ( http : //www-users.cs.york.ac.uk/~fisher/mkfilter/) */
# if defined(FILTER_IIR_ORDER_1)
/* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
Command line : / www / usr / fisher / helpers / mkfilter - Bu - Lp - o 1 - a 1.1333499558e-01 0.0000000000e+00 - l
Parameters : filtertype = Butterworth
passtype = Lowpass
ripple =
order = 1
samplerate = 44117.64706
corner1 = 5000
corner2 =
adzero =
logmin =
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define NZEROS 1
# define NPOLES 1
# define GAIN 3.688918967e+00
static float xv [ NZEROS + 1 ] , yv [ NPOLES + 1 ] ;
xv [ 0 ] = xv [ 1 ] ;
xv [ 1 ] = ( float ( * mp ) / SHRT_MAX ) / GAIN ;
yv [ 0 ] = yv [ 1 ] ;
yv [ 1 ] = ( xv [ 0 ] + xv [ 1 ] ) + ( 0.4578357460 * yv [ 0 ] ) ;
//new_value = yv[1];
mod_idx = yv [ 1 ] * float ( _delay_length > > 1 ) ;
# elif defined(FILTER_IIR_ORDER_3)
/* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
Command line : / www / usr / fisher / helpers / mkfilter - Bu - Lp - o 3 - a 1.1333333333e-01 0.0000000000e+00 - l
raw alpha1 = 0.1133333333
raw alpha2 = 0.1133333333
warped alpha1 = 0.1183783855
warped alpha2 = 0.1183783855
gain at dc : mag = 4.028005941e+01 phase = 0.0000000000 pi
gain at centre : mag = 2.848230315e+01 phase = - 0.7500000000 pi
gain at hf : mag = 0.000000000e+00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define NZEROS 3
# define NPOLES 3
# define GAIN 4.028005941e+01
static float xv [ NZEROS + 1 ] , yv [ NPOLES + 1 ] ;
xv [ 0 ] = xv [ 1 ] ; xv [ 1 ] = xv [ 2 ] ; xv [ 2 ] = xv [ 3 ] ;
xv [ 3 ] = ( float ( * mp ) / SHRT_MAX ) / GAIN ;
yv [ 0 ] = yv [ 1 ] ; yv [ 1 ] = yv [ 2 ] ; yv [ 2 ] = yv [ 3 ] ;
yv [ 3 ] = ( xv [ 0 ] + xv [ 3 ] ) + 3 * ( xv [ 1 ] + xv [ 2 ] )
+ ( 0.2323461955 * yv [ 0 ] ) + ( - 1.0299524229 * yv [ 1 ] )
+ ( 1.5989967885 * yv [ 2 ] ) ;
//new_value = yv[3];
mod_idx = yv [ 3 ] * float ( _delay_length > > 1 ) ;
/************************************************************************/
# endif
mod_fraction = modff ( mod_idx , & mod_number ) ;
mod_fraction = modff ( mod_idx , & mod_number ) ;
# ifdef INTERPOLATE_MODE
# ifdef INTERPOLATE_MODE
@ -173,13 +132,13 @@ void AudioEffectModulatedDelay::update(void)
if ( c_mod_idx < 0 )
if ( c_mod_idx < 0 )
{
{
value1 = _delayline [ _delay_length + c_mod_idx ] ;
value1 = _delayline [ _delay_length + c_mod_idx - 1 ] ;
value2 = _delayline [ _delay_length + c_mod_idx - 1 ] ;
value2 = _delayline [ _delay_length + c_mod_idx ] ;
}
}
else
else
{
{
value1 = _delayline [ c_mod_idx ] ;
value1 = _delayline [ c_mod_idx - 1 ] ;
value2 = _delayline [ c_mod_idx - 1 ] ;
value2 = _delayline [ c_mod_idx ] ;
}
}
* bp = mod_fraction * value1 + ( 1.0 - mod_fraction ) * value2 ;
* bp = mod_fraction * value1 + ( 1.0 - mod_fraction ) * value2 ;
# endif
# endif
@ -190,17 +149,47 @@ void AudioEffectModulatedDelay::update(void)
}
}
}
}
if ( modulation )
release ( modulation ) ;
if ( block )
if ( block )
{
{
transmit ( block , 0 ) ;
transmit ( block , 0 ) ;
release ( block ) ;
release ( block ) ;
}
}
if ( modulation )
release ( modulation ) ;
}
}
void AudioEffectModulatedDelay : : setDelay ( float milliseconds )
void AudioEffectModulatedDelay : : setDelay ( float milliseconds )
{
{
_delay_length = min ( AUDIO_SAMPLE_RATE * milliseconds / 500 , _max_delay_length ) ;
_delay_length = min ( AUDIO_SAMPLE_RATE * milliseconds / 500 , _max_delay_length ) ;
}
}
void AudioEffectModulatedDelay : : calcModFilterCoeff ( float32_t cFrq , float32_t gain , float32_t width )
{
/* Calculate intermediate values */
float32_t A = sqrt ( pow ( 10 , gain / 20.0f ) ) ;
float32_t w0 = 2.0f * PI * cFrq / ( ( float32_t ) AUDIO_SAMPLE_RATE_EXACT ) ;
float32_t cosw0 = cos ( w0 ) ;
float32_t sinw0 = sin ( w0 ) ;
float32_t alpha = sinw0 / ( 2.0f * width ) ;
/* Calculate coefficients */
float32_t b0 = 1.0f + alpha * A ;
float32_t b1 = - 2.0f * cosw0 ;
float32_t b2 = 1.0f - alpha * A ;
float32_t a0 = 1.0f + alpha / A ;
float32_t a1 = - 2.0f * cosw0 ;
float32_t a2 = 1.0f - alpha / A ;
/* Normalize so a0 = 1 */
filter_coeffs [ 0 ] = b0 / a0 ;
filter_coeffs [ 1 ] = b1 / a0 ;
filter_coeffs [ 2 ] = b2 / a0 ;
filter_coeffs [ 3 ] = - a1 / a0 ;
filter_coeffs [ 4 ] = - a2 / a0 ;
}
void AudioEffectModulatedDelay : : setModFilter ( float cFrq , float gain , float width )
{
calcModFilterCoeff ( cFrq , gain , width ) ;
}