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