| @@ -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; | |||
| }; | |||