How to Generate Wave Files with Random Audio Data in C#

If you want to generate *.wav files with random audio data in C#, you’ve come to the right place. Check out the code below, which you can simply dump into a fresh console application and test run. You can also use the code below to convert from floating point audio samples which have a range from -1 to 1 (both inclusive) into WAVE PCM audio files.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace RandomAudioGenerator
{
	internal class Program
	{
		private static void Main(string[] args)
		{
			var random = new Random();
			var data = new float[random.Next(1, 1000001)];
			for (var i = 0; i < data.Length; i++)
			{
				data[i] = (float)random.Next(0, 65537) / 65536;
				if (random.Next(0, 2) == 0)
					data[i] = -data[i];
			}
			var directory = Directory.GetCurrentDirectory();
			var path = Path.Combine(directory, Guid.NewGuid() + ".wav");
			GenerateAudioFile(path, data, 1, 44000);
			Process.Start("explorer.exe", "/select, " + path);
		}

		private static void GenerateAudioFile(string path, IReadOnlyCollection data, int channels, int frequency)
		{
			using (var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write))
			{
				// The following values are based on http://soundfile.sapp.org/doc/WaveFormat/
				const ushort bitsPerSample = (ushort)16;
				const string chunkId = "RIFF";
				const string format = "WAVE";
				const string subChunk1Id = "fmt ";
				const uint subChunk1Size = (uint)16;
				const ushort audioFormat = (ushort)1;
				var numChannels = (ushort)channels;
				var sampleRate = (uint)frequency;
				var byteRate = (uint)(sampleRate * channels * bitsPerSample / 8);  // SampleRate * NumChannels * BitsPerSample/8
				var blockAlign = (ushort)(numChannels * bitsPerSample / 8); // NumChannels * BitsPerSample/8
				const string subChunk2Id = "data";
				var subChunk2Size = (uint)(data.Count * channels * bitsPerSample / 8); // NumSamples * NumChannels * BitsPerSample/8
				var chunkSize = (uint)(36 + subChunk2Size); // 36 + SubChunk2Size
				// Start writing the file.
				WriteString(stream, chunkId);
				WriteInteger(stream, chunkSize);
				WriteString(stream, format);
				WriteString(stream, subChunk1Id);
				WriteInteger(stream, subChunk1Size);
				WriteShort(stream, audioFormat);
				WriteShort(stream, numChannels);
				WriteInteger(stream, sampleRate);
				WriteInteger(stream, byteRate);
				WriteShort(stream, blockAlign);
				WriteShort(stream, bitsPerSample);
				WriteString(stream, subChunk2Id);
				WriteInteger(stream, subChunk2Size);
				foreach (var sample in data)
				{
					// De-normalize the samples to 16 bits.
					var deNormalizedSample = (short)0;
					if (sample > 0)
					{
						var temp = sample * short.MaxValue;
						if (temp > short.MaxValue)
							temp = short.MaxValue;
						deNormalizedSample = (short)temp;
					}
					if (sample < 0)
					{
						var temp = sample * (-short.MinValue);
						if (temp < short.MinValue)
							temp = short.MinValue;
						deNormalizedSample = (short)temp;
					}
					WriteShort(stream, (ushort)deNormalizedSample);
				}
			}
		}

		private static void WriteString(Stream stream, string value)
		{
			foreach (var character in value)
				stream.WriteByte((byte)character);
		}

		private static void WriteInteger(Stream stream, uint value)
		{
			stream.WriteByte((byte)(value & 0xFF));
			stream.WriteByte((byte)((value >> 8) & 0xFF));
			stream.WriteByte((byte)((value >> 16) & 0xFF));
			stream.WriteByte((byte)((value >> 24) & 0xFF));
		}

		private static void WriteShort(Stream stream, ushort value)
		{
			stream.WriteByte((byte)(value & 0xFF));
			stream.WriteByte((byte)((value >> 8) & 0xFF));
		}
	}
}