{"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 |