@ -1,5 +1,5 @@
/*
* AdioSynthWaveformSine_F32
* Au dioSynthWaveformSine_F32
*
* Created : Chip Audette ( OpenAudio ) Feb 2017
* Modeled on : AudioSynthWaveformSine from Teensy Audio Library
@ -9,55 +9,128 @@
* License : MIT License . Use at your own risk .
*
*/
/* Revised 7 Feb 2022 to use a larger 512 point table and direct floating
* point . The level of harmonics depends on the exact frequency , but seems
* to be around - 110 dB below the sine wave output . This is more than
* adequate for most applications . For some testing , a pure sine wave ,
* limited only by the 24 bit mantissa , is useful . For this , the function
* pureSpectrum ( true ) will run two stages of biquad filtering putting the
* harmonics below - 135 dBc . This filter tracks the frequency ( ) entry , and
* is available above a few hundred Hz , depending on the sample rate . - - Bob
*
* Update time is about 9 microsends for 128 update ( ) with T4 . x . This goes
* up to 16 microseconds if " pureSpectrum " is used .
*/
# ifndef synth_sine_f32_h_
# define synth_sine_f32_h_
# ifndef synth_sine2 _f32_h_
# define synth_sine2 _f32_h_
# include "Arduino.h"
# include "AudioStream_F32.h"
# include "arm_math.h"
class AudioSynthWaveformSine_F32 : public AudioStream_F32
{
//GUI: inputs:0, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName:sine //this line used for automatic generation of GUI node
public :
AudioSynthWaveformSine_F32 ( ) : AudioStream_F32 ( 0 , NULL ) , magnitude ( 16384 ) { } //uses default AUDIO_SAMPLE_RATE from AudioStream.h
AudioSynthWaveformSine_F32 ( const AudioSettings_F32 & settings ) : AudioStream_F32 ( 0 , NULL ) , magnitude ( 16384 ) {
AudioSynthWaveformSine_F32 ( ) : AudioStream_F32 ( 0 , NULL ) , magnitude ( 0.5f ) {
initSine ( ) ;
} //uses default AUDIO_SAMPLE_RATE from AudioStream.h
AudioSynthWaveformSine_F32 ( const AudioSettings_F32 & settings ) :
AudioStream_F32 ( 0 , NULL ) , magnitude ( 0.5f ) {
setSampleRate_Hz ( settings . sample_rate_Hz ) ;
initSine ( ) ;
}
void initSine ( void ) {
for ( int ii = 0 ; ii < 10 ; ii + + ) // Coeff for BiQuad BPF
coeff32 [ ii ] = 0.0 ;
coeff32 [ 0 ] = 1.0 ; // b0 = 1 for pass through
coeff32 [ 5 ] = 1.0 ;
// {numStages, pState, pCoeffs};
arm_biquad_cascade_df1_init_f32 ( & bq_inst , 2 , state32 , coeff32 ) ;
}
void frequency ( float32_t _freq ) { // Frequency in Hz
freq = _freq ;
if ( freq < 0.0f )
freq = 0.0f ;
if ( freq > sample_rate_Hz / 2.0f )
freq = sample_rate_Hz / 2.0f ;
phaseIncrement = 512.0f * freq / sample_rate_Hz ;
// Find coeff for 2 stages of BPF to remove harmoncs
// Always compute these in case pureSpectrum is enabled later.
if ( freq > 0.003f * sample_rate_Hz )
{
float32_t q = 20.0f ;
float32_t w0 = freq * ( 2.0f * 3.141592654f / sample_rate_Hz ) ;
float32_t alpha = sin ( w0 ) / ( q * 2.0 ) ;
float32_t scale = 1.0f / ( 1.0f + alpha ) ;
/* b0 */ coeff32 [ 0 ] = alpha * scale ;
/* b1 */ coeff32 [ 1 ] = 0 ;
/* b2 */ coeff32 [ 2 ] = ( - alpha ) * scale ;
/* a1 */ coeff32 [ 3 ] = - ( - 2.0 * cos ( w0 ) ) * scale ;
/* a2 */ coeff32 [ 4 ] = - ( 1.0 - alpha ) * scale ;
/* b0 */ coeff32 [ 5 ] = coeff32 [ 0 ] ;
/* b1 */ coeff32 [ 6 ] = coeff32 [ 1 ] ;
/* b2 */ coeff32 [ 7 ] = coeff32 [ 2 ] ;
/* a1 */ coeff32 [ 8 ] = coeff32 [ 3 ] ;
/* a2 */ coeff32 [ 9 ] = coeff32 [ 4 ] ;
arm_biquad_cascade_df1_init_f32 ( & bq_inst , 2 , coeff32 , state32 ) ;
}
void frequency ( float freq ) {
if ( freq < 0.0 ) freq = 0.0 ;
else if ( freq > sample_rate_Hz / 2.f ) freq = sample_rate_Hz / 2.f ;
phase_increment = freq * ( 4294967296.0 / sample_rate_Hz ) ;
else
{
for ( int ii = 0 ; ii < 10 ; ii + + ) // Coeff for BiQuad BPF
coeff32 [ ii ] = 0.0 ;
coeff32 [ 0 ] = 1.0 ; // b0 = 1 for pass through
coeff32 [ 5 ] = 1.0 ;
arm_biquad_cascade_df1_init_f32 ( & bq_inst , 2 , coeff32 , state32 ) ;
enabled = false ;
}
void phase ( float angle ) {
if ( angle < 0.0f ) angle = 0.0f ;
else if ( angle > 360.0f ) {
angle = angle - 360.0f ;
if ( angle > = 360.0f ) return ;
}
phase_accumulator = angle * ( 4294967296.0f / 360.0f ) ;
/* Externally, phase comes in the range (.0, 360.0).
* Internally , the full circle is represented as ( 0.0 , 512.0 ) . This is
* convenient for finding the entry to the sine table .
* Corrected 1 - day at phase_r ( ) 24 Feb 22
*/
void phase ( float32_t _angle ) {
angle = 1.42222222f * _angle ; // Change (0,360) to (0, 512)
while ( angle < 0.0f ) angle + = 512.0f ;
while ( angle > 512.0f ) angle - = 512.0 ;
}
void amplitude ( float n ) {
if ( n < 0 ) n = 0 ;
else if ( n > 1.0f ) n = 1.0f ;
magnitude = n * 65536.0f ;
// The amplitude, a, is the peak, as in zero-to-peak. This produces outputs
// ranging from -a to +a.
void amplitude ( float32_t a ) {
if ( a < 0.0f ) a = 0.0f ;
magnitude = a ;
}
void setSampleRate_Hz ( const float & fs_Hz ) {
phase_increment * = sample_rate_Hz / fs_Hz ; //change the phase increment for the new frequency
phaseI ncrement * = sample_rate_Hz / fs_Hz ; //change the phase increment for the new frequency
sample_rate_Hz = fs_Hz ;
}
void begin ( void ) { enabled = true ; }
void end ( void ) { enabled = false ; }
void pureSpectrum ( bool _setPure ) { doPureSpectrum = _setPure ; }
virtual void update ( void ) ;
private :
uint32_t phase_accumulator = 0 ;
uint32_t phase_increment = 0 ;
int32_t magnitude = 0 ;
float sample_rate_Hz = AUDIO_SAMPLE_RATE ;
volatile uint8_t enabled = 1 ;
float32_t freq = 1000.0f ;
float32_t angle = 0.0f ; // Phase angle
float32_t phaseS = 0.0f ;
float32_t phaseIncrement = 0.0f ;
float32_t magnitude = 0.0f ;
float32_t sample_rate_Hz = AUDIO_SAMPLE_RATE ;
bool doPureSpectrum = false ; // Adds bandpass filter (not normally needed)
bool enabled = true ;
float32_t coeff32 [ 10 ] ; // 2 biquad stages for filtering output
float32_t state32 [ 8 ] ;
arm_biquad_casd_df1_inst_f32 bq_inst ; // ARM DSP Math library filter instance.
} ;
# endif