@@ -44,6 +44,7 @@ play KEYWORD2 | |||
updateCoefs KEYWORD2 | |||
frequency KEYWORD2 | |||
amplitude KEYWORD2 | |||
offset KEYWORD2 | |||
resonance KEYWORD2 | |||
octaveControl KEYWORD2 | |||
modify KEYWORD2 | |||
@@ -122,4 +123,9 @@ FILTER_PARAEQ LITERAL1 | |||
FILTER_LOSHELF LITERAL1 | |||
FILTER_HISHELF LITERAL1 | |||
WAVEFORM_SINE LITERAL1 | |||
WAVEFORM_SAWTOOTH LITERAL1 | |||
WAVEFORM_SQUARE LITERAL1 | |||
WAVEFORM_TRIANGLE LITERAL1 | |||
WAVEFORM_ARBITRARY LITERAL1 | |||
@@ -24,8 +24,7 @@ | |||
* THE SOFTWARE. | |||
*/ | |||
#include "Audio.h" | |||
#include "arm_math.h" | |||
#include "synth_sine.h" | |||
#include "utility/dspinst.h" | |||
// data_waveforms.c |
@@ -27,6 +27,9 @@ | |||
#ifndef synth_sine_h_ | |||
#define synth_sine_h_ | |||
#include "AudioStream.h" | |||
#include "arm_math.h" | |||
// TODO: investigate making a high resolution sine wave | |||
// using Taylor series expansion. | |||
// http://www.musicdsp.org/showone.php?id=13 |
@@ -36,33 +36,10 @@ | |||
// 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) | |||
{ | |||
audio_block_t *block; | |||
short *bp; | |||
short *bp, *end; | |||
int32_t val1, val2, val3; | |||
uint32_t index, scale; | |||
@@ -70,12 +47,12 @@ void AudioSynthWaveform::update(void) | |||
uint32_t mag; | |||
short tmp_amp; | |||
if(tone_freq == 0)return; | |||
if(tone_amp == 0) return; | |||
block = allocate(); | |||
if(block) { | |||
if (block) { | |||
bp = block->data; | |||
switch(tone_type) { | |||
case TONE_TYPE_SINE: | |||
case WAVEFORM_SINE: | |||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | |||
// Calculate interpolated sin | |||
index = tone_phase >> 23; | |||
@@ -93,8 +70,28 @@ void AudioSynthWaveform::update(void) | |||
if(tone_phase & 0x80000000)tone_phase &= 0x7fffffff; | |||
} | |||
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++) { | |||
if(tone_phase & 0x40000000)*bp++ = -tone_amp; | |||
else *bp++ = tone_amp; | |||
@@ -103,7 +100,7 @@ void AudioSynthWaveform::update(void) | |||
} | |||
break; | |||
case TONE_TYPE_SAWTOOTH: | |||
case WAVEFORM_SAWTOOTH: | |||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | |||
*bp++ = ((short)(tone_phase>>15)*tone_amp) >> 15; | |||
// phase and incr are both unsigned 32-bit fractions | |||
@@ -111,7 +108,7 @@ void AudioSynthWaveform::update(void) | |||
} | |||
break; | |||
case TONE_TYPE_TRIANGLE: | |||
case WAVEFORM_TRIANGLE: | |||
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) { | |||
if(tone_phase & 0x80000000) { | |||
// negative half-cycle | |||
@@ -132,7 +129,14 @@ void AudioSynthWaveform::update(void) | |||
} | |||
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); | |||
release(block); | |||
} |
@@ -39,6 +39,13 @@ extern const int16_t AudioWaveformSine[257]; | |||
#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_SAWTOOTH 1 | |||
#define TONE_TYPE_SQUARE 2 | |||
@@ -50,24 +57,20 @@ public AudioStream | |||
public: | |||
AudioSynthWaveform(void) : | |||
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 | |||
if (n < 0) n = 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 | |||
// and has now been increased. | |||
tone_phase = 0; | |||
@@ -75,19 +78,31 @@ public: | |||
// set new magnitude | |||
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); | |||
private: | |||
short tone_amp; | |||
short last_tone_amp; | |||
short tone_freq; | |||
uint32_t tone_phase; | |||
// volatile prevents the compiler optimizing out the frequency function | |||
volatile uint32_t tone_incr; | |||
short tone_type; | |||
int16_t tone_offset; | |||
const int16_t *arbdata; | |||
}; | |||