Frequency Modulation Synthesis Algorithm

Based on what I read, I created an FM sound synthesis algorithm. I'm not sure if I did it right. When creating a software synthesizer, the generator generation function is used, and a modulator can be used to modulate the frequency of this generator. I don’t know if FM synthesis should work only for modulating sine waves?

The algorithm uses the wave function of the device and the modulator index and coefficient for the frequency modulator. For each note, it takes a frequency and stores the phase value for the carrier and modulator oscillators. The modulator always uses a sine wave.

This is the algorithm in pseudo code:

function ProduceSample(instrument, notes_playing) for each note in notes_playing if note.isPlaying() # Calculate signal if instrument.FMIndex != 0 # Apply FM FMFrequency = note.frequency*instrument.FMRatio; # FM frequency is factor of note frequency. note.FMPhase = note.FMPhase + FMFrequency / kGraphSampleRate # Phase of modulator. frequencyDeviation = sin(note.FMPhase * PI)*instrument.FMIndex*FMFrequency # Frequency deviation. Max deviation is a factor of the FM frequency. Modulation is done by a sine wave. note.phase = note.phase + (note.frequency + frequencyDeviation) / kGraphSampleRate # Adjust phase with deviation # Reset the phase value to prevent the float from overflowing if note.FMPhase >= 1 note.FMPhase = note.FMPhase - 1 end if else # No FM applied note.phase = note.phase + note.frequency / kGraphSampleRate # Adjust phase without deviation end if # Calculate the next sample signal = signal + instrument.waveFunction(note.phase,instrument.waveParameter)*note.amplitude # Reset the phase value to prevent the float from overflowing if note.phase >= 1 note.phase = note.phase - 1 end if end if end loop return signal end function 

So, if the frequency of notes is 100 Hz, FMRatio is set to 0.5, and FMIndex is 0.1, it should produce frequencies that go between 95 Hz and 105 Hz in a 50 Hz cycle. This is the right way to do it. My tests show that it does not always sound right, especially when modulating a saw and square waves. Is it possible to modulate saw and square waves like this, or is it only for sine waves?

This is the implementation in C and CoreAudio:

 static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ AudioSynthesiser * audioController = (AudioSynthesiser *)inRefCon; // Get a pointer to the dataBuffer of the AudioBufferList AudioSampleType * outA = (AudioSampleType *) ioData->mBuffers[0].mData; if(!audioController->playing){ for (UInt32 i = 0; i < inNumberFrames; ++i){ outA[i] = (SInt16)0; } return noErr; } Track * track = &audioController->tracks[inBusNumber]; SynthInstrument * instrument = (SynthInstrument *)track; float frequency_deviation; float FMFrequency; // Loop through the callback buffer, generating samples for (UInt32 i = 0; i < inNumberFrames; ++i){ float signal = 0; for (int x = 0; x < 10; x++) { Note * note = track->notes_playing[x]; if(note){ //Envelope code removed //Calculate signal if (instrument->FMIndex) { //Apply FM FMFrequency = note->frequency*instrument->FMRatio; //FM frequency is factor of note frequency. note->FMPhase += FMFrequency / kGraphSampleRate; //Phase of modulator. frequency_deviation = sinf(note->FMPhase * M_PI)*instrument->FMIndex*FMFrequency; //Frequency deviation. Max deviation is a factor of the FM frequency. Modulation is done by a sine wave. note->phase += (note->frequency + frequency_deviation) / kGraphSampleRate; //Adjust phase with deviation // Reset the phase value to prevent the float from overflowing if (note->FMPhase >= 1){ note->FMPhase--; } }else{ note->phase += note->frequency/ kGraphSampleRate; //Adjust phase without deviation } // Calculate the next sample signal += instrument->wave_function(note->phase,instrument->wave_parameter)*track->note_amplitude[x]; // Reset the phase value to prevent the float from overflowing if (note->phase >= 1){ note->phase--; } } //Else nothing added } if(signal > 1.0){ signal = 1; }else if(signal < -1.0){ signal = -1.0; } audioController->wave[audioController->wave_last] = signal; if (audioController->wave_last == 499) { audioController->wave_last = 0; }else{ audioController->wave_last++; } outA[i] = (SInt16)(signal * 32767.0f); } return noErr; } 

The answers are much appreciated.

+7
source share
3 answers

In the end, I decided to use phase modulation. I found that many synthesizers use phase modulation, even if they are labeled FM.

It was easy to implement:

 signal += wave_function(note_phase * note_frequency / sample_rate + fm_index * sin(note_phase * fm_frequency * pi / sample_rate))*note_amplitude 
+2
source

Redeye:

To answer your basic question, yes, this is absolutely normal for modulating signals other than sine waves. In fact, this is what is better than FM. Modulating sine waves give a very boring sound output, but when you introduce more complex waveforms with the same modulation, you get much more interesting results.

This is at best a simplification and possibly completely false. Modulating sine waves with sinusoidal waves are perfectly capable of creating a wide range of complex rather than β€œboring” sounds.

On the contrary, complex waveforms multiply the number of resulting sidebands and can achieve more predictable results. Most of the documentation for FM - actually virtually equivalent to PHASE modulation (PM) in many common cases, including Yamaha's "FM", applies only to sine waves.

FYI (in case you still don't know it), the most famous FM synthesizer is probably the Yamaha DX7, which was revolutionary at the time (and also one of the first MIDI synthesizers).

Another observation is that FM synthesis was the beginning of the digital age, so waveforms were digitally generated and therefore used more complex waveforms than sine / square / triangular waves to create interesting sounds. "

This is completely false, no doubt. DX7 and many early FM - in fact, PM - Yamaha synthesizers offered ONLY sine waves, and yet, as I mentioned above, they are still capable of a lot of not-so-boring sounds. There are no "more complex waveforms."

Only later did Yamaha add other waveforms, and their usefulness is somewhat dubious compared to the predictability of the sidebands created by sine waves, as I said above.

It may be what you need to do to get the best sound - instead of just generating a sine wave to modulate, use complex waveforms. "

Or just use sine waves with good settings and combinations of parameters (ratio, index, etc.)

The fact that FM / PM with sine waves does not give an immediate result for studio quality - or maybe just analog - for many users, does not indicate that it is unable to do this.

+6
source

Good question, I will try to offer some thoughts / ideas ...

To answer your basic question, yes, this is absolutely normal for modulating signals other than sine waves. In fact, this is what is better than FM. Modulating sine waves give a very boring sound output, but when you input more complex signals with the same modulation, you get much more interesting results. FYI (if you still don’t know), the most famous FM synthesizer is probably the Yamaha DX7 , which was revolutionary at the time (and also one of the first MIDI synthesizers).

Another observation is that FM synthesis was the beginning of the digital age, so waveforms were generated digitally and, therefore, more complex waveforms than sine / square / triangular waves were used to create interesting sounds. This may be what you need to do to get the best sound, and not just generate a sine wave to modulate, use complex waveforms.

Looking through your code, it looks like you are doing FM correctly. However, I think that the modulation frequency is usually fixed, and not part of the frequency of notes, as in the code. It might be worth a try and see if it looks like what you are looking for.

I hope this helps a bit.

+3
source

All Articles