Making a simple audio synthesizer in C#

I have been into producing dance music for a while now and have always wondered how difficult it would be to make my own simple synthesizer. Turns out it not that difficult at all. I have created a very simple synthesizer in just one afternoon.

How does a software synth work?

Very similar to a hardware synth, it works by creating and mixing waveforms before effecting them to get a desired sound.

How do I create a waveform?

Well you need to write some code that will produce a wave. The most common wave to produce is a sine wave. This sounds like a constant tone with no harmonics.

This is what a sine wave looks like

Sine wave

Ok, so how do I make a sine wave in C#?

Its actually pretty easy to make a sine wave in C#. It a matter of using the mathematical function Math.Sin() then sending in the angle (in radians). Here is an example of my Sine occilator in my program:

public class SineOccilator : SignWaveTest.IOccilator {

	private double _radiansPerCircle = Math.PI * 2;
	private double _currentFrequency = 2000;
	private double _sampleRate = 44100;

	public SineOccilator(double sampleRate) {
		_sampleRate = sampleRate;
	}

	public void SetFrequency(double value){
		_currentFrequency = value;
	}

	public double GetNext(int sampleNumberInSecond) {
		double samplesPerOccilation = (_sampleRate / _currentFrequency);
		double depthIntoOccilations = (sampleNumberInSecond % samplesPerOccilation) / samplesPerOccilation;
		return Math.Sin( depthIntoOccilations * _radiansPerCircle);
	}
}

All of the hard work is done in the GetNext method. The calling code tells the GetNext what sample (of the current second) that it wants and GetNext will return a number between 1 and -1.

This works by working out the ‘samplesPerOccilation’ value, which is the basically “how many samples does one oscillation take at the defined frequency”

After working that out we can work out how far we would be through an oscillation by taking the remainder of the sampleNumberInSecond / samplesPerOccilation. Then making that a number between 0 – 1 by dividing that answer by samplesPerOccilation.

Now we just need to work out that the numeric value for the waveform at that point, this is as simple as using calling Math.Sin and passing in the (depthIntoOccilations * _radiansPerCircle).

So here is how you would call it:

List<double> data = new List<double>();

SquareOccilator o = new SquareOccilator(sampleRate);
SineOccilator j = new SineOccilator(sampleRate);
SawToothOccilator s = new SawToothOccilator(sampleRate);
RoyalSawToothOccilator rs = new RoyalSawToothOccilator(sampleRate);
SawToothOccilatorSteadyDetunable detunableOccilator = new SawToothOccilatorSteadyDetunable(sampleRate);
detunableOccilator.SetDetune(0.05);

s.SetFrequency(GetNoteFrequnecy.C);
for (int i = 0; i < sampleRate * 2; i++) {
	data.Add(s.GetNext(i));
}
rs.SetFrequency(GetNoteFrequnecy.C);
for (int i = 0; i < sampleRate * 2; i++) {
	data.Add(rs.GetNext(i));
}

Create a list of doubles to store the resulting wave sample values, Set the frequency to a “C” then add 2 Seconds worth ( 2 X 441000 samples) to the list.

How can I actually hear what it sounds like?

The easiest way to hear it is to export the wave you have produced to a .wav file. It is reasonbly simple to create a .wav file just follow the specification here.

I found an implementation in the Sixport Synth project that I changed slightly for my needs. It simply writes a “test.wav” file to the bin directory of the application.

public static void SaveIntoStream(double[] sampleData, long sampleCount, int samplesPerSecond) {
	// Export
	FileStream stream = File.Create("test.wav");
	System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream);
	int RIFF = 0x46464952;
	int WAVE = 0x45564157;
	int formatChunkSize = 16;
	int headerSize = 8;
	int format = 0x20746D66;
	short formatType = 1;
	short tracks = 2;
	short bitsPerSample = 16;
	short frameSize = (short)(tracks * ((bitsPerSample + 7) / 8));
	int bytesPerSecond = samplesPerSecond * frameSize;
	int waveSize = 4;
	int data = 0x61746164;
	int samples = (int)sampleCount;
	int dataChunkSize = samples * frameSize;
	int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize;
	writer.Write(RIFF);
	writer.Write(fileSize);
	writer.Write(WAVE);
	writer.Write(format);
	writer.Write(formatChunkSize);
	writer.Write(formatType);
	writer.Write(tracks);
	writer.Write(samplesPerSecond);
	writer.Write(bytesPerSecond);
	writer.Write(frameSize);
	writer.Write(bitsPerSample);
	writer.Write(data);
	writer.Write(dataChunkSize);

	double sample_l;
	short sl;
	for (int i = 0; i < sampleCount; i++) {
		sample_l = sampleData[i] * 30000.0;
		if (sample_l < -32767.0f) { sample_l = -32767.0f; }
		if (sample_l > 32767.0f) { sample_l = 32767.0f; }
		sl = (short)sample_l;
		stream.WriteByte((byte)(sl & 0xff));
		stream.WriteByte((byte)(sl >> 8));
		stream.WriteByte((byte)(sl & 0xff));
		stream.WriteByte((byte)(sl >> 8));
	}
	stream.Close();
}

That’s pretty cool but I don’t think its going to win any awards

Well, yeah it is a really very simple synth but using that principle and mixing it with other waveforms it is possible to make some awesome sounds.

The source can be downloaded here

3 thoughts on “Making a simple audio synthesizer in C#

  1. Brilliant! I can’t wait to try this tonight. =)

    How would you suggest programming an active synth, one that plays as you the user interacts with it, as opposed to one produced by the programmers code to be written to wav for later listen/use?

  2. Im making a synth in a windows form. Using buttons as a kind of piano-like keyboard, then assigning keyboard keys and sounds to each button, so that when you press a key on your keyboard or click the button, it plays the sound assigned to that key. Heres some example code:

    private void Button1_KeyDown(object sender, KeyEventArgs e)
    {
    SoundPlayer SoundPlayer1 = new SoundPlayer(@”file/path/to/sound.wav);
    if (e.KeyCode == Keys.A) // use “KeyCode == Keys.[the key you want to use]”
    {
    SoundPlayer1.Play();
    }
    }
    private void Button1_OnClick(object sender, EventArgs e)
    {
    SoundPlayer SoundPlayer1 = new SoundPlayer(@”file/path/to/sound.wav);
    SoundPlayer1.Play(); // Plays the sound when the button is clicked
    }

    Hope this helps.

    • absolutely cool…. (I know cool is dead, but I am old as dirt in the music (almost 49). So using this principle, how would a person then program the ability to use a midi keyboard to play it back… Rather, to interface this code to my midi interface (a midisport 4×4). I am just starting to learn how to code in C# because I have some ideas for some VSTi modular stuff. So yes, I know I have a long way to go, but.. well you know.
      Any help greatly appreciated.

Leave a comment