Ver código fonte

Add AudioSynthWaveformModulated

dds
PaulStoffregen 6 anos atrás
pai
commit
e2db4871c6
4 arquivos alterados com 287 adições e 1 exclusões
  1. +1
    -0
      gui/index.html
  2. +3
    -0
      keywords.txt
  3. +204
    -0
      synth_waveform.cpp
  4. +79
    -1
      synth_waveform.h

+ 1
- 0
gui/index.html Ver arquivo

@@ -375,6 +375,7 @@ span.mainfunction {color: #993300; font-weight: bolder}
{"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":"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":"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"}},

+ 3
- 0
keywords.txt Ver arquivo

@@ -60,6 +60,7 @@ AudioPlaySerialflashRaw KEYWORD2
AudioRecordQueue KEYWORD2
AudioSynthToneSweep KEYWORD2
AudioSynthWaveform KEYWORD2
AudioSynthWaveformModulated KEYWORD2
AudioSynthWaveformSine KEYWORD2
AudioSynthWaveformSineHires KEYWORD2
AudioSynthWaveformSineModulated KEYWORD2
@@ -173,6 +174,8 @@ decode KEYWORD2
secondMix KEYWORD2
pitchMod KEYWORD2
shape KEYWORD2
frequencyModulation KEYWORD2
phaseModulation KEYWORD2

AudioMemoryUsage KEYWORD2
AudioMemoryUsageMax KEYWORD2

+ 204
- 0
synth_waveform.cpp Ver arquivo

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



+ 79
- 1
synth_waveform.h Ver arquivo

@@ -64,7 +64,6 @@ public:
freq = AUDIO_SAMPLE_RATE_EXACT / 2;
}
phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
//tone_incr = (t_freq * (0x80000000LL/AUDIO_SAMPLE_RATE_EXACT)) + 0.5;
}
void phase(float angle) {
if (angle < 0.0) {
@@ -127,5 +126,84 @@ private:
};


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

Carregando…
Cancelar
Salvar