/// <summary> /// Write a shortened wave. /// </summary> /// <param name="w">The writer.</param> public void WriteShortened(FileWriter w) { //Format. PcmFormat pcmFormat = PcmFormat.Encoded; if (Audio.EncodingType.Equals(typeof(PCM8Signed))) { w.Write((byte)PcmFormat.SignedPCM8); pcmFormat = PcmFormat.SignedPCM8; } else if (Audio.EncodingType.Equals(typeof(PCM16))) { w.Write((byte)PcmFormat.PCM16); pcmFormat = PcmFormat.PCM16; } else if (Audio.EncodingType.Equals(typeof(ImaAdpcm))) { w.Write((byte)PcmFormat.Encoded); pcmFormat = PcmFormat.Encoded; } else { throw new Exception("Invalid channel format!"); } //Data. w.Write(Loops); w.Write((ushort)SampleRate); ushort nTimeSampleRate = (ushort)(16756991 / SampleRate); if (BackupNTime != 0) { w.Write(BackupNTime); } else { w.Write(nTimeSampleRate); } if (Loops) { w.Write((ushort)(Sample2Offset(LoopStart, pcmFormat) / 4)); } else { w.Write((ushort)(pcmFormat == PcmFormat.Encoded ? 1 : 0)); } if (Loops) { w.Write((uint)((Audio.DataSize - Sample2Offset(LoopStart, pcmFormat)) / 4)); } else { w.Write((uint)((Audio.DataSize - Sample2Offset((uint)(pcmFormat == PcmFormat.Encoded ? 1 : 0), pcmFormat)) / 4)); } Audio.Write(w); }
/// <summary> /// Read the file. /// </summary> /// <param name="r">The reader.</param> public override void Read(FileReader r) { //Read header. r.OpenFile <NHeader>(out _); //Head block. r.OpenBlock(0, out _, out _); PcmFormat pcmFormat = (PcmFormat)r.ReadByte(); Loops = r.ReadBoolean(); int numChannels = r.ReadByte(); r.ReadByte(); SampleRate = r.ReadUInt16(); r.ReadUInt16(); LoopStart = r.ReadUInt32(); uint numSamples = r.ReadUInt32(); if (Loops) { LoopEnd = numSamples; } r.OpenOffset("dataOffset"); uint numBlocks = r.ReadUInt32(); uint blockSize = r.ReadUInt32(); uint blockSamples = r.ReadUInt32(); uint lastBlockSize = r.ReadUInt32(); uint lastBlockSamples = r.ReadUInt32(); r.ReadBytes(32); //Encoding type. Type encodingType = null; switch (pcmFormat) { case PcmFormat.SignedPCM8: encodingType = typeof(PCM8Signed); break; case PcmFormat.PCM16: encodingType = typeof(PCM16); break; case PcmFormat.Encoded: encodingType = typeof(ImaAdpcm); break; } //Data block. r.JumpToOffset("dataOffset", true, true); Audio.Read(r, encodingType, numChannels, numBlocks, blockSize, blockSamples, lastBlockSize, lastBlockSamples, 0); }
/// <summary> /// Read a shortened wave. /// </summary> /// <param name="r">The reader.</param> /// <param name="length">The data length.</param> /// <returns>A wave.</returns> public static Wave ReadShortened(FileReader r, uint length) { //Set up wave. Wave w = new Wave(); PcmFormat pcmFormat = (PcmFormat)r.ReadByte(); w.Loops = r.ReadBoolean(); int numChannels = 1; w.SampleRate = r.ReadUInt16(); w.BackupNTime = r.ReadUInt16(); w.LoopStart = r.ReadUInt16(); r.ReadUInt32(); //Non-loop length. //Data size. uint dataSize = length - 12; w.LoopEnd = dataSize * 2; //Loop start offset is divided by 4 for some reason. w.LoopStart = Offset2Samples(w.LoopStart * 4, pcmFormat); w.LoopEnd = Offset2Samples(dataSize, pcmFormat); //Switch type. Type format = null; switch (pcmFormat) { case PcmFormat.SignedPCM8: format = typeof(PCM8Signed); break; case PcmFormat.PCM16: format = typeof(PCM16); break; case PcmFormat.Encoded: format = typeof(ImaAdpcm); break; } //Read channels. w.Audio.Read(r, format, numChannels, (int)dataSize, (int)w.LoopEnd, 0); //Return the wave. return(w); }
/// <summary> /// Convert a sample to an offset. /// </summary> /// <param name="sample">The offset.</param> /// <param name="format">The format.</param> /// <returns>The offset number.</returns> public static uint Sample2Offset(uint sample, PcmFormat format) { //Offset. uint offset = sample; switch (format) { case PcmFormat.SignedPCM8: return(offset); case PcmFormat.PCM16: return(offset * 2); case PcmFormat.Encoded: return((offset + 8) / 2); } return(0); }
/// <summary> /// Convert an offset to a sample. /// </summary> /// <param name="offset">The offset.</param> /// <param name="format">The format.</param> /// <returns>The sample number.</returns> public static uint Offset2Samples(uint offset, PcmFormat format) { //Sample. uint samples = offset; switch (format) { case PcmFormat.SignedPCM8: return(samples); case PcmFormat.PCM16: return(samples / 2); case PcmFormat.Encoded: return(samples * 2 - 8); } return(0); }
/// <summary> /// Write the file. /// </summary> /// <param name="w">The writer.</param> public override void Write(FileWriter w) { //Init header. w.InitFile <NHeader>("STRM", ByteOrder.LittleEndian, null, 2); long countOff = w.Position - 2; //Head block. w.Write("HEAD".ToCharArray()); w.Write((uint)0x50); //Format. PcmFormat pcmFormat = PcmFormat.Encoded; uint blockSamples = (uint)Audio.NumSamples; uint blockSize = (uint)Audio.DataSize; if (Audio.EncodingType.Equals(typeof(PCM8Signed))) { w.Write((byte)PcmFormat.SignedPCM8); pcmFormat = PcmFormat.SignedPCM8; } else if (Audio.EncodingType.Equals(typeof(PCM16))) { w.Write((byte)PcmFormat.PCM16); pcmFormat = PcmFormat.PCM16; } else if (Audio.EncodingType.Equals(typeof(ImaAdpcm))) { w.Write((byte)PcmFormat.Encoded); pcmFormat = PcmFormat.Encoded; blockSize = (uint)Audio.BlockSize; blockSamples = (blockSize - 4) * 2; } else { throw new Exception("Invalid channel format!"); } w.Write(Loops); w.Write((byte)Audio.Channels.Count()); w.Write((byte)0); w.Write((ushort)SampleRate); w.Write((ushort)Math.Floor((decimal)523655.96875 * ((decimal)1 / (decimal)SampleRate))); w.Write(LoopStart); w.Write(Audio.NumSamples); w.Write((uint)0x68); w.Write(Audio.NumBlocks); w.Write(blockSize); w.Write(blockSamples); w.Write(Audio.LastBlockSize); w.Write(Audio.LastBlockSamples); w.Write(new byte[0x20]); long bak = w.Position; w.Write("DATA".ToCharArray()); w.Write((uint)0); Audio.Write(w); w.Pad(4); long bak2 = w.Position; w.Position = bak + 4; w.Write((uint)(bak2 - bak)); w.Position = bak2; w.CloseFile(); bak = w.Position; w.Position = countOff; w.Write((ushort)2); w.Position = bak; }