Created
August 14, 2014 12:46
-
-
Save pensacola1989/ee6e726815f9e4e91d58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Audio | |
{ | |
using System; | |
using System.IO; | |
/// <summary> | |
/// Provides methods for saving byte arrays of audio samples to a wav file in mono or stereo. | |
/// </summary> | |
public static class WaveSaver | |
{ | |
/// <summary> | |
/// Saves the waveform as a mono audio file in wav format. | |
/// </summary> | |
/// <param name="samples">The individual samples that make up the waveform.</param> | |
/// <param name="filename">The filename of the output wav file.</param> | |
public static void SaveToWave(short[] samples, string filename) | |
{ | |
const short NumberOfChannels = 1; // mono audio | |
const short BytesPerSample = 2; // 16bit samples | |
const int SamplingRate = 44100; // 44.1 kHz | |
int totalBytes = checked(44 + (samples.Length * BytesPerSample * NumberOfChannels)); // size of headers + data | |
var output = new byte[totalBytes]; | |
Buffer.BlockCopy(GetLEBytes(0x46464952), 0, output, 0, 4); // "RIFF" | |
Buffer.BlockCopy(GetLEBytes(totalBytes - 8), 0, output, 4, 4); // RIFF chunk size | |
Buffer.BlockCopy(GetLEBytes(0x45564157), 0, output, 8, 4); // "WAVE" | |
Buffer.BlockCopy(GetLEBytes(0x20746D66), 0, output, 12, 4); // "fmt " | |
Buffer.BlockCopy(GetLEBytes(16), 0, output, 16, 4); // fmt chunk size | |
Buffer.BlockCopy(GetLEBytes((short)1), 0, output, 20, 2); // compression code (1 - PCM/Uncompressed) | |
Buffer.BlockCopy(GetLEBytes((short)NumberOfChannels), 0, output, 22, 2); // number of channels | |
Buffer.BlockCopy(GetLEBytes(SamplingRate), 0, output, 24, 4); // sampling rate | |
Buffer.BlockCopy(GetLEBytes(SamplingRate * BytesPerSample * NumberOfChannels), 0, output, 28, 4); // bytes/second | |
Buffer.BlockCopy(GetLEBytes((short)(BytesPerSample * NumberOfChannels)), 0, output, 32, 2); // block size | |
Buffer.BlockCopy(GetLEBytes((short)(BytesPerSample * 8)), 0, output, 34, 2); // bits per sample | |
Buffer.BlockCopy(GetLEBytes(0x61746164), 0, output, 36, 4); // "data" | |
Buffer.BlockCopy(GetLEBytes(totalBytes - 44), 0, output, 40, 4); // data chunk size | |
for (var i = 0; i < samples.Length; i++) | |
{ | |
Buffer.BlockCopy(GetLEBytes(samples[i]), 0, output, (BytesPerSample * i * NumberOfChannels) + 44, BytesPerSample); | |
} | |
File.WriteAllBytes(filename, output); | |
} | |
/// <summary> | |
/// Saves the waveform as a stereo audio file in wav format. | |
/// </summary> | |
/// <param name="leftSamples">The individual samples that make up the left channel of the waveform.</param> | |
/// <param name="rightSamples">The individual samples that make up the right channel of the waveform.</param> | |
/// <param name="filename">The filename of the output wav file.</param> | |
public static void SaveToWave(short[] leftSamples, short[] rightSamples, string filename) | |
{ | |
const short NumberOfChannels = 2; // stereo audio | |
const short BytesPerSample = 2; // 16bit samples | |
const int SamplingRate = 44100; // 44.1 kHz | |
var shortChannel = (leftSamples.Length < rightSamples.Length) ? leftSamples : rightSamples; | |
int totalBytes = checked(44 + (shortChannel.Length * BytesPerSample * NumberOfChannels)); // size of headers + data | |
var output = new byte[totalBytes]; | |
Buffer.BlockCopy(GetLEBytes(0x46464952), 0, output, 0, 4); // "RIFF" | |
Buffer.BlockCopy(GetLEBytes(totalBytes - 8), 0, output, 4, 4); // RIFF chunk size | |
Buffer.BlockCopy(GetLEBytes(0x45564157), 0, output, 8, 4); // "WAVE" | |
Buffer.BlockCopy(GetLEBytes(0x20746D66), 0, output, 12, 4); // "fmt " | |
Buffer.BlockCopy(GetLEBytes(16), 0, output, 16, 4); // fmt chunk size | |
Buffer.BlockCopy(GetLEBytes((short)1), 0, output, 20, 2); // compression code (1 - PCM/Uncompressed) | |
Buffer.BlockCopy(GetLEBytes((short)NumberOfChannels), 0, output, 22, 2); // number of channels | |
Buffer.BlockCopy(GetLEBytes(SamplingRate), 0, output, 24, 4); // sampling rate | |
Buffer.BlockCopy(GetLEBytes(SamplingRate * BytesPerSample * NumberOfChannels), 0, output, 28, 4); // bytes/second | |
Buffer.BlockCopy(GetLEBytes((short)(BytesPerSample * NumberOfChannels)), 0, output, 32, 2); // block size | |
Buffer.BlockCopy(GetLEBytes((short)(BytesPerSample * 8)), 0, output, 34, 2); // bits per sample | |
Buffer.BlockCopy(GetLEBytes(0x61746164), 0, output, 36, 4); // "data" | |
Buffer.BlockCopy(GetLEBytes(totalBytes - 44), 0, output, 40, 4); // data chunk size | |
for (var i = 0; i < shortChannel.Length; i++) | |
{ | |
Buffer.BlockCopy(GetLEBytes(leftSamples[i]), 0, output, (BytesPerSample * i * NumberOfChannels) + 44, BytesPerSample); | |
Buffer.BlockCopy(GetLEBytes(rightSamples[i]), 0, output, (BytesPerSample * i * NumberOfChannels) + 44 + BytesPerSample, BytesPerSample); | |
} | |
File.WriteAllBytes(filename, output); | |
} | |
/// <summary> | |
/// Gets a <c>byte</c> array that represents the specified <c>short</c> in little endian. | |
/// </summary> | |
/// <param name="value">The value to represent in the <c>byte</c> array.</param> | |
/// <returns>The <c>byte</c> array.</returns> | |
private static byte[] GetLEBytes(short value) | |
{ | |
if (BitConverter.IsLittleEndian) | |
{ | |
return BitConverter.GetBytes(value); | |
} | |
else | |
{ | |
return BitConverter.GetBytes((short)((value & 0xFF) << 8 | (value & 0xFF00) >> 8)); | |
} | |
} | |
/// <summary> | |
/// Gets a <c>byte</c> array that represents the specified <c>int</c> in little endian. | |
/// </summary> | |
/// <param name="value">The value to represent in the <c>byte</c> array.</param> | |
/// <returns>The <c>byte</c> array.</returns> | |
private static byte[] GetLEBytes(int value) | |
{ | |
if (BitConverter.IsLittleEndian) | |
{ | |
return BitConverter.GetBytes(value); | |
} | |
else | |
{ | |
return BitConverter.GetBytes((int)((value & 0xFF) << 24) | (int)((value & 0xFF00) << 8) | |
| (int)((value & 0xFF0000) >> 8) | (int)((value & 0xFF000000) >> 24)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment