/// <summary> /// Get the size of the data block. /// </summary> /// <returns></returns> public UInt32 GetSize(byte encoding, ref b_stm.InfoBlock wavInfo) { UInt32 size = 0x20; switch (encoding) { case EncodingTypes.PCM8: size += (UInt32)(pcm8.Length * pcm8[0].Length); int padd0 = pcm8[0].Length; while ((padd0) % 0x20 != 0) { padd0 += 1; } padd0 -= pcm8[0].Length; size += (UInt32)(padd0 * pcm8.Length); break; case EncodingTypes.PCM16: size += (UInt32)(pcm16.Length * pcm16[0].Length * 2); int padd1 = pcm16[0].Length * 2; while ((padd1) % 0x20 != 0) { padd1 += 1; } padd1 -= (pcm16[0].Length * 2); size += (UInt32)(padd1 * pcm16.Length); break; case EncodingTypes.DSP_ADPCM: size += (UInt32)(dspAdpcm.Length * dspAdpcm[0].Length); int padd2 = dspAdpcm[0].Length; while ((padd2) % 0x20 != 0) { padd2 += 1; } padd2 -= dspAdpcm[0].Length; size += (UInt32)(padd2 * dspAdpcm.Length); break; } return(size); }
/// <summary> /// Get data from a b_stm. /// </summary> /// <param name="wavInfo"></param> /// <returns></returns> public object GetDataSTM(b_stm.StreamSoundInfo wavInfo, b_stm.InfoBlock info) { object returnValue = null; //See encoding. switch (wavInfo.encoding) { case EncodingTypes.PCM8: return(EncoderFactory.SignedPcm8ToPcm8(pcm8)); case EncodingTypes.PCM16: return(pcm16); case EncodingTypes.DSP_ADPCM: List <DspAdpcmInfo> context = new List <DspAdpcmInfo>(); foreach (b_stm.ChannelInfo c in info.channels) { context.Add(c.dspAdpcmInfo); } return(EncoderFactory.DspApcmToPcm16(dspAdpcm, wavInfo.sampleCount, context.ToArray())); } return(returnValue); }
/// <summary> /// Read a soundN'Stream block. /// </summary> /// <param name="br">The reader.</param> /// <param name="info">Stream info.</param> /// <param name="seek">Seek info for history.</param> public SoundNStreamDataBlock(ref BinaryDataReader br, b_stm.InfoBlock info) { //Read magic. br.ReadUInt32s(2); br.Position += info.streamSoundInfo.sampleDataOffset.offset; //Read the channels. switch (info.streamSoundInfo.encoding) { //PCM8. case EncodingTypes.PCM8: //New data array. pcm8 = new sbyte[info.channels.Count()][]; //Read channel blocks. List <sbyte>[] channelData = new List <sbyte> [info.channels.Count()]; for (int j = 0; j < info.channels.Count; j++) { channelData[j] = new List <sbyte>(); } for (int i = 0; i < info.streamSoundInfo.blockCount - 1; i++) { //Read data. for (int j = 0; j < info.channels.Count; j++) { channelData[j].AddRange(br.ReadSBytes((int)info.streamSoundInfo.oneBlockBytesize)); } } //Read last block. for (int j = 0; j < info.channels.Count; j++) { channelData[j].AddRange(br.ReadSBytes((int)info.streamSoundInfo.lastBlockBytesize)); br.ReadBytes((int)(info.streamSoundInfo.lastBlockPaddedBytesize - info.streamSoundInfo.lastBlockBytesize)); } //Convert data. for (int j = 0; j < info.channels.Count; j++) { pcm8[j] = channelData[j].ToArray(); } break; //PCM16. case EncodingTypes.PCM16: //New data array. pcm16 = new Int16[info.channels.Count()][]; //Read channel blocks. List <Int16>[] channelData2 = new List <Int16> [info.channels.Count()]; for (int j = 0; j < info.channels.Count; j++) { channelData2[j] = new List <Int16>(); } for (int i = 0; i < info.streamSoundInfo.blockCount - 1; i++) { //Read data. for (int j = 0; j < info.channels.Count; j++) { channelData2[j].AddRange(br.ReadInt16s((int)info.streamSoundInfo.oneBlockSamples)); } } //Read last block. for (int j = 0; j < info.channels.Count; j++) { channelData2[j].AddRange(br.ReadInt16s((int)info.streamSoundInfo.lastBlockSamples)); br.ReadBytes((int)(info.streamSoundInfo.lastBlockPaddedBytesize - info.streamSoundInfo.lastBlockBytesize)); } //Convert data. for (int j = 0; j < info.channels.Count; j++) { pcm16[j] = channelData2[j].ToArray(); } break; //DSP-ADPCM. case EncodingTypes.DSP_ADPCM: //New data array. dspAdpcm = new byte[info.channels.Count()][]; //Read channel blocks. List <byte>[] channelData3 = new List <byte> [info.channels.Count()]; for (int j = 0; j < info.channels.Count; j++) { channelData3[j] = new List <byte>(); } for (int i = 0; i < info.streamSoundInfo.blockCount - 1; i++) { //Read data. for (int j = 0; j < info.channels.Count; j++) { channelData3[j].AddRange(br.ReadBytes((int)info.streamSoundInfo.oneBlockBytesize)); } } //Read last block. for (int j = 0; j < info.channels.Count; j++) { channelData3[j].AddRange(br.ReadBytes((int)info.streamSoundInfo.lastBlockBytesize)); br.ReadBytes((int)(info.streamSoundInfo.lastBlockPaddedBytesize - info.streamSoundInfo.lastBlockBytesize)); } //Convert data. for (int j = 0; j < info.channels.Count; j++) { dspAdpcm[j] = channelData3[j].ToArray(); } break; } }
/// <summary> /// Write for BFSTM. /// </summary> /// <param name="bw">The writer.</param> /// <param name="wavInfo"></param> public void WriteSTM(ref BinaryDataWriter bw, b_stm.InfoBlock wavInfo, UInt32 numSamples) { bw.Write("DATA".ToCharArray()); bw.Write(GetSize(wavInfo.streamSoundInfo.encoding, ref wavInfo)); bw.Write(new byte[0x18]); //Update data. wavInfo.streamSoundInfo.oneBlockBytesize = 0x2000; switch (wavInfo.streamSoundInfo.encoding) { //PCM8. case EncodingTypes.PCM8: wavInfo.streamSoundInfo.oneBlockSamples = wavInfo.streamSoundInfo.seekInfoIntervalSamples = 0x2000; wavInfo.streamSoundInfo.lastBlockSamples = (uint)pcm8[0].Length % 0x2000; wavInfo.streamSoundInfo.lastBlockBytesize = wavInfo.streamSoundInfo.lastBlockPaddedBytesize = (uint)pcm8[0].Length % 0x2000; while (wavInfo.streamSoundInfo.lastBlockPaddedBytesize % 0x20 != 0) { wavInfo.streamSoundInfo.lastBlockPaddedBytesize++; } wavInfo.streamSoundInfo.blockCount = (uint)pcm8[0].Length / 0x2000 + 1; break; //PCM16. case EncodingTypes.PCM16: wavInfo.streamSoundInfo.oneBlockSamples = wavInfo.streamSoundInfo.seekInfoIntervalSamples = 0x1000; wavInfo.streamSoundInfo.lastBlockSamples = (uint)pcm16[0].Length % 0x1000; wavInfo.streamSoundInfo.lastBlockBytesize = wavInfo.streamSoundInfo.lastBlockPaddedBytesize = (uint)pcm16[0].Length % 0x2000; while (wavInfo.streamSoundInfo.lastBlockPaddedBytesize % 0x20 != 0) { wavInfo.streamSoundInfo.lastBlockPaddedBytesize++; } wavInfo.streamSoundInfo.blockCount = (uint)pcm16[0].Length / 0x1000 + 1; break; //DSP-ADPCM. case EncodingTypes.DSP_ADPCM: wavInfo.streamSoundInfo.oneBlockSamples = wavInfo.streamSoundInfo.seekInfoIntervalSamples = 0x3800; wavInfo.streamSoundInfo.lastBlockSamples = (uint)numSamples % 0x3800; wavInfo.streamSoundInfo.lastBlockBytesize = wavInfo.streamSoundInfo.lastBlockPaddedBytesize = (uint)dspAdpcm[0].Length % 0x2000; while (wavInfo.streamSoundInfo.lastBlockPaddedBytesize % 0x20 != 0) { wavInfo.streamSoundInfo.lastBlockPaddedBytesize++; } wavInfo.streamSoundInfo.blockCount = (uint)dspAdpcm[0].Length / 0x2000 + 1; wavInfo.streamSoundInfo.sampleCount = numSamples; break; } //Chunk the data first. List <byte>[][] dspAdpcmBlocks = new List <byte> [wavInfo.channels.Count()][]; List <Int16>[][] pcm16Blocks = new List <Int16> [wavInfo.channels.Count()][]; List <sbyte>[][] pcm8Blocks = new List <sbyte> [wavInfo.channels.Count()][]; for (int c = 0; c < wavInfo.channels.Count(); c++) { dspAdpcmBlocks[c] = new List <byte> [(int)wavInfo.streamSoundInfo.blockCount]; pcm16Blocks[c] = new List <Int16> [(int)wavInfo.streamSoundInfo.blockCount]; pcm8Blocks[c] = new List <sbyte> [(int)wavInfo.streamSoundInfo.blockCount]; for (int i = 0; i < wavInfo.streamSoundInfo.blockCount; i++) { pcm8Blocks[c][i] = new List <sbyte>(); pcm16Blocks[c][i] = new List <short>(); dspAdpcmBlocks[c][i] = new List <byte>(); //Normal block. if (i != wavInfo.streamSoundInfo.blockCount - 1) { //Add to block. switch (wavInfo.streamSoundInfo.encoding) { //PCM8. case EncodingTypes.PCM8: for (int j = i * 0x2000; j < i * 0x2000 + 0x2000; j++) { pcm8Blocks[c][i].Add(pcm8[c][j]); } break; //PCM16. case EncodingTypes.PCM16: for (int j = i * 0x1000; j < i * 0x1000 + 0x1000; j++) { pcm16Blocks[c][i].Add(pcm16[c][j]); } break; //DSP-ADPCM. case EncodingTypes.DSP_ADPCM: for (int j = i * 0x2000; j < i * 0x2000 + 0x2000; j++) { dspAdpcmBlocks[c][i].Add(dspAdpcm[c][j]); } break; } } //Last block. else { //Add to block. switch (wavInfo.streamSoundInfo.encoding) { //PCM8. case EncodingTypes.PCM8: for (int j = i * 0x2000; j < pcm8[0].Length; j++) { pcm8Blocks[c][i].Add(pcm8[c][j]); } break; //PCM16. case EncodingTypes.PCM16: for (int j = i * 0x1000; j < pcm16[0].Length; j++) { pcm16Blocks[c][i].Add(pcm16[c][j]); } break; //DSP-ADPCM. case EncodingTypes.DSP_ADPCM: for (int j = i * 0x2000; j < dspAdpcm[0].Length; j++) { dspAdpcmBlocks[c][i].Add(dspAdpcm[c][j]); } break; } } } } //Write each block. for (int b = 0; b < wavInfo.streamSoundInfo.blockCount; b++) { //Write each channel. for (int c = 0; c < wavInfo.channels.Count(); c++) { switch (wavInfo.streamSoundInfo.encoding) { //PCM8. case EncodingTypes.PCM8: foreach (sbyte s in pcm8Blocks[c][b].ToArray()) { bw.Write(s); } break; //PCM16. case EncodingTypes.PCM16: bw.Write(pcm16Blocks[c][b]); break; //DSP-ADPCM. case EncodingTypes.DSP_ADPCM: bw.Write(dspAdpcmBlocks[c][b].ToArray()); break; } //Write padding if last block. if (b == wavInfo.streamSoundInfo.blockCount - 1) { while (bw.Position % 0x20 != 0) { bw.Write((byte)0); } } } } }
/// <summary> /// Load a file. /// </summary> /// <param name="b">The blue component.</param> public void Load(byte[] b) { //The reader. MemoryStream src = new MemoryStream(b); BinaryDataReader br = new BinaryDataReader(src); //Read the header. fileHeader = new FileHeader(ref br); //Read blocks. foreach (SizedReference s in fileHeader.blockOffsets) { if (s.offset != Reference.NULL_PTR) { br.Position = s.offset; switch (s.typeId) { //Info block. case ReferenceTypes.STRM_Block_Info: long basePos = br.Position + 8; info = new InfoBlock() { magic = br.ReadChars(4), blockSize = br.ReadUInt32(), streamSoundInfoRef = new Reference(ref br), trackInfoTableRef = new Reference(ref br), channelInfoTableRef = new Reference(ref br), streamSoundInfo = null, trackInfoRefTable = null, channelInfoRefTable = null, tracks = null, channels = null }; //Stream sound info. if (info.streamSoundInfoRef.typeId == ReferenceTypes.STRM_Info_StreamSound && info.streamSoundInfoRef.offset != Reference.NULL_PTR) { br.Position = basePos + info.streamSoundInfoRef.offset; info.streamSoundInfo = new StreamSoundInfo() { encoding = br.ReadByte(), isLoop = br.ReadBoolean(), channelCount = br.ReadByte(), regionCount = br.ReadByte(), sampleRate = br.ReadUInt32(), loopStart = br.ReadUInt32(), sampleCount = br.ReadUInt32(), blockCount = br.ReadUInt32(), oneBlockBytesize = br.ReadUInt32(), oneBlockSamples = br.ReadUInt32(), lastBlockBytesize = br.ReadUInt32(), lastBlockSamples = br.ReadUInt32(), lastBlockPaddedBytesize = br.ReadUInt32(), sizeOfSeekInfo = br.ReadUInt32(), seekInfoIntervalSamples = br.ReadUInt32(), sampleDataOffset = new Reference(ref br), regionInfoBytesize = 0x100, padding = 0, regionDataOffset = new Reference(0, 0x18), originalLoopStart = 0, originalLoopEnd = 0, secretInfo = 0 }; if (fileHeader.vMajor >= regionInfo) { info.streamSoundInfo.regionInfoBytesize = br.ReadUInt16(); info.streamSoundInfo.padding = br.ReadUInt16(); info.streamSoundInfo.regionDataOffset = new Reference(ref br); } if (fileHeader.vMajor >= originalLoopInfo) { info.streamSoundInfo.originalLoopStart = br.ReadUInt32(); info.streamSoundInfo.originalLoopEnd = br.ReadUInt32(); } if (fileHeader.vMajor >= secretInfo) { info.streamSoundInfo.secretInfo = br.ReadUInt32(); } } //Track info. if (info.trackInfoTableRef.typeId == ReferenceTypes.Tables + 1 && info.trackInfoTableRef.offset != Reference.NULL_PTR) { br.Position = basePos + info.trackInfoTableRef.offset; long newPos = br.Position; info.trackInfoRefTable = new ReferenceTable(ref br); //Get tracks. info.tracks = new List <TrackInfo>(); foreach (Reference r in info.trackInfoRefTable.references) { TrackInfo t = null; if (r.typeId == ReferenceTypes.STRM_Info_Track && r.offset != Reference.NULL_PTR) { br.Position = newPos + r.offset; t = new TrackInfo() { volume = br.ReadByte(), pan = br.ReadByte(), span = br.ReadByte(), surroundMode = br.ReadByte(), globalChannelIndexTableRef = new Reference(ref br), globalChannelIndexTable = null }; if (t.globalChannelIndexTableRef.offset != Reference.NULL_PTR) { br.Position = newPos + r.offset + t.globalChannelIndexTableRef.offset; t.globalChannelIndexTable = new Table <byte>(); t.globalChannelIndexTable.count = br.ReadUInt32(); t.globalChannelIndexTable.entries = new List <byte>(); for (int i = 0; i < t.globalChannelIndexTable.count; i++) { t.globalChannelIndexTable.entries.Add(br.ReadByte()); } } } info.tracks.Add(t); } } //Channel info. if (info.channelInfoTableRef.typeId == ReferenceTypes.Tables + 1 && info.channelInfoTableRef.offset != Reference.NULL_PTR) { br.Position = basePos + info.channelInfoTableRef.offset; long newPos = br.Position; info.channelInfoRefTable = new ReferenceTable(ref br); //Get channels. info.channels = new List <ChannelInfo>(); foreach (Reference r in info.channelInfoRefTable.references) { ChannelInfo c = null; if (r.offset != Reference.NULL_PTR) { br.Position = newPos + r.offset; c = new ChannelInfo() { dspAdpcmInfoRef = new Reference(ref br), dspAdpcmInfo = null }; if (c.dspAdpcmInfoRef.offset != Reference.NULL_PTR) { br.Position = newPos + r.offset + c.dspAdpcmInfoRef.offset; c.dspAdpcmInfo = new DspAdpcmInfo(); c.dspAdpcmInfo = new DspAdpcmInfo() { coefs = new short[8][] }; c.dspAdpcmInfo.coefs[0] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[1] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[2] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[3] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[4] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[5] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[6] = br.ReadInt16s(2); c.dspAdpcmInfo.coefs[7] = br.ReadInt16s(2); c.dspAdpcmInfo.pred_scale = br.ReadUInt16(); c.dspAdpcmInfo.yn1 = br.ReadInt16(); c.dspAdpcmInfo.yn2 = br.ReadInt16(); c.dspAdpcmInfo.loop_pred_scale = br.ReadUInt16(); c.dspAdpcmInfo.loop_yn1 = br.ReadInt16(); c.dspAdpcmInfo.loop_yn2 = br.ReadInt16(); } } info.channels.Add(c); } } break; //Data block. case ReferenceTypes.STRM_Block_PrefetchData: pdat = new PdatBlock(); pdat.magic = br.ReadChars(4); pdat.size = br.ReadUInt32(); break; } } } }