FM modulation of wavetable

Status
Not open for further replies.

RABB17

Well-known member
Hello all,

I am looking to begin creating a custom audio block for wavetable modulation. Any pointers on how to get it done? I have compiled 400+ single cycle waveforms into an Sf2 that will fit in the teensy 4.0 flash, and would like to be able to use those as carriers. I have also wondered if it would be more advisable to approximate the single cycle wave forms with power series or linear piecewise approximation thereof? Thus far I have avoided this as it seems it would be rather time consuming to do this for 500+ waveforms
 
Last edited:
Code:
/**
 * @brief Set various integer offsets to values that will produce intended frequencies
 * @details the main integer offset, tone_incr, is used to step through the current sample's 16-bit PCM audio sample.
 * Specifically, the tone_incr is the rate at which the interpolation code in update() steps through uint32_t space.
 * The remaining offset variables represent a minimum and maximum offset allowed for tone_incr, which allows for low-frequency
 * variation in playback frequency (aka vibrato). Further details on implementation in update() and in sample_data.h.
 *
 * @param freq frequency of the generated output (between 0 and the board-specific sample rate)
 */

^does this indicate that FM would be possible by adjusting the offsets?
 
Why not use the multiply block to modulate the wavetable waveform with some other waveform?

You know, considering I was just messing with the very same thing, I don't know why I didn't consider that. I think I put it out of my mind because when I compared the multiply fm output to the waveformmod output I was noticing variations with the waveforms generated. I wasn't sure which one was more "correct" barring further analysis which unfortunately I haven't had the time to do.

Today, when I was going through synthwaveform.cpp I noticed this:

Code:
// uncomment for more accurate but more computationally expensive frequency modulation
//#define IMPROVE_EXPONENTIAL_ACCURACY

I imagine I could simply cut and paste the multiply directly from the code into a custom multiply object.

Thanks for the suggestion!
 
Why not use the multiply block to modulate the wavetable waveform with some other waveform?

Wait, doesn't the multiply block perform AM? Not FM? I'm not 100% but I think you adjust the phase and the maths are different. I was planning to extrapolate the code from the audiowaveform modulated but it takes a bit to digest. If you can just use the multiply block that would save me the time but I am unsure how to do that, being under the impression it was for AM. I'm trying to find algorithms for FM specifically but it's not as easy as I was hoping. I have my old college DSP book around somewhere...
 
This is the one you want for FM.

https://www.pjrc.com/teensy/gui/?info=AudioSynthWaveformModulated

You can modulate frequency directly (the default way), or indirectly by phase modulation.

That's the one I have been using for FM, the early experiment I made used the multiply block with envelope and the waveform mod output to compare that results of that vs just running the waveformmod block into the envelope:
https://forum.pjrc.com/threads/58984-FM-synthesis-block-audio-design-tool?highlight=synthesis"].

Now I am trying to use a wavetable as a carrier for the modulation source. I had already hit upon the

Code:
	// 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 = (uint16_t)(*bp++) * modulation_factor;
			phasedata[i] = ph + n;
			ph += inc;
		}
		release(moddata);

as the bit I need I just don't fully understand the magic yet. Any suggestions as to routing the audio from a wavetable to be the carrier source?
 
Status
Not open for further replies.
Back
Top