public static void WriteSingleChunkHeader(WavSingleChunkHeader header, Stream wavStream) { BinaryEndianWriter w = new BinaryEndianWriter(wavStream); w.Write(Encoding.Default.GetBytes(header.FileId)); w.Write(header.FileLength); w.Write(Encoding.Default.GetBytes(header.RiffType)); w.Write(Encoding.Default.GetBytes(header.ChunkHeaderId)); w.Write(header.ChunkHeaderLength); w.Write(header.FormatTag); w.Write(header.Channels); w.Write(header.SamplesPerSec); w.Write(header.AvgBytesPerSec); w.Write(header.BlockAlign); w.Write(header.BitsPerSample); w.Write(header.ExtraBytes); w.Write(Encoding.Default.GetBytes(header.ChunkId)); w.Write(header.ChunkLength); }
public static void CreatePreview(int offset, int length, int fade, float volume, bool volumeApplied, string dstFilename, params AudioFile[] srcFilenames) { if (srcFilenames == null || srcFilenames.Length == 0 || (srcFilenames.Length == 1 && (srcFilenames[0] == null || srcFilenames[0].Name.Length == 0))) return; FileHelper.Delete(dstFilename); WavSingleChunkHeader[] whi = new WavSingleChunkHeader[srcFilenames.Length]; BinaryEndianReader[] br = new BinaryEndianReader[srcFilenames.Length]; float[] vols = new float[srcFilenames.Length]; int outWav = 0; //use this input wav as the format for the output wav int maxLen = 0; for (int c = 0; c < srcFilenames.Length; c++) { br[c] = new BinaryEndianReader(File.OpenRead(srcFilenames[c].Name)); whi[c] = ParseWavSingleChunkHeader(br[c].BaseStream); if (!volumeApplied) vols[c] = srcFilenames[c].Volume / 100F; //get percentage else vols[c] = 1; //100% //move to the correct point in each wav uint wOffset = (uint)(whi[c].AvgBytesPerSec * ((float)offset / 1000)); wOffset -= wOffset % whi[c].BlockAlign; br[c].BaseStream.Seek((long)wOffset, SeekOrigin.Current); if (whi[c].AudioLength > maxLen) maxLen = whi[c].AudioLength; if (whi[c].Channels == 2) outWav = c; } WavSingleChunkHeader who = new WavSingleChunkHeader(); if (length == 0) length = maxLen; uint wLength = (uint)(whi[outWav].AvgBytesPerSec * ((float)length / 1000)); wLength -= wLength % whi[outWav].BlockAlign; who.FileId = "RIFF"; who.FileLength = (uint)(br[outWav].BaseStream.Length - whi[outWav].FileLength) + wLength; who.RiffType = "WAVE"; who.ChunkHeaderId = "fmt "; who.ChunkHeaderLength = whi[outWav].ChunkHeaderLength; who.FormatTag = whi[outWav].FormatTag; who.Channels = whi[outWav].Channels; who.SamplesPerSec = whi[outWav].SamplesPerSec; who.AvgBytesPerSec = whi[outWav].AvgBytesPerSec; who.BlockAlign = whi[outWav].BlockAlign; who.BitsPerSample = whi[outWav].BitsPerSample; who.ExtraBytes = whi[outWav].ExtraBytes; who.ChunkId = "data"; who.ChunkLength = wLength; using (FileStream fso = File.OpenWrite(dstFilename)) { WriteSingleChunkHeader(who, fso); int loops = (int)((who.AvgBytesPerSec / who.BlockAlign) * ((float)length / 1000)); int fadeLen = (int)((who.AvgBytesPerSec / who.BlockAlign) * ((float)fade / 1000)); Double maxVol = (volume / (float)srcFilenames.Length); //reduce volume Audio in game maxVol *= 1F + ((srcFilenames.Length - 1) * 0.33F); //add an extra third per file to cater for volume loss Double vol = 0; //initial volume if (fade == 0) vol = maxVol; int b32; BinaryEndianWriter bw = new BinaryEndianWriter(fso); Double step = (double)(maxVol - 0) / fadeLen; //fade in if (Double.IsInfinity(step)) step = 0; int allLeft = 0; int allRight = 0; long[] streamPos = new long[br.Length]; //fast way to track pos in stream for (int c = 0; c < br.Length; c++) streamPos[c] = br[c].BaseStream.Position; long[] streamLen = new long[br.Length]; //fast way to get length of stream for (int c = 0; c < br.Length; c++) streamLen[c] = br[c].BaseStream.Length; for (int i = 0; i != loops; i++) { if (i == fadeLen) step = 0; //use max volume if (i == loops - fadeLen) //fade out step = (double)(0 - maxVol) / fadeLen; allLeft = 0; allRight = 0; for (int c = 0; c < br.Length; c++) //each input stream { BinaryEndianReader b = br[c]; WavSingleChunkHeader w = whi[c]; //Left channel b32 = 0; if (streamPos[c] + 2 < streamLen[c]) { b32 = (int)(b.ReadInt16(EndianType.Little) * vols[c]); streamPos[c] += 2; } allLeft += (int)(b32 * vol); allLeft = (short)Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, allLeft)); if (who.Channels > 1) { if (w.Channels > 1) { //Right channel b32 = 0; if (streamPos[c] + 2 < streamLen[c]) { b32 = (int)(b.ReadInt16(EndianType.Little) * vols[c]); streamPos[c] += 2; } } allRight += (int)(b32 * vol); allRight = (short)Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, allRight)); } } bw.Write((short)allLeft); if (who.Channels > 1) bw.Write((short)allRight); vol += step; } foreach (BinaryEndianReader b in br) b.Close(); fso.Flush(); } }
public static void CreateSilentWav(int length, string dstFilename, bool stereo, int samplesPerSec) { FileHelper.Delete(dstFilename); ushort bits = 16; ushort channels = (ushort)(stereo ? 2 : 1); ushort blockAlign = (ushort)(channels * 2); WavSingleChunkHeader who = new WavSingleChunkHeader(); uint wLength = (uint)((float)(blockAlign * samplesPerSec) * (float)(length / 1000F)); wLength -= wLength % blockAlign; who.FileId = "RIFF"; who.FileLength = (uint)(wLength + 46) - 8; who.RiffType = "WAVE"; who.ChunkHeaderId = "fmt "; who.ChunkHeaderLength = 18; who.FormatTag = 1; //raw wav who.Channels = channels; who.SamplesPerSec = (uint)samplesPerSec; who.AvgBytesPerSec = (uint)(blockAlign * samplesPerSec); who.BlockAlign = blockAlign; who.BitsPerSample = bits; who.ExtraBytes = new byte[2]; who.ChunkId = "data"; who.ChunkLength = wLength; using (FileStream fso = File.OpenWrite(dstFilename)) { WriteSingleChunkHeader(who, fso); byte[] buffer = new byte[who.AvgBytesPerSec]; for (int i = 0; i < buffer.Length; i++) buffer[i] = 0; long written = 0; while (written + buffer.Length < wLength) { fso.Write(buffer, 0, buffer.Length); written += buffer.Length; } if (written != wLength) fso.Write(buffer, 0, (int)(wLength - written)); fso.Flush(); } }
public static WavSingleChunkHeader ParseWavSingleChunkHeader(Stream wavStream) { WavSingleChunkHeader w = new WavSingleChunkHeader(); byte[] b; BinaryEndianReader r = new BinaryEndianReader(wavStream); b = r.ReadBytes(4); w.FileId = Encoding.Default.GetString(b); w.FileLength = r.ReadUInt32(EndianType.Little); b = r.ReadBytes(4); w.RiffType = Encoding.Default.GetString(b); b = r.ReadBytes(4); w.ChunkHeaderId = Encoding.Default.GetString(b); w.ChunkHeaderLength = r.ReadUInt32(EndianType.Little); long p = wavStream.Position; w.FormatTag = r.ReadUInt16(EndianType.Little); w.Channels = r.ReadUInt16(EndianType.Little); w.SamplesPerSec = r.ReadUInt32(EndianType.Little); w.AvgBytesPerSec = r.ReadUInt32(EndianType.Little); w.BlockAlign = r.ReadUInt16(EndianType.Little); w.BitsPerSample = r.ReadUInt16(EndianType.Little); if (wavStream.Position - p != w.ChunkHeaderLength) w.ExtraBytes = r.ReadBytes((int)(w.ChunkHeaderLength - (wavStream.Position - p))); b = r.ReadBytes(4); w.ChunkId = Encoding.Default.GetString(b); w.ChunkLength = r.ReadUInt32(EndianType.Little); w.DataOffset = (int)wavStream.Position; return w; }
public static void CreateSilentWav(int length, string dstFilename, params string[] srcFilenames) { if (srcFilenames == null || (srcFilenames.Length == 1 && srcFilenames[0].Length == 0)) return; FileHelper.Delete(dstFilename); WavSingleChunkHeader[] whi = new WavSingleChunkHeader[srcFilenames.Length]; BinaryEndianReader[] br = new BinaryEndianReader[srcFilenames.Length]; int outWav = 0; //use this input wav as the format for the output wav for (int c = 0; c < srcFilenames.Length; c++) { br[c] = new BinaryEndianReader(File.OpenRead(srcFilenames[c])); whi[c] = ParseWavSingleChunkHeader(br[c].BaseStream); if (whi[c].Channels == 2) outWav = c; } WavSingleChunkHeader who = new WavSingleChunkHeader(); uint wLength = (uint)((float)whi[outWav].AvgBytesPerSec * (float)(length / 1000F)); wLength -= wLength % whi[outWav].BlockAlign; who.FileId = "RIFF"; who.FileLength = (uint)(whi[outWav].DataOffset + wLength) - 8; who.RiffType = "WAVE"; who.ChunkHeaderId = "fmt "; who.ChunkHeaderLength = whi[outWav].ChunkHeaderLength; who.FormatTag = whi[outWav].FormatTag; who.Channels = whi[outWav].Channels; who.SamplesPerSec = whi[outWav].SamplesPerSec; who.AvgBytesPerSec = whi[outWav].AvgBytesPerSec; who.BlockAlign = whi[outWav].BlockAlign; who.BitsPerSample = whi[outWav].BitsPerSample; who.ExtraBytes = whi[outWav].ExtraBytes; who.ChunkId = "data"; who.ChunkLength = wLength; foreach (BinaryEndianReader b in br) b.Close(); using (FileStream fso = File.OpenWrite(dstFilename)) { WriteSingleChunkHeader(who, fso); byte[] buffer = new byte[who.AvgBytesPerSec]; for (int i = 0; i < buffer.Length; i++) buffer[i] = 0; long written = 0; while (written + buffer.Length < wLength) { fso.Write(buffer, 0, buffer.Length); written += buffer.Length; } if (written != wLength) fso.Write(buffer, 0, (int)(wLength - written)); fso.Flush(); } }