/// <summary> /// Melee's sound format /// </summary> /// <param name="filePath"></param> private void OpenSSM(string filePath) { using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; var headerLength = r.ReadInt32() + 0x10; var dataOff = r.ReadInt32(); var soundCount = r.ReadInt32(); Unknown = r.ReadInt32(); for (int i = 0; i < soundCount; i++) { var sound = new DSP(); sound.Index = i; var ChannelCount = r.ReadInt32(); sound.Frequency = r.ReadInt32(); sound.Channels.Clear(); for (int j = 0; j < ChannelCount; j++) { var channel = new DSPChannel(); channel.LoopFlag = r.ReadInt16(); channel.Format = r.ReadInt16(); var LoopStartOffset = r.ReadInt32(); var LoopEndOffset = r.ReadInt32(); var CurrentAddress = r.ReadInt32(); for (int k = 0; k < 0x10; k++) { channel.COEF[k] = r.ReadInt16(); } channel.Gain = r.ReadInt16(); channel.InitialPredictorScale = r.ReadInt16(); channel.InitialSampleHistory1 = r.ReadInt16(); channel.InitialSampleHistory2 = r.ReadInt16(); channel.LoopPredictorScale = r.ReadInt16(); channel.LoopSampleHistory1 = r.ReadInt16(); channel.LoopSampleHistory2 = r.ReadInt16(); r.ReadInt16(); // padding channel.NibbleCount = LoopEndOffset - CurrentAddress; channel.LoopStart = LoopStartOffset - CurrentAddress; sound.Channels.Add(channel); var DataOffset = headerLength + (int)Math.Ceiling(CurrentAddress / 2d) - 1; channel.Data = r.GetSection((uint)DataOffset, (int)Math.Ceiling(channel.NibbleCount / 2d) + 1); } Sounds.Add(sound); } } }
private DSP ImportDSP(string filePath) { using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; var dsp = new DSP(); r.ReadInt32(); var nibbleCount = r.ReadInt32(); dsp.Frequency = r.ReadInt32(); var channel = new DSPChannel(); channel.LoopFlag = r.ReadInt16(); channel.Format = r.ReadInt16(); var LoopStartOffset = r.ReadInt32(); var LoopEndOffset = r.ReadInt32(); var CurrentAddress = r.ReadInt32(); for (int k = 0; k < 0x10; k++) { channel.COEF[k] = r.ReadInt16(); } channel.Gain = r.ReadInt16(); channel.InitialPredictorScale = r.ReadInt16(); channel.InitialSampleHistory1 = r.ReadInt16(); channel.InitialSampleHistory2 = r.ReadInt16(); channel.LoopPredictorScale = r.ReadInt16(); channel.LoopSampleHistory1 = r.ReadInt16(); channel.LoopSampleHistory2 = r.ReadInt16(); r.ReadInt16(); // padding r.Seek(0x60); channel.NibbleCount = nibbleCount; channel.LoopStart = LoopStartOffset - CurrentAddress; channel.Data = r.ReadBytes((int)Math.Ceiling(nibbleCount / 2d)); dsp.Channels.Add(channel); r.BaseStream.Close(); return(dsp); } }
private void SaveChannelAsDSP(string filePath, DSPChannel channel, int frequency) { using (BinaryWriterExt w = new BinaryWriterExt(new FileStream(filePath, FileMode.Create))) { w.BigEndian = true; var samples = channel.NibbleCount * 7 / 8; w.Write(samples); w.Write(channel.NibbleCount); w.Write(frequency); w.Write(channel.LoopFlag); w.Write(channel.Format); w.Write(2); w.Write(channel.NibbleCount - 2); w.Write(2); foreach (var v in channel.COEF) { w.Write(v); } w.Write(channel.Gain); w.Write(channel.InitialPredictorScale); w.Write(channel.InitialSampleHistory1); w.Write(channel.InitialSampleHistory2); w.Write(channel.LoopPredictorScale); w.Write(channel.LoopSampleHistory1); w.Write(channel.LoopSampleHistory2); w.Write((short)0); w.Write(new byte[0x14]); w.Write(channel.Data); if (w.BaseStream.Position % 0x8 != 0) { w.Write(new byte[0x08 - w.BaseStream.Position % 0x08]); } w.BaseStream.Close(); } }
public void FromHPS(byte[] data) { using (BinaryReaderExt r = new BinaryReaderExt(new MemoryStream(data))) { r.BigEndian = true; if (new string(r.ReadChars(7)) != " HALPST") { throw new NotSupportedException("Invalid HPS file"); } r.ReadByte(); Frequency = r.ReadInt32(); var channelCount = r.ReadInt32(); if (channelCount != 2) { throw new NotSupportedException("Only HPS with 2 channels are currently supported"); } for (int i = 0; i < channelCount; i++) { var channel = new DSPChannel(); channel.LoopFlag = r.ReadInt16(); channel.Format = r.ReadInt16(); var SA = r.ReadInt32(); var EA = r.ReadInt32(); var CA = r.ReadInt32(); for (int k = 0; k < 0x10; k++) { channel.COEF[k] = r.ReadInt16(); } channel.Gain = r.ReadInt16(); channel.InitialPredictorScale = r.ReadInt16(); channel.InitialSampleHistory1 = r.ReadInt16(); channel.InitialSampleHistory1 = r.ReadInt16(); channel.NibbleCount = EA - CA; channel.LoopStart = SA - CA; Channels.Add(channel); } // read blocks r.Position = 0x80; Dictionary <int, int> OffsetToLoopPosition = new Dictionary <int, int>(); List <byte> channelData1 = new List <byte>(); List <byte> channelData2 = new List <byte>(); while (true) { var pos = r.Position; var length = r.ReadInt32(); var lengthMinusOne = r.ReadInt32(); var next = r.ReadInt32(); { var initPS = r.ReadInt16(); var initsh1 = r.ReadInt16(); var initsh2 = r.ReadInt16(); r.ReadInt16(); } { var initPS = r.ReadInt16(); var initsh1 = r.ReadInt16(); var initsh2 = r.ReadInt16(); r.ReadInt16(); } r.ReadInt32(); OffsetToLoopPosition.Add((int)pos, channelData1.Count * 2); channelData1.AddRange(r.ReadBytes(length / 2)); channelData2.AddRange(r.ReadBytes(length / 2)); if (next < r.Position || next == -1) { if (next != -1) { foreach (var c in Channels) { c.LoopStart = OffsetToLoopPosition[next]; } } break; } else { r.Position = (uint)next; } } Channels[0].Data = channelData1.ToArray(); Channels[1].Data = channelData2.ToArray(); } }
/*public void ToHPS() * { * * }*/ public void FromWAVE(byte[] wavFile) { if (wavFile.Length < 0x2C) { throw new NotSupportedException("File is not a valid WAVE file"); } using (BinaryReader r = new BinaryReader(new MemoryStream(wavFile))) { if (new string(r.ReadChars(4)) != "RIFF") { throw new NotSupportedException("File is not a valid WAVE file"); } r.BaseStream.Position = 0x14; var comp = r.ReadInt16(); var channelCount = r.ReadInt16(); Frequency = r.ReadInt32(); r.ReadInt32(); // block rate r.ReadInt16(); // block align var bpp = r.ReadInt16(); if (comp != 1) { throw new NotSupportedException("Compressed WAVE files not supported"); } if (bpp != 16) { throw new NotSupportedException("Only 16 bit WAVE formats accepted"); } r.BaseStream.Position = 0x28; var channelSizes = r.ReadInt32() / channelCount / 2; List <List <short> > channels = new List <List <short> >(); for (int i = 0; i < channelCount; i++) { channels.Add(new List <short>()); } foreach (var v in channels) { for (int i = 0; i < channelSizes; i++) { v.Add(r.ReadInt16()); } } Channels.Clear(); foreach (var data in channels) { var c = new DSPChannel(); var ss = data.ToArray(); c.COEF = GcAdpcmCoefficients.CalculateCoefficients(ss); c.Data = GcAdpcmEncoder.Encode(ss, c.COEF); c.NibbleCount = c.Data.Length * 2; c.InitialPredictorScale = c.Data[0]; Channels.Add(c); } } }
/// <summary> /// Used in Eighting Engine Games /// </summary> /// <param name="filePath"></param> private void OpenSDI(string filePath) { var sam = filePath.Replace(".sdi", ".sam"); if (!File.Exists(sam)) { return; } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) using (BinaryReaderExt d = new BinaryReaderExt(new FileStream(sam, FileMode.Open))) { r.BigEndian = true; while (true) { var id = r.ReadInt32(); if (id == -1) { break; } var dataoffset = r.ReadUInt32(); var padding = r.ReadInt32(); var flags = r.ReadInt16(); var frequency = r.ReadInt16(); var value = r.ReadInt32(); r.Skip(8); // unknown uint coefOffset = r.ReadUInt32(); DSP dsp = new DSP(); dsp.Frequency = frequency; DSPChannel channel = new DSPChannel(); channel.NibbleCount = value; var temp = r.Position; var end = (uint)d.Length; if (r.ReadInt32() != -1) { end = r.ReadUInt32(); } r.Seek(coefOffset); r.ReadInt32(); r.ReadInt32(); for (int i = 0; i < 0x10; i++) { channel.COEF[i] = r.ReadInt16(); } r.Seek(temp); d.Seek(dataoffset); byte[] data = d.ReadBytes((int)(end - dataoffset)); channel.Data = data; channel.InitialPredictorScale = data[0]; dsp.Channels.Add(channel); Sounds.Add(dsp); } } }