Generating a Simple Sinewave

I’ve been racking my brain for a while trying to figure out how to do this, but… Essentially, I’d like to create a script that generates two sinewave tones that are panned both hard left and right. Ideally, I’d like to be able to change the frequency of each tone with a slider. Anyone have any ideas? I’m at a loss…

Research AudioClip.SetData(), which should allow you to “create” audio, or modify existing audio.

1 Like

Hi zeekee. Here is an example you can try out. The script generates 2 sinewaves and sends each of them to their respective channel. I must add that I didn’t test if it compiles rightaway, although it shouldn’t be too hard to fix the errors (if any). If you have any questions or problems let me know.

public class SinewaveExample : MonoBehaviour
{
	[Range(1,20000)]  //Creates a slider in the inspector
	public float frequency1;

	[Range(1,20000)]  //Creates a slider in the inspector
    public float frequency2;

    public float sampleRate = 44100;
	public float waveLengthInSeconds = 2.0f;

	AudioSource audioSource;
	int timeIndex = 0;

	void Start()
	{
		audioSource = gameObject.AddComponent<AudioSource>();
		audioSource.playOnAwake = false;
		audioSource.spatialBlend = 0; //force 2D sound
		audioSource.Stop();	//avoids audiosource from starting to play automatically
	}
	
	void Update()
	{
		if(Input.GetKeyDown(KeyCode.Space))
		{
			if(!audioSource.isPlaying)
			{
				timeIndex = 0;  //resets timer before playing sound
				audioSource.Play();
			}
			else
			{
				audioSource.Stop();
			}
		}
	}
	
	void OnAudioFilterRead(float[] data, int channels)
	{
		for(int i = 0; i < data.Length; i+= channels)
		{			
			data[i] = CreateSine(timeIndex, frequency1, sampleRate);
			
			if(channels == 2)
				data[i+1] = CreateSine(timeIndex, frequency2, sampleRate);
			
			timeIndex++;
			
			//if timeIndex gets too big, reset it to 0
			if(timeIndex >= (sampleRate * waveLengthInSeconds))
			{
				timeIndex = 0;
			}
		}
	}
	
	//Creates a sinewave
	public float CreateSine(int timeIndex, float frequency, float sampleRate)
	{
		return Mathf.Sin(2 * Mathf.PI * timeIndex * frequency / sampleRate);
	}
}
16 Likes

Willemsenzo, that works great! This may sound like a stupid question, but how would I get the sinewave to play on a loop? Also, I tried associating the frequencies of each tone with slider objects in the hierarchy view, but I can’t seem to get it to work.

Actually, disregard the loop question, I just figured it out!

I’m essentially looking to associate a Slider object in the Scene view to the frequency value in the script. I’ve tried adding the game object with the script attached to it in the hierarchy view to the “On value changed” submenu, but I can’t seem to find the function that changes the value of the frequencies.

On a side note, the script you made works really well, but it seems to be producing a monaural beat as opposed to a binaural beat. Would I use AudioSource.panStereo to remedy this? If so, how would I implement it? The reference page doesn’t include an example.

Also, thanks for bearing with me. I realize I have a lot to learn about Unity and am really appreciative of all the help :slight_smile:

Is anyone else experiencing a lot of background noise with this? a lot of popping, is there a way to get rid of this?

1 Like

thank !!

yeah, I’m getting a clicking, popping if I’m updating the frequency (to create different notes). Have you found a solution?

1 Like

It Works great, but the volume is too low.
There is a way to turn crate a wave in a higher volume?

Thank you

If you need higher volume, multiply the output of the GetSine function with some number. However you might want to check your audiosettings first because if it’s low volume now then something probably isn’t right on your end.

1 Like

@willemsenzo how would I go about playing custom waves? For instance, I have an animationCurve in my inspector that I’ve shaped like a square wave. What code should go inside the OnAudioFilterRead() method to play this curve like a sound wave?

I thought I understood what I was doing and tried to write my wave to the data[ ] array, but this doesn’t sound like I want it to.

void OnAudioFilterRead(float[] data, int channels)
{
        for (int i = 0; i < data.Length; i += channels) {
        float waveData = wave.Evaluate(i / 2048);
        data[i] = waveData;
        data[i + 1] = waveData;
    }
}

Any idea how to do this?

How do you want it to sound? If you set the time of the animation curve to 1, and you would divide by 44100 (or whatever your sampling rate may be) you end up with a 1 hertz sound which probably sounds like a low click or something. If you want more control on the frequency I suggest to use a function like this which would generate a square wave.

float waveData = Mathf.Sign(Mathf.Sin(2 * Mathf.PI * timeCount * frequency / samplingRate));

@jason416 @mitchellson97
Hi, have you found any solution for the clicking noise?

It’s probably caused by setting timeIndex to 0, but this example algorithm is also not suitable for changing frequency while the sound is playing. I’ve updated it to fix both things, but also made other changes for what I needed but it ought to be easy enough to add back the second channel if you want it.

public class SineTest : MonoBehaviour
{
    [Range(1,20000)]  //Creates a slider in the inspector
    public float frequency = 100;

    public float sampleRate = 44100;

    float phase = 0;

    // ...I cut the rest of the functions because they are mostly unchanged...
  
    void OnAudioFilterRead(float[] data, int channels)
    {
        for(int i = 0 ; i < data.Length ; i += channels)
        {  
            phase += 2 * Mathf.PI * frequency / sampleRate;

            data[i] = Mathf.Sin(phase);

            if (phase >= 2 * Mathf.PI)
            {
                phase -= 2 * Mathf.PI;
            }
        }
    }

}
4 Likes

Hello, is this supported by WebGL?

To the best of my knowledge, it is still not supported by WebGL till now.:frowning:
https://answers.unity.com/questions/987850/can-onaudiofilterread-be-used-with-webgl.html
https://docs.unity3d.com/Manual/webgl-audio.html

Hey guys,
I’m currently working on a synth component to my drum machine for Android. I have basic Sine, Square, and Triangle waves set. I need help putting in variables that will modify the sound using sliders. Can anyone help with this?
etu1yk

1 Like

Hi, the free version of Maestro is able to play samples of drum :wink: