| {"type":"AudioSynthWaveformSineHires","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine_hires","inputs":0,"outputs":2,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | {"type":"AudioSynthWaveformSineHires","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine_hires","inputs":0,"outputs":2,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | ||||
| {"type":"AudioSynthWaveformSineModulated","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine_fm","inputs":1,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | {"type":"AudioSynthWaveformSineModulated","data":{"defaults":{"name":{"value":"new"}},"shortName":"sine_fm","inputs":1,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | ||||
| {"type":"AudioSynthWaveform","data":{"defaults":{"name":{"value":"new"}},"shortName":"waveform","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | {"type":"AudioSynthWaveform","data":{"defaults":{"name":{"value":"new"}},"shortName":"waveform","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | ||||
| {"type":"AudioSynthWaveformModulated","data":{"defaults":{"name":{"value":"new"}},"shortName":"waveform","inputs":2,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | |||||
| {"type":"AudioSynthWaveformPWM","data":{"defaults":{"name":{"value":"new"}},"shortName":"pwm","inputs":1,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | {"type":"AudioSynthWaveformPWM","data":{"defaults":{"name":{"value":"new"}},"shortName":"pwm","inputs":1,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | ||||
| {"type":"AudioSynthToneSweep","data":{"defaults":{"name":{"value":"new"}},"shortName":"tonesweep","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | {"type":"AudioSynthToneSweep","data":{"defaults":{"name":{"value":"new"}},"shortName":"tonesweep","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | ||||
| {"type":"AudioSynthWaveformDc","data":{"defaults":{"name":{"value":"new"}},"shortName":"dc","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, | {"type":"AudioSynthWaveformDc","data":{"defaults":{"name":{"value":"new"}},"shortName":"dc","inputs":0,"outputs":1,"category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png"}}, |
| AudioRecordQueue KEYWORD2 | AudioRecordQueue KEYWORD2 | ||||
| AudioSynthToneSweep KEYWORD2 | AudioSynthToneSweep KEYWORD2 | ||||
| AudioSynthWaveform KEYWORD2 | AudioSynthWaveform KEYWORD2 | ||||
| AudioSynthWaveformModulated KEYWORD2 | |||||
| AudioSynthWaveformSine KEYWORD2 | AudioSynthWaveformSine KEYWORD2 | ||||
| AudioSynthWaveformSineHires KEYWORD2 | AudioSynthWaveformSineHires KEYWORD2 | ||||
| AudioSynthWaveformSineModulated KEYWORD2 | AudioSynthWaveformSineModulated KEYWORD2 | ||||
| secondMix KEYWORD2 | secondMix KEYWORD2 | ||||
| pitchMod KEYWORD2 | pitchMod KEYWORD2 | ||||
| shape KEYWORD2 | shape KEYWORD2 | ||||
| frequencyModulation KEYWORD2 | |||||
| phaseModulation KEYWORD2 | |||||
| AudioMemoryUsage KEYWORD2 | AudioMemoryUsage KEYWORD2 | ||||
| AudioMemoryUsageMax KEYWORD2 | AudioMemoryUsageMax KEYWORD2 |
| release(block); | release(block); | ||||
| } | } | ||||
| //-------------------------------------------------------------------------------- | |||||
| void AudioSynthWaveformModulated::update(void) | |||||
| { | |||||
| audio_block_t *block, *moddata, *shapedata; | |||||
| int16_t *bp, *end; | |||||
| int32_t val1, val2; | |||||
| int16_t magnitude15; | |||||
| uint32_t i, ph, index, index2, scale, priorphase; | |||||
| const uint32_t inc = phase_increment; | |||||
| moddata = receiveReadOnly(0); | |||||
| shapedata = receiveReadOnly(1); | |||||
| ph = phase_accumulator; | |||||
| priorphase = phasedata[AUDIO_BLOCK_SAMPLES-1]; | |||||
| if (moddata && modulation_type == 0) { | |||||
| // Frequency Modulation | |||||
| bp = moddata->data; | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| int32_t n = (*bp++) * modulation_factor; // n is # of octaves to mod | |||||
| int32_t ipart = n >> 27; // 4 integer bits | |||||
| n &= 0x7FFFFFF; // 27 fractional bits | |||||
| #ifdef IMPROVE_EXPONENTIAL_ACCURACY | |||||
| // exp2 polynomial suggested by Stefan Stenzel on "music-dsp" | |||||
| // mail list, Wed, 3 Sep 2014 10:08:55 +0200 | |||||
| int32_t x = n << 3; | |||||
| n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713); | |||||
| int32_t sq = multiply_32x32_rshift32_rounded(x, x); | |||||
| n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615); | |||||
| n = n + (multiply_32x32_rshift32_rounded(sq, | |||||
| multiply_32x32_rshift32_rounded(x, 1358044250)) << 1); | |||||
| #else | |||||
| // exp2 algorithm by Laurent de Soras | |||||
| // http://www.musicdsp.org/showone.php?id=106 | |||||
| n = (n + 134217728) << 3; | |||||
| n = multiply_32x32_rshift32_rounded(n, n); | |||||
| n = multiply_32x32_rshift32_rounded(n, 715827883) << 3; | |||||
| n = n + 715827882; | |||||
| #endif | |||||
| uint32_t scale = n >> (14 - ipart); | |||||
| uint32_t phinc = ((uint64_t)inc * scale) >> 16; // TODO: saturate 31 bits?? | |||||
| ph += phinc; | |||||
| phasedata[i] = ph; | |||||
| } | |||||
| release(moddata); | |||||
| } else if (moddata) { | |||||
| // Phase Modulation | |||||
| // TODO..... | |||||
| release(moddata); | |||||
| } else { | |||||
| // No Modulation Input | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| phasedata[i] = ph; | |||||
| ph += inc; | |||||
| } | |||||
| } | |||||
| phase_accumulator = ph; | |||||
| if (magnitude == 0) { | |||||
| if (shapedata) release(shapedata); | |||||
| return; | |||||
| } | |||||
| block = allocate(); | |||||
| if (!block) { | |||||
| if (shapedata) release(shapedata); | |||||
| return; | |||||
| } | |||||
| bp = block->data; | |||||
| switch(tone_type) { | |||||
| case WAVEFORM_SINE: | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| ph = phasedata[i]; | |||||
| index = ph >> 24; | |||||
| val1 = AudioWaveformSine[index]; | |||||
| val2 = AudioWaveformSine[index+1]; | |||||
| scale = (ph >> 8) & 0xFFFF; | |||||
| val2 *= scale; | |||||
| val1 *= 0x10000 - scale; | |||||
| *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude); | |||||
| } | |||||
| break; | |||||
| case WAVEFORM_ARBITRARY: | |||||
| if (!arbdata) { | |||||
| release(block); | |||||
| if (shapedata) release(shapedata); | |||||
| return; | |||||
| } | |||||
| // len = 256 | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| ph = phasedata[i]; | |||||
| index = ph >> 24; | |||||
| index2 = index + 1; | |||||
| if (index2 >= 256) index2 = 0; | |||||
| val1 = *(arbdata + index); | |||||
| val2 = *(arbdata + index2); | |||||
| scale = (ph >> 8) & 0xFFFF; | |||||
| val2 *= scale; | |||||
| val1 *= 0x10000 - scale; | |||||
| *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude); | |||||
| } | |||||
| break; | |||||
| case WAVEFORM_PULSE: | |||||
| if (shapedata) { | |||||
| magnitude15 = signed_saturate_rshift(magnitude, 16, 1); | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16; | |||||
| if (phasedata[i] < width) { | |||||
| *bp++ = magnitude15; | |||||
| } else { | |||||
| *bp++ = -magnitude15; | |||||
| } | |||||
| } | |||||
| break; | |||||
| } // else fall through to orginary square without shape modulation | |||||
| case WAVEFORM_SQUARE: | |||||
| magnitude15 = signed_saturate_rshift(magnitude, 16, 1); | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| if (phasedata[i] & 0x80000000) { | |||||
| *bp++ = -magnitude15; | |||||
| } else { | |||||
| *bp++ = magnitude15; | |||||
| } | |||||
| } | |||||
| break; | |||||
| case WAVEFORM_SAWTOOTH: | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| *bp++ = signed_multiply_32x16t(magnitude, phasedata[i]); | |||||
| } | |||||
| break; | |||||
| case WAVEFORM_SAWTOOTH_REVERSE: | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| *bp++ = signed_multiply_32x16t(0xFFFFFFFFu - magnitude, phasedata[i]); | |||||
| } | |||||
| break; | |||||
| case WAVEFORM_TRIANGLE_VARIABLE: | |||||
| if (shapedata) { | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| uint32_t width = (shapedata->data[i] + 0x8000) & 0xFFFF; | |||||
| uint32_t rise = 0xFFFFFFFF / width; | |||||
| uint32_t fall = 0xFFFFFFFF / (0xFFFF - width); | |||||
| width = width << 15; | |||||
| uint32_t n; | |||||
| ph = phasedata[i]; | |||||
| if (ph < width) { | |||||
| n = (ph >> 16) * rise; | |||||
| *bp++ = ((n >> 16) * magnitude) >> 16; | |||||
| } else if (ph < 0xFFFFFFFF - width) { | |||||
| n = 0x7FFFFFFF - (((ph - width) >> 16) * fall); | |||||
| *bp++ = ((n >> 16) * magnitude) >> 16; | |||||
| } else { | |||||
| n = ((ph + width) >> 16) * rise + 0x80000000; | |||||
| *bp++ = ((n >> 16) * magnitude) >> 16; | |||||
| } | |||||
| ph += inc; | |||||
| } | |||||
| break; | |||||
| } // else fall through to orginary triangle without shape modulation | |||||
| case WAVEFORM_TRIANGLE: | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| ph = phasedata[i]; | |||||
| uint32_t phtop = ph >> 30; | |||||
| if (phtop == 1 || phtop == 2) { | |||||
| *bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16; | |||||
| } else { | |||||
| *bp++ = ((ph >> 15) * magnitude) >> 16; | |||||
| } | |||||
| } | |||||
| break; | |||||
| case WAVEFORM_SAMPLE_HOLD: | |||||
| for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
| ph = phasedata[i]; | |||||
| if (ph < priorphase) { | |||||
| sample = random(magnitude) - (magnitude >> 1); | |||||
| } | |||||
| priorphase = ph; | |||||
| *bp++ = sample; | |||||
| } | |||||
| break; | |||||
| } | |||||
| 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); | |||||
| } | |||||
| if (shapedata) release(shapedata); | |||||
| transmit(block, 0); | |||||
| release(block); | |||||
| } | |||||
| freq = AUDIO_SAMPLE_RATE_EXACT / 2; | freq = AUDIO_SAMPLE_RATE_EXACT / 2; | ||||
| } | } | ||||
| phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT); | phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT); | ||||
| //tone_incr = (t_freq * (0x80000000LL/AUDIO_SAMPLE_RATE_EXACT)) + 0.5; | |||||
| } | } | ||||
| void phase(float angle) { | void phase(float angle) { | ||||
| if (angle < 0.0) { | if (angle < 0.0) { | ||||
| }; | }; | ||||
| class AudioSynthWaveformModulated : public AudioStream | |||||
| { | |||||
| public: | |||||
| AudioSynthWaveformModulated(void) : AudioStream(2, inputQueueArray), | |||||
| phase_accumulator(0), phase_increment(0), modulation_factor(32768), | |||||
| magnitude(0), arbdata(NULL), priorphase(0), sample(0), tone_offset(0), | |||||
| tone_type(WAVEFORM_SINE), modulation_type(0) { | |||||
| } | |||||
| void frequency(float freq) { | |||||
| if (freq < 0.0) { | |||||
| freq = 0.0; | |||||
| } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) { | |||||
| freq = AUDIO_SAMPLE_RATE_EXACT / 2; | |||||
| } | |||||
| phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT); | |||||
| } | |||||
| void amplitude(float n) { // 0 to 1.0 | |||||
| if (n < 0) { | |||||
| n = 0; | |||||
| } else if (n > 1.0) { | |||||
| n = 1.0; | |||||
| } | |||||
| magnitude = n * 65536.0; | |||||
| } | |||||
| 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_type = t_type; | |||||
| } | |||||
| void begin(float t_amp, float t_freq, short t_type) { | |||||
| amplitude(t_amp); | |||||
| frequency(t_freq); | |||||
| tone_type = t_type; | |||||
| } | |||||
| void arbitraryWaveform(const int16_t *data, float maxFreq) { | |||||
| arbdata = data; | |||||
| } | |||||
| void frequencyModulation(float octaves) { | |||||
| if (octaves > 12.0) { | |||||
| octaves = 12.0; | |||||
| } else if (octaves < 0.1) { | |||||
| octaves = 0.1; | |||||
| } | |||||
| modulation_factor = octaves * 4096.0; | |||||
| modulation_type = 0; | |||||
| } | |||||
| void phaseModulation(float degrees) { | |||||
| if (degrees > 18000.0) { | |||||
| degrees = 18000.0; | |||||
| } else if (degrees < 30.0) { | |||||
| degrees = 30.0; | |||||
| } | |||||
| modulation_factor = degrees * (65536.0 / 360.0); | |||||
| modulation_type = 1; | |||||
| } | |||||
| virtual void update(void); | |||||
| private: | |||||
| audio_block_t *inputQueueArray[2]; | |||||
| uint32_t phase_accumulator; | |||||
| uint32_t phase_increment; | |||||
| uint32_t modulation_factor; | |||||
| int32_t magnitude; | |||||
| const int16_t *arbdata; | |||||
| uint32_t phasedata[AUDIO_BLOCK_SAMPLES]; | |||||
| uint32_t priorphase; | |||||
| int16_t sample; // for WAVEFORM_SAMPLE_HOLD | |||||
| int16_t tone_offset; | |||||
| uint8_t tone_type; | |||||
| uint8_t modulation_type; | |||||
| }; | |||||
| #endif | #endif |