|
|
@@ -181,4 +181,208 @@ void AudioSynthWaveform::update(void) |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
|