/* This file is part of CustomizeMii * Copyright (C) 2009 Leathl * * CustomizeMii is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CustomizeMii is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using System; using System.IO; namespace WaveFile { /// /// A class for RIFF Wave files /// public class Wave { //Private Variables private int fmtOffset; private int dataOffset; private int smplOffset; private byte[] waveFile; //Public Variables /// /// The Samplerate of the Wave file /// public int SampleRate { get { return GetSampleRate(); } } /// /// The Bitdepth of the Wave file /// public int BitDepth { get { return GetBitDepth(); } } /// /// The number of channels of the Wave file /// public int ChannelCount { get { return GetChannelCount(); } } /// /// The format of the Wave file's data. 1 = PCM /// public int DataFormat { get { return GetDataFormat(); } } /// /// The number of Loops in the Wave file /// public int LoopCount { get { return GetLoopCount(); } } /// /// The start sample of the first Loop (if exist) /// public int LoopStart { get { return GetLoopStart(); } } /// /// The total number of Frames /// public int SampleCount { get { return GetFrameCount(); } } //Public Functions public Wave(string waveFile) { using (FileStream fs = new FileStream(waveFile, FileMode.Open)) { byte[] temp = new byte[fs.Length]; fs.Read(temp, 0, temp.Length); this.waveFile = temp; } if (!CheckWave()) throw new Exception("This is not a supported PCM Wave File!"); if (!GetFmtOffset()) throw new Exception("The format section couldn't be found!"); if (!GetDataOffset()) throw new Exception("The data section couldn't be found!"); GetSmplOffset(); } public Wave(byte[] waveFile) { this.waveFile = waveFile; if (!CheckWave()) throw new Exception("This is not a supported PCM Wave File!"); if (!GetFmtOffset()) throw new Exception("The format section couldn't be found!"); if (!GetDataOffset()) throw new Exception("The data section couldn't be found!"); GetSmplOffset(); } /// /// Returns the Wave file as a Byte Array /// /// public byte[] ToByteArray() { return waveFile; } /// /// Returns the Wave file as a Memory Stream /// /// public MemoryStream ToMemoryStream() { return new MemoryStream(waveFile); } /// /// Returns only the audio data of the Wave file (No header or anything else) /// /// public byte[] GetAllFrames() { int dataLength = GetDataLength(); MemoryStream ms = new MemoryStream(); ms.Write(waveFile, dataOffset, dataLength); return ms.ToArray(); } /// /// Trims the start of the wave to the given sample /// /// /// public MemoryStream TrimStart(int newStartSample) { if (newStartSample > this.SampleCount) throw new Exception(string.Format("The loop start sample ({0}) is higher than the total number of samples ({1}) in this file!", newStartSample, this.SampleCount)); MemoryStream msOut = new MemoryStream(); msOut.Seek(0, SeekOrigin.Begin); if (newStartSample == 0) { msOut.Write(waveFile, 0, waveFile.Length); msOut.Seek(0, SeekOrigin.Begin); return msOut; } msOut.Write(waveFile, 0, this.dataOffset + 8); msOut.Write(waveFile, this.ChannelCount * 2 * newStartSample, waveFile.Length - (this.dataOffset + 8 + (this.ChannelCount * 2 * newStartSample))); int cutted = (this.ChannelCount * 2 * newStartSample) - (this.dataOffset + 8); byte[] newLength = BitConverter.GetBytes((UInt32)msOut.Position); byte[] dataLength = BitConverter.GetBytes(BitConverter.ToInt32(waveFile, this.dataOffset + 4) - cutted); msOut.Seek(4, SeekOrigin.Begin); msOut.Write(newLength, 0, newLength.Length); msOut.Seek(this.dataOffset + 4, SeekOrigin.Begin); msOut.Write(dataLength, 0, dataLength.Length); msOut.Seek(0, SeekOrigin.Begin); return msOut; } /// /// Closes the Wave file /// public void Close() { waveFile = null; } //Private Functions private int GetFrameCount() { int dataLength = GetDataLength(); return (dataLength / (this.ChannelCount * 2)); } private int GetLoopStart() { if (smplOffset == -1) return 0; byte[] temp = new byte[4]; temp[0] = waveFile[smplOffset + 52]; temp[1] = waveFile[smplOffset + 53]; temp[2] = waveFile[smplOffset + 54]; temp[3] = waveFile[smplOffset + 55]; return BitConverter.ToInt32(temp, 0); } private int GetLoopCount() { if (smplOffset == -1) return 0; byte[] temp = new byte[4]; temp[0] = waveFile[smplOffset + 36]; temp[1] = waveFile[smplOffset + 37]; temp[2] = waveFile[smplOffset + 38]; temp[3] = waveFile[smplOffset + 39]; return BitConverter.ToInt32(temp, 0); } private bool GetSmplOffset() { try { int length = (waveFile.Length > 5004 ? (waveFile.Length - 5000) : 0); for (int i = waveFile.Length - 4; i > length; i--) { if (waveFile[i] == 's' && waveFile[i + 1] == 'm' && waveFile[i + 2] == 'p' && waveFile[i + 3] == 'l') { this.smplOffset = i; return true; } } } catch { } for (int i = 0; i < waveFile.Length - 4; i++) { if (waveFile[i] == 's' && waveFile[i + 1] == 'm' && waveFile[i + 2] == 'p' && waveFile[i + 3] == 'l') { this.smplOffset = i; return true; } } this.smplOffset = -1; return false; } private bool GetFmtOffset() { if (waveFile[12] == 'f' && waveFile[13] == 'm' && waveFile[14] == 't' && waveFile[15] == ' ') { this.fmtOffset = 12; return true; } int length = (waveFile.Length > 5004 ? 5000 : waveFile.Length - 4); for (int i = 0; i < length; i++) { if (waveFile[i] == 'f' && waveFile[i + 1] == 'm' && waveFile[i + 2] == 't' && waveFile[i + 3] == ' ') { this.fmtOffset = i; return true; } } this.fmtOffset = -1; return false; } private int GetDataLength() { byte[] temp = new byte[4]; temp[0] = waveFile[dataOffset + 4]; temp[1] = waveFile[dataOffset + 5]; temp[2] = waveFile[dataOffset + 6]; temp[3] = waveFile[dataOffset + 7]; return BitConverter.ToInt32(temp, 0); } private bool GetDataOffset() { if (waveFile[40] == 'd' && waveFile[41] == 'a' && waveFile[42] == 't' && waveFile[43] == 'a') { this.dataOffset = 40; return true; } for (int i = 0; i < waveFile.Length - 4; i++) { if (waveFile[i] == 'd' && waveFile[i + 1] == 'a' && waveFile[i + 2] == 't' && waveFile[i + 3] == 'a') { this.dataOffset = i; return true; } } this.dataOffset = -1; return false; } private int GetSampleRate() { byte[] temp = new byte[4]; temp[0] = waveFile[fmtOffset + 12]; temp[1] = waveFile[fmtOffset + 13]; temp[2] = waveFile[fmtOffset + 14]; temp[3] = waveFile[fmtOffset + 15]; return BitConverter.ToInt32(temp, 0); } private int GetBitDepth() { byte[] temp = new byte[2]; temp[0] = waveFile[fmtOffset + 22]; temp[1] = waveFile[fmtOffset + 23]; return BitConverter.ToInt16(temp, 0); } private int GetChannelCount() { byte[] temp = new byte[2]; temp[0] = waveFile[fmtOffset + 10]; temp[1] = waveFile[fmtOffset + 11]; return BitConverter.ToInt16(temp, 0); } private int GetDataFormat() { byte[] temp = new byte[2]; temp[0] = waveFile[fmtOffset + 8]; temp[1] = waveFile[fmtOffset + 9]; return BitConverter.ToInt16(temp, 0); } private bool CheckWave() { if (waveFile[0] != 'R' || waveFile[1] != 'I' || waveFile[2] != 'F' || waveFile[3] != 'F' || waveFile[8] != 'W' || waveFile[9] != 'A' || waveFile[10] != 'V' || waveFile[11] != 'E') return false; return true; } } }