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#
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;
|
|
}
|
|
}
|
|
} |