parent
59e11fd79f
commit
8353f29b10
@ -1,63 +1,136 @@ |
|||||||
/*
|
/*
|
||||||
* AdioSynthWaveformSine_F32 |
* AudioSynthWaveformSine_F32 |
||||||
*
|
* |
||||||
* Created: Chip Audette (OpenAudio) Feb 2017 |
* Created: Chip Audette (OpenAudio) Feb 2017 |
||||||
* Modeled on: AudioSynthWaveformSine from Teensy Audio Library |
* Modeled on: AudioSynthWaveformSine from Teensy Audio Library |
||||||
*
|
* |
||||||
* Purpose: Create sine wave of given amplitude and frequency |
* Purpose: Create sine wave of given amplitude and frequency |
||||||
* |
* |
||||||
* License: MIT License. Use at your own risk.
|
* 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_ |
#ifndef synth_sine2_f32_h_ |
||||||
#define synth_sine_f32_h_ |
#define synth_sine2_f32_h_ |
||||||
|
|
||||||
#include "Arduino.h" |
#include "Arduino.h" |
||||||
#include "AudioStream_F32.h" |
#include "AudioStream_F32.h" |
||||||
#include "arm_math.h" |
#include "arm_math.h" |
||||||
|
|
||||||
|
|
||||||
class AudioSynthWaveformSine_F32 : public AudioStream_F32 |
class AudioSynthWaveformSine_F32 : public AudioStream_F32 |
||||||
{ |
{ |
||||||
//GUI: inputs:0, outputs:1 //this line used for automatic generation of GUI node
|
//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
|
//GUI: shortName:sine //this line used for automatic generation of GUI node
|
||||||
public: |
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) { |
||||||
setSampleRate_Hz(settings.sample_rate_Hz); |
initSine(); |
||||||
} |
} //uses default AUDIO_SAMPLE_RATE from AudioStream.h
|
||||||
void frequency(float freq) { |
|
||||||
if (freq < 0.0) freq = 0.0; |
AudioSynthWaveformSine_F32(const AudioSettings_F32 &settings) : |
||||||
else if (freq > sample_rate_Hz/2.f) freq = sample_rate_Hz/2.f; |
AudioStream_F32(0, NULL), magnitude(0.5f) { |
||||||
phase_increment = freq * (4294967296.0 / sample_rate_Hz); |
setSampleRate_Hz(settings.sample_rate_Hz); |
||||||
} |
initSine(); |
||||||
void phase(float angle) { |
} |
||||||
if (angle < 0.0f) angle = 0.0f; |
|
||||||
else if (angle > 360.0f) { |
void initSine(void) { |
||||||
angle = angle - 360.0f; |
for(int ii=0; ii<10; ii++) // Coeff for BiQuad BPF
|
||||||
if (angle >= 360.0f) return; |
coeff32[ii] = 0.0; |
||||||
} |
coeff32[0] = 1.0; // b0 = 1 for pass through
|
||||||
phase_accumulator = angle * (4294967296.0f / 360.0f); |
coeff32[5] = 1.0; |
||||||
} |
// {numStages, pState, pCoeffs};
|
||||||
void amplitude(float n) { |
arm_biquad_cascade_df1_init_f32( &bq_inst, 2, state32, coeff32 ); |
||||||
if (n < 0) n = 0; |
} |
||||||
else if (n > 1.0f) n = 1.0f; |
|
||||||
magnitude = n * 65536.0f; |
void frequency(float32_t _freq) { // Frequency in Hz
|
||||||
} |
freq = _freq; |
||||||
void setSampleRate_Hz(const float &fs_Hz) { |
if (freq < 0.0f) |
||||||
phase_increment *= sample_rate_Hz / fs_Hz; //change the phase increment for the new frequency
|
freq = 0.0f; |
||||||
sample_rate_Hz = fs_Hz; |
if (freq > sample_rate_Hz/2.0f) |
||||||
} |
freq = sample_rate_Hz/2.0f; |
||||||
void begin(void) { enabled = true; } |
phaseIncrement = 512.0f * freq / sample_rate_Hz; |
||||||
void end(void) { enabled = false; } |
|
||||||
virtual void update(void); |
// 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 ); |
||||||
|
} |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* 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; |
||||||
|
} |
||||||
|
|
||||||
|
// 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) { |
||||||
|
phaseIncrement *= 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: |
private: |
||||||
uint32_t phase_accumulator = 0; |
float32_t freq = 1000.0f; |
||||||
uint32_t phase_increment = 0; |
float32_t angle = 0.0f; // Phase angle
|
||||||
int32_t magnitude = 0; |
float32_t phaseS = 0.0f; |
||||||
float sample_rate_Hz = AUDIO_SAMPLE_RATE; |
float32_t phaseIncrement = 0.0f; |
||||||
volatile uint8_t enabled = 1; |
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 |
#endif |
||||||
|
Loading…
Reference in new issue