You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
6.1 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Diagnostics;
namespace DotNetCTFDumper.Utils
{
class WavFile
{
public int samplesPerSecond { get; set; }
public int samplesTotalCount { get; set; }
public string wavFilename { get; private set; }
public byte[] metaData { get; set; }
public WavFile(string filename)
{
samplesTotalCount = samplesPerSecond = -1;
wavFilename = filename;
metaData = null;
}
/// <summary>
/// Reading all samples of a 16-bit stereo wav file into arrays.
/// </summary>
public bool readData(ref double[] L, ref double[] R)
{
try
{
BinaryReader reader = new BinaryReader(File.Open(wavFilename, FileMode.Open));
// header (8 + 4 bytes):
byte[] riffId = reader.ReadBytes(4); // "RIFF"
int fileSize = reader.ReadInt32(); // size of entire file
byte[] typeId = reader.ReadBytes(4); // "WAVE"
if (Encoding.ASCII.GetString(typeId) != "WAVE") return false;
// chunk 1 (8 + 16 or 18 bytes):
byte[] fmtId = reader.ReadBytes(4); // "fmt "
int fmtSize = reader.ReadInt32(); // size of chunk in bytes
int fmtCode = reader.ReadInt16(); // 1 - for PCM
int channels = reader.ReadInt16(); // 1 - mono, 2 - stereo
int sampleRate = reader.ReadInt32(); // sample rate per second
int byteRate = reader.ReadInt32(); // bytes per second
int dataAlign = reader.ReadInt16(); // data align
int bitDepth = reader.ReadInt16(); // 8, 16, 24, 32, 64 bits
if (fmtCode != 1) return false; // not PCM
if (channels != 2) return false; // only Stereo files in this version
if (bitDepth != 16) return false; // only 16-bit in this version
if (fmtSize == 18) // fmt chunk can be 16 or 18 bytes
{
int fmtExtraSize = reader.ReadInt16(); // read extra bytes size
reader.ReadBytes(fmtExtraSize); // skip over "INFO" chunk
}
// chunk 2 (8 bytes):
byte[] dataId = reader.ReadBytes(4); // "data"
int dataSize = reader.ReadInt32(); // size of audio data
Debug.Assert(Encoding.ASCII.GetString(dataId) == "data", "Data chunk not found!");
samplesPerSecond = sampleRate; // sample rate (usually 44100)
samplesTotalCount = dataSize / (bitDepth / 8); // total samples count in audio data
// audio data:
L = R = new double[samplesTotalCount / 2];
for (int i = 0, s = 0; i < samplesTotalCount; i += 2)
{
L[s] = Convert.ToDouble(reader.ReadInt16());
R[s] = Convert.ToDouble(reader.ReadInt16());
s++;
}
// metadata:
long moreBytes = reader.BaseStream.Length - reader.BaseStream.Position;
if (moreBytes > 0)
{
metaData = reader.ReadBytes((int)moreBytes);
}
reader.Close();
}
catch
{
Debug.Fail("Failed to read file.");
return false;
}
return true;
}
/// <summary>
/// Writing all 16-bit stereo samples from arrays into wav file.
/// </summary>
public bool writeData(double[] L, double[] R)
{
Debug.Assert((samplesTotalCount != -1) && (samplesPerSecond != -1),
"No sample count or sample rate info!");
try
{
BinaryWriter writer = new BinaryWriter(File.Create(wavFilename));
int fileSize = 44 + samplesTotalCount * 2;
if (metaData != null)
{
fileSize += metaData.Length;
}
// header:
writer.Write(Encoding.ASCII.GetBytes("RIFF")); // "RIFF"
writer.Write((Int32)fileSize); // size of entire file with 16-bit data
writer.Write(Encoding.ASCII.GetBytes("WAVE")); // "WAVE"
// chunk 1:
writer.Write(Encoding.ASCII.GetBytes("fmt ")); // "fmt "
writer.Write((Int32)16); // size of chunk in bytes
writer.Write((Int16)1); // 1 - for PCM
writer.Write((Int16)2); // only Stereo files in this version
writer.Write((Int32)samplesPerSecond); // sample rate per second (usually 44100)
writer.Write((Int32)(4 * samplesPerSecond)); // bytes per second (usually 176400)
writer.Write((Int16)4); // data align 4 bytes (2 bytes sample stereo)
writer.Write((Int16)16); // only 16-bit in this version
// chunk 2:
writer.Write(Encoding.ASCII.GetBytes("data")); // "data"
writer.Write((Int32)(samplesTotalCount * 2)); // size of audio data 16-bit
// audio data:
for (int i = 0, s = 0; i < samplesTotalCount; i += 2)
{
writer.Write(Convert.ToInt16(L[s]));
writer.Write(Convert.ToInt16(R[s]));
s++;
}
// metadata:
if (metaData != null)
{
writer.Write(metaData);
}
writer.Flush();
writer.Close();
}
catch
{
Debug.Fail("Failed to write file.");
return false;
}
return true;
}
}
}