updateCoefs KEYWORD2 | updateCoefs KEYWORD2 | ||||
frequency KEYWORD2 | frequency KEYWORD2 | ||||
amplitude KEYWORD2 | amplitude KEYWORD2 | ||||
offset KEYWORD2 | |||||
resonance KEYWORD2 | resonance KEYWORD2 | ||||
octaveControl KEYWORD2 | octaveControl KEYWORD2 | ||||
modify KEYWORD2 | modify KEYWORD2 | ||||
FILTER_LOSHELF LITERAL1 | FILTER_LOSHELF LITERAL1 | ||||
FILTER_HISHELF LITERAL1 | FILTER_HISHELF LITERAL1 | ||||
WAVEFORM_SINE LITERAL1 | |||||
WAVEFORM_SAWTOOTH LITERAL1 | |||||
WAVEFORM_SQUARE LITERAL1 | |||||
WAVEFORM_TRIANGLE LITERAL1 | |||||
WAVEFORM_ARBITRARY LITERAL1 | |||||
* THE SOFTWARE. | * THE SOFTWARE. | ||||
*/ | */ | ||||
#include "Audio.h" | |||||
#include "arm_math.h" | |||||
#include "synth_sine.h" | |||||
#include "utility/dspinst.h" | #include "utility/dspinst.h" | ||||
// data_waveforms.c | // data_waveforms.c |
#ifndef synth_sine_h_ | #ifndef synth_sine_h_ | ||||
#define synth_sine_h_ | #define synth_sine_h_ | ||||
#include "AudioStream.h" | |||||
#include "arm_math.h" | |||||
// TODO: investigate making a high resolution sine wave | // TODO: investigate making a high resolution sine wave | ||||
// using Taylor series expansion. | // using Taylor series expansion. | ||||
// http://www.musicdsp.org/showone.php?id=13 | // http://www.musicdsp.org/showone.php?id=13 |
// PAH 140314 - change t_hi from int to float | // PAH 140314 - change t_hi from int to float | ||||
boolean AudioSynthWaveform::begin(float t_amp,float t_hi,short type) | |||||
{ | |||||
tone_type = type; | |||||
amplitude(t_amp); | |||||
tone_freq = t_hi > 0.0; | |||||
if(t_hi <= 0.0)return false; | |||||
if(t_hi >= AUDIO_SAMPLE_RATE_EXACT/2)return false; | |||||
tone_phase = 0; | |||||
frequency(t_hi); | |||||
if(0) { | |||||
Serial.print("AudioSynthWaveform.begin(tone_amp = "); | |||||
Serial.print(t_amp); | |||||
Serial.print(", tone_hi = "); | |||||
Serial.print(t_hi); | |||||
Serial.print(", tone_incr = "); | |||||
Serial.print(tone_incr,HEX); | |||||
// Serial.print(", tone_hi = "); | |||||
// Serial.print(t_hi); | |||||
Serial.println(")"); | |||||
} | |||||
return(true); | |||||
} | |||||
void AudioSynthWaveform::update(void) | void AudioSynthWaveform::update(void) | ||||
{ | { | ||||
audio_block_t *block; | audio_block_t *block; | ||||
short *bp; | |||||
short *bp, *end; | |||||
int32_t val1, val2, val3; | int32_t val1, val2, val3; | ||||
uint32_t index, scale; | uint32_t index, scale; | ||||
uint32_t mag; | uint32_t mag; | ||||
short tmp_amp; | short tmp_amp; | ||||
if(tone_freq == 0)return; | |||||
if(tone_amp == 0) return; | |||||
block = allocate(); | block = allocate(); | ||||
if(block) { | |||||
if (block) { | |||||
bp = block->data; | bp = block->data; | ||||
switch(tone_type) { | switch(tone_type) { | ||||
case TONE_TYPE_SINE: | |||||
case WAVEFORM_SINE: | |||||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | ||||
// Calculate interpolated sin | // Calculate interpolated sin | ||||
index = tone_phase >> 23; | index = tone_phase >> 23; | ||||
if(tone_phase & 0x80000000)tone_phase &= 0x7fffffff; | if(tone_phase & 0x80000000)tone_phase &= 0x7fffffff; | ||||
} | } | ||||
break; | break; | ||||
case WAVEFORM_ARBITRARY: | |||||
if (!arbdata) { | |||||
release(block); | |||||
return; | |||||
} | |||||
// len = 256 | |||||
for (int i = 0; i < AUDIO_BLOCK_SAMPLES;i++) { | |||||
index = tone_phase >> 23; | |||||
val1 = *(arbdata + index); | |||||
val2 = *(arbdata + ((index + 1) & 255)); | |||||
scale = (tone_phase >> 7) & 0xFFFF; | |||||
val2 *= scale; | |||||
val1 *= 0xFFFF - scale; | |||||
val3 = (val1 + val2) >> 16; | |||||
*bp++ = (short)((val3 * tone_amp) >> 15); | |||||
tone_phase += tone_incr; | |||||
tone_phase &= 0x7fffffff; | |||||
} | |||||
break; | |||||
case TONE_TYPE_SQUARE: | |||||
case WAVEFORM_SQUARE: | |||||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | ||||
if(tone_phase & 0x40000000)*bp++ = -tone_amp; | if(tone_phase & 0x40000000)*bp++ = -tone_amp; | ||||
else *bp++ = tone_amp; | else *bp++ = tone_amp; | ||||
} | } | ||||
break; | break; | ||||
case TONE_TYPE_SAWTOOTH: | |||||
case WAVEFORM_SAWTOOTH: | |||||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | ||||
*bp++ = ((short)(tone_phase>>15)*tone_amp) >> 15; | *bp++ = ((short)(tone_phase>>15)*tone_amp) >> 15; | ||||
// phase and incr are both unsigned 32-bit fractions | // phase and incr are both unsigned 32-bit fractions | ||||
} | } | ||||
break; | break; | ||||
case TONE_TYPE_TRIANGLE: | |||||
case WAVEFORM_TRIANGLE: | |||||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | ||||
if(tone_phase & 0x80000000) { | if(tone_phase & 0x80000000) { | ||||
// negative half-cycle | // negative half-cycle | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
// send the samples to the left channel | |||||
if (tone_offset) { | |||||
bp = block->data; | |||||
end = bp + AUDIO_BLOCK_SAMPLES; | |||||
do { | |||||
val1 = *bp; | |||||
*bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0); | |||||
} while (bp < end); | |||||
} | |||||
transmit(block,0); | transmit(block,0); | ||||
release(block); | release(block); | ||||
} | } |
#define DELAY_PASSTHRU -1 | #define DELAY_PASSTHRU -1 | ||||
#define WAVEFORM_SINE 0 | |||||
#define WAVEFORM_SAWTOOTH 1 | |||||
#define WAVEFORM_SQUARE 2 | |||||
#define WAVEFORM_TRIANGLE 3 | |||||
#define WAVEFORM_ARBITRARY 4 | |||||
// todo: remove these... | |||||
#define TONE_TYPE_SINE 0 | #define TONE_TYPE_SINE 0 | ||||
#define TONE_TYPE_SAWTOOTH 1 | #define TONE_TYPE_SAWTOOTH 1 | ||||
#define TONE_TYPE_SQUARE 2 | #define TONE_TYPE_SQUARE 2 | ||||
public: | public: | ||||
AudioSynthWaveform(void) : | AudioSynthWaveform(void) : | ||||
AudioStream(0,NULL), | AudioStream(0,NULL), | ||||
tone_freq(0), tone_phase(0), tone_incr(0), tone_type(0) | |||||
tone_phase(0), tone_incr(0), tone_type(0), | |||||
tone_offset(0), arbdata(NULL) | |||||
{ | { | ||||
} | } | ||||
void frequency(float t_hi) | |||||
{ | |||||
if (t_hi > AUDIO_SAMPLE_RATE_EXACT / 2 || t_hi < 0.0) return; | |||||
tone_incr = ((0x80000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT) + 0.5; | |||||
void frequency(float t_freq) { | |||||
if (t_freq < 0.0) t_freq = 0.0; | |||||
else if (t_freq > AUDIO_SAMPLE_RATE_EXACT / 2) t_freq = AUDIO_SAMPLE_RATE_EXACT / 2; | |||||
tone_incr = (t_freq * (0x80000000LL/AUDIO_SAMPLE_RATE_EXACT)) + 0.5; | |||||
} | } | ||||
void amplitude(float n) { // 0 to 1.0 | void amplitude(float n) { // 0 to 1.0 | ||||
if (n < 0) n = 0; | if (n < 0) n = 0; | ||||
else if (n > 1.0) n = 1.0; | else if (n > 1.0) n = 1.0; | ||||
// Ramp code | |||||
if(tone_amp && (n == 0)) { | |||||
last_tone_amp = tone_amp; | |||||
} | |||||
else if((tone_amp == 0) && n) { | |||||
if ((tone_amp == 0) && n) { | |||||
// reset the phase when the amplitude was zero | // reset the phase when the amplitude was zero | ||||
// and has now been increased. | // and has now been increased. | ||||
tone_phase = 0; | tone_phase = 0; | ||||
// set new magnitude | // set new magnitude | ||||
tone_amp = n * 32767.0; | tone_amp = n * 32767.0; | ||||
} | } | ||||
boolean begin(float t_amp,float t_hi,short t_type); | |||||
void offset(float n) { | |||||
if (n < -1.0) n = -1.0; | |||||
else if (n > 1.0) n = 1.0; | |||||
tone_offset = n * 32767.0; | |||||
} | |||||
void begin(short t_type) { | |||||
tone_phase = 0; | |||||
tone_type = t_type; | |||||
} | |||||
void begin(float t_amp, float t_freq, short t_type) { | |||||
amplitude(t_amp); | |||||
frequency(t_freq); | |||||
begin(t_type); | |||||
} | |||||
virtual void update(void); | virtual void update(void); | ||||
private: | private: | ||||
short tone_amp; | short tone_amp; | ||||
short last_tone_amp; | |||||
short tone_freq; | short tone_freq; | ||||
uint32_t tone_phase; | uint32_t tone_phase; | ||||
// volatile prevents the compiler optimizing out the frequency function | // volatile prevents the compiler optimizing out the frequency function | ||||
volatile uint32_t tone_incr; | volatile uint32_t tone_incr; | ||||
short tone_type; | short tone_type; | ||||
int16_t tone_offset; | |||||
const int16_t *arbdata; | |||||
}; | }; | ||||