void AudioSynthWaveformModulated::update(void)
{
audio_block_t *block, *moddata, *shapedata, * posblock;
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);
posblock = receiveReadOnly(2); // zusätzlicher Modulationseingang
// Pre-compute the phase angle for every output sample of this update
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);
n = n << 1;
#else
// exp2 algorithm by Laurent de Soras
// https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html
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);
uint64_t phstep = (uint64_t)inc * scale;
uint32_t phstep_msw = phstep >> 32;
if (phstep_msw < 0x7FFE) {
ph += phstep >> 16;
} else {
ph += 0x7FFE0000;
}
phasedata[i] = ph;
}
release(moddata);
} else if (moddata) {
// Phase Modulation
bp = moddata->data;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
// more than +/- 180 deg shift by 32 bit overflow of "n"
uint32_t n = ((uint32_t)(*bp++)) * modulation_factor;
phasedata[i] = ph + n;
ph += inc;
}
release(moddata);
} else {
// No Modulation Input
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
phasedata[i] = ph;
ph += inc;
}
}
phase_accumulator = ph;
// If the amplitude is zero, no output, but phase still increments properly
if (magnitude == 0) {
if (shapedata) release(shapedata);
return;
}
block = allocate();
if (!block) {
if (shapedata) release(shapedata);
return;
}
bp = block->data;
// Now generate the output samples using the pre-computed phase angles
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_BANDLIMIT_PULSE:
if (shapedata)
{
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++)
{
uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16;
int32_t val = band_limit_waveform.generate_pulse (phasedata[i], width, i) ;
*bp++ = (int16_t) ((val * magnitude) >> 16) ;
}
break;
} // else fall through to orginary square without shape modulation
case WAVEFORM_BANDLIMIT_SQUARE:
for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
{
int32_t val = band_limit_waveform.generate_square (phasedata[i], i) ;
*bp++ = (int16_t) ((val * magnitude) >> 16) ;
}
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_BANDLIMIT_SAWTOOTH:
case WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE:
for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
{
int16_t val = band_limit_waveform.generate_sawtooth (phasedata[i], i) ;
val = (int16_t) ((val * magnitude) >> 16) ;
*bp++ = tone_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE ? (int16_t) -val : (int16_t) +val ;
}
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);
uint32_t halfwidth = width << 15;
uint32_t n;
ph = phasedata[i];
if (ph < halfwidth) {
n = (ph >> 16) * rise;
*bp++ = ((n >> 16) * magnitude) >> 16;
} else if (ph < 0xFFFFFFFF - halfwidth) {
n = 0x7FFFFFFF - (((ph - halfwidth) >> 16) * fall);
*bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
} else {
n = ((ph + halfwidth) >> 16) * rise + 0x80000000;
*bp++ = (((int32_t)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++ = (((int32_t)ph >> 15) * magnitude) >> 16;
}
}
break;
case WAVEFORM_SAMPLE_HOLD:
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
ph = phasedata[i];
if (ph < priorphase) { // does not work for phase modulation
sample = random(magnitude) - (magnitude >> 1);
}
priorphase = ph;
*bp++ = sample;
}
break;
// WaveformModulated with user wavetables ----------------
case WAVEFORM_USER_WAVETABLE:
{
// smooth parameter value
smooth_parameter_0();
smooth_parameter_1();
// --- NEU: Positions-Modulation einrechnen ---
int16_t position_modulation = 0;
if (posblock && posblock->data)
{
// Wir lesen das erste Sample des Blocks.
// Wichtig: posblock->data ist ein int16_t Array, kein einzelner Wert!
position_modulation = posblock->data[0];
}
// Achtung: Wenn Ihr posblock Werte von -32768 bis 32767 liefert,
// müssen wir den Wert eventuell skalieren, damit er den Parameter nicht sprengt
parameter_[0] = previous_smooth_parameter_[0] + par_a_mod_ + position_modulation;
parameter_[1] = previous_smooth_parameter_[1] + par_b_mod_;
position_modulation_out = position_modulation;
if (parameter_[0] <= 0)
{
parameter_[0] = 0;
}
// clip max value
parameter_[0] = saturate16(parameter_[0]);
parameter_[1] = saturate16(parameter_[1]);
smoothed_parameter_ = (3 * smoothed_parameter_ + (parameter_[0] << 1)) >> 2;
uint16_t scan = smoothed_parameter_;
uint8_t tabIndex = user_wt_index;
uint32_t tab_offset = ((129 * 64) * tabIndex);
const uint8_t *wave_0 = user_waves + tab_offset + userwave_line[previous_parameter_[0] >> 9] * 129;
const uint8_t *wave_1 = user_waves + tab_offset + userwave_line[scan >> 10] * 129;
const uint8_t *wave_2 = user_waves + tab_offset + userwave_line[(scan >> 10) + 1] * 129;
uint16_t smooth_xfade = scan << 6;
uint16_t rough_xfade = 0;
uint16_t rough_xfade_increment = 32768 / 128;
uint32_t balance = parameter_[1] << 3;
uint32_t phase = phase_;
uint32_t phase_increment1 = phase_increment >> 1;
int16_t rough, smooth;
if (parameter_[1] < 8192)
{
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
int32_t sample = 0;
rough = Crossfade(wave_0, wave_1, (phase >> 1) & 0xfe000000, rough_xfade);
smooth = Crossfade(wave_0, wave_1, phase >> 1, rough_xfade);
sample += Mix(rough, smooth, balance);
phase = phasedata[i];
rough_xfade += rough_xfade_increment;
rough = Crossfade(wave_0, wave_1, (phase >> 1) & 0xfe000000, rough_xfade);
smooth = Crossfade(wave_0, wave_1, phase >> 1, rough_xfade);
sample += Mix(rough, smooth, balance);
phase += phase_increment1;
rough_xfade += rough_xfade_increment;
*bp++ = ~sample >> 1;
}
}
else if (parameter_[1] < 16384)
{
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
int32_t sample = 0;
rough = Crossfade(wave_0, wave_1, phase >> 1, rough_xfade);
smooth = Crossfade(wave_1, wave_2, phase >> 1, smooth_xfade);
sample += Mix(rough, smooth, balance);
phase = phasedata[i];
rough_xfade += rough_xfade_increment;
rough = Crossfade(wave_0, wave_1, phase >> 1, rough_xfade);
smooth = Crossfade(wave_1, wave_2, phase >> 1, smooth_xfade);
sample += Mix(rough, smooth, balance);
phase += phase_increment1;
rough_xfade += rough_xfade_increment;
*bp++ = ~sample >> 1;
}
}
else if (parameter_[1] < 24576)
{
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
int32_t sample = 0;
smooth = Crossfade(wave_1, wave_2, phase >> 1, smooth_xfade);
rough = Crossfade(wave_1, wave_2, (phase >> 1) & 0xfe000000, smooth_xfade);
sample += Mix(smooth, rough, balance);
phase = phasedata[i];
smooth = Crossfade(wave_1, wave_2, phase >> 1, smooth_xfade);
rough = Crossfade(wave_1, wave_2, (phase >> 1) & 0xfe000000, smooth_xfade);
sample += Mix(smooth, rough, balance);
phase += phase_increment1;
*bp++ = ~sample >> 1;
}
}
else
{
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
int32_t sample = 0;
smooth = Crossfade(wave_1, wave_2, (phase >> 1) & 0xfe000000, smooth_xfade);
rough = Crossfade(wave_1, wave_2, (phase >> 1) & 0xf8000000, smooth_xfade);
sample += Mix(smooth, rough, balance);
phase = phasedata[i];
smooth = Crossfade(wave_1, wave_2, (phase >> 1) & 0xfe000000, smooth_xfade);
rough = Crossfade(wave_1, wave_2, (phase >> 1) & 0xf8000000, smooth_xfade);
sample += Mix(smooth, rough, balance);
phase += phase_increment1;
*bp++ = ~sample >> 1;
}
}
phase_ = phase;
previous_parameter_[0] = smoothed_parameter_ >> 1;
}
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);
if (posblock) release(posblock); // <-- WICHTIG: Speicherleck verhindern!
transmit(block, 0);
release(block);
}