How to Build an FM synth in Unity

FM synthesis is a powerful technique, popularized in the 1970’s, that allows for complex sounds to be created by modulating the frequency of simple sine waves. If you want to dive deep into FM, you can check out this awesome article from sound on sound. In this tutorial ill show you how to build a basic FM synth inside of Unity using C#.

Start by creating an empty Game Object with an Audio Source and a new C# script attached.

 

In the script, first create two float variables to hold the frequency values and two to hold the amplitudes. It can be helpful to constrain the values using the range attribute.

[Range(50, 1000)]
public float frequency1;
[Range(0, 1)]
public float amplitude1;

[Range(0, 30)]
public float frequency2;
[Range(0, .1f)]
public float amplitude2;

Next, create a function to create sine waves:

public float CreateSine(int timeIndex, float frequency, float sampleRate, float amplitude)
    {
        return Mathf.Sin(2 * Mathf.PI * timeIndex * frequency / sampleRate) * amplitude;
    }

Now we can implement the OnAudioFilterRead() function, which will allow us to send our own audio into Unity’s audio stream. We will also add a for loop an a bit of code that will take the modulated sin wave that we create and clone it to the second channel.

void OnAudioFilterRead(float[] data, int channels)
    {
        for (int i = 0; i < data.Length; i += channels)
        {
            //calculate sin wave

            if (channels == 2)
                data[i + 1] = data[i];
        }
    }

To calculate the modulated sin wave we will use two instances of the CreateSine(). At this point we will also add a global variable called timeIndex which will tell us where in the waveform we are.

int timeIndex;

void OnAudioFilterRead(float[] data, int channels)
    {
        for (int i = 0; i < data.Length; i += channels)
        {
            float FMfreq = frequency1 * CreateSine(timeIndex, frequency2, 44100, amplitude2);
            data[i] = CreateSine(timeIndex, FMfreq, 44100, amplitude1);

            if (channels == 2)
                data[i + 1] = data[i];
        }
    }

It should work at this point! Just play around with the frequency and amplitude values and listen to the crazy sounds! To improve the functionality, we could add amplitude and frequency envelopes and some sort of trigger. Let us know if you want to see how to do that in a future tutorial!

Heres the full code:

using UnityEngine;

public class FMsynth : MonoBehaviour
{
    [Range(50, 1000)]
    public float frequency1;
    [Range(0, 1)]
    public float amplitude1;

    [Range(0, 30)]
    public float frequency2;
    [Range(0, .1f)]
    public float amplitude2;

    int timeIndex = 0;

    void OnAudioFilterRead(float[] data, int channels)
    {
        for (int i = 0; i < data.Length; i += channels)
        {
            float FMfreq = frequency1 * CreateSine(timeIndex, frequency2, 44100, amplitude2);
            data[i] = CreateSine(timeIndex, FMfreq, 44100, amplitude1);

            if (channels == 2)
                data[i + 1] = data[i];

            timeIndex++;
        }
    }

        //Creates a sinewave
        public float CreateSine(int timeIndex, float frequency, float sampleRate, float amplitude)
    {
        return Mathf.Sin(2 * Mathf.PI * timeIndex * frequency / sampleRate) * amplitude;
    }

}

Thanks for reading. Click the menu tab for more Unity tutorials, sound packs, and software.

Check out our assets on the Unity Asset Store.

hello