public static void CreateSRS(SortedList <int, TrackData> tracks, FileData file, FileInfo inFile, FileInfo srsFile, bool bigFile) { using (FileStream fsOut = srsFile.Create()) using (RiffReader rdr = new RiffReader(inFile.FullName, RiffReadMode.AVI)) { while (rdr.Read()) { fsOut.Write(rdr.Chunk.RawHeader, 0, rdr.Chunk.RawHeader.Length); if (rdr.ChunkType == RiffChunkType.List) { // in store mode, create and write our custom chunks as the first child of LIST movi // we put them after the avi headers so mediainfo can still read them from the SRS if (rdr.List.ListType == "LIST" && rdr.List.FourCC == "movi") { byte[] fileChunk = file.SerializeAsRiff(); fsOut.Write(fileChunk, 0, fileChunk.Length); if (fileChunk.Length % 2 == 1) { fsOut.WriteByte(0); } foreach (TrackData track in tracks.Values) { if (bigFile) { track.Flags |= TrackData.TrackDataFlags.BigFile; } byte[] trackChunk = track.SerializeAsRiff(); fsOut.Write(trackChunk, 0, trackChunk.Length); if (trackChunk.Length % 2 == 1) { fsOut.WriteByte(0); } } } rdr.MoveToChild(); } else { if (rdr.ChunkType == RiffChunkType.Movi) { rdr.SkipContents(); // don't copy stream data } else { fsOut.Write(rdr.ReadContents(), 0, (int)rdr.Chunk.Length); // do copy everything else } if (rdr.HasPad) { fsOut.WriteByte(rdr.PadByte); } } } } }
public static DlsCollection Read(Stream stream) { using (var reader = new RiffReader(stream)) { var collectionVersion = default(Version); var instruments = new List <DlsInstrument>(); var wavePool = new List <DlsWaveFile>(); var info = new DlsInfo(); var id = default(Guid?); foreach (var dlsSubchunk in reader.ReadRiff("DLS ").ReadList()) { switch (dlsSubchunk.Name) { case "vers": var minor = dlsSubchunk.ReadUInt16(); var major = dlsSubchunk.ReadUInt16(); var revision = dlsSubchunk.ReadUInt16(); var build = dlsSubchunk.ReadUInt16(); collectionVersion = new Version(major, minor, build, revision); break; case "dlid": id = ReadDlsId(dlsSubchunk); break; case "lins": instruments.AddRange( from lrgnSubchunk in dlsSubchunk.ReadList() where lrgnSubchunk.Name == "ins " let instrument = ReadDlsInstrument(lrgnSubchunk) where instrument != null select instrument.Value); break; case "wvpl": wavePool.AddRange( from wvplSubchunk in dlsSubchunk.ReadList() where wvplSubchunk.Name == "wave" let waveFile = ReadDlsWaveFile(wvplSubchunk) where waveFile != null select waveFile.Value); break; case "INFO": info = ReadDlsInfo(dlsSubchunk); break; } } return(new DlsCollection(id, collectionVersion, info, instruments, wavePool)); } }
/// <summary> /// Read the RIFF. /// </summary> /// <param name="r">The reader.</param> public override void Read(FileReader r) { //Init. using (RiffReader rr = new RiffReader(r.BaseStream)) { //Format. rr.OpenChunk(rr.Chunks.Where(x => x.Magic.Equals("fmt ")).FirstOrDefault()); if (rr.ReadUInt16() != 1) { throw new Exception("Unexpected standard WAV data format."); } int numChannels = rr.ReadUInt16(); SampleRate = rr.ReadUInt32(); rr.ReadUInt32(); //Byte rate. rr.ReadUInt16(); //Blocks. ushort bitsPerSample = rr.ReadUInt16(); LoopStart = 0; LoopEnd = 0; Loops = false; if (bitsPerSample != 8 && bitsPerSample != 16) { throw new Exception("This tool only accepts 8-bit or 16-bit WAV files."); } //Sample. var smpl = rr.Chunks.Where(x => x.Magic.Equals("smpl")).FirstOrDefault(); if (smpl != null) { rr.OpenChunk(smpl); rr.ReadUInt32s(7); Loops = rr.ReadUInt32() > 0; if (Loops) { rr.ReadUInt32s(3); LoopStart = r.ReadUInt32(); //(uint)(r.ReadUInt32() / (bitsPerSample / 8)); LoopEnd = r.ReadUInt32(); //(uint)(r.ReadUInt32() / (bitsPerSample / 8)); } } //Data. rr.OpenChunk(rr.Chunks.Where(x => x.Magic.Equals("data")).FirstOrDefault()); uint dataSize = rr.Chunks.Where(x => x.Magic.Equals("data")).FirstOrDefault().Size; uint numBlocks = (uint)(dataSize / numChannels / (bitsPerSample / 8)); r.Position = rr.Position; Audio.Read(r, bitsPerSample == 16 ? typeof(PCM16) : typeof(PCM8), numChannels, numBlocks, (uint)bitsPerSample / 8, 1, (uint)bitsPerSample / 8, 1, 0); Audio.ChangeBlockSize(-1); } }
public override Buffer CreateResource(ResourceManager resourceManager) { var buffer = base.CreateResource(resourceManager); using (var reader = new BinaryReader(OpenResource(FileName))) { RiffHeader header; RiffReader.ReadHeader(reader, out header); var format = header.GetFormat(); var sampleData = new byte[header.DataLength]; var bytesRead = reader.Read(sampleData, 0, sampleData.Length); if (bytesRead < sampleData.Length) { throw new InvalidOperationException("Unable to read audio data. Sound WAV file may be corrupted or truncated."); } AL.BufferData(buffer.Id, format, sampleData, sampleData.Length, (int)header.SampleRate); } return(buffer); }
public static void LoadSRS(SortedList <int, TrackData> tracks, ref FileData file, FileInfo inFile) { using (RiffReader rdr = new RiffReader(inFile.FullName, RiffReadMode.SRS)) { bool done = false; while (!done && rdr.Read()) { if (rdr.ChunkType == RiffChunkType.List) { rdr.MoveToChild(); } else { if (rdr.Chunk.FourCC == "SRSF") // resample file { byte[] buff = rdr.ReadContents(); file = new FileData(buff); } else if (rdr.Chunk.FourCC == "SRST") // resample track { byte[] buff = rdr.ReadContents(); TrackData track = new TrackData(buff); tracks.Add(track.TrackNumber, track); } else if (rdr.ChunkType == RiffChunkType.Movi) { // if we get here in load mode, we have already got what we need, so bail out done = true; continue; } else { rdr.SkipContents(); } } } } }
private void bgWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { const int COPY_LEN = 50 * 1024; BackgroundWorker worker = sender as BackgroundWorker; string[] files = (string[])e.Argument; try { using (RiffReader rr = new RiffReader(files[0])) using (RiffWriter rw = new RiffWriter(files[1])) { // 読み取りファイル解析 bool b = rr.Parse(); if (!b) { e.Result = -2; return; } WaveFormatEx wf = rr.WaveFormat; // 拡張ヘッダーを無効化できる条件 if (wf.Channels <= 2 && wf.Extensible && wf.BitsPerSample != 32) { wf.Extensible = false; wf.FormatTag = WaveFormatTag.PCM; } // ヘッダーの書き出し b = rw.WriteHeader(wf); if (!b) { e.Result = -1; return; } // ループ回数を計算。進捗にも使う long max = rr.Length / COPY_LEN; if ((rr.Length % COPY_LEN) > 0) { max++; } for (long i = 0; i < max; i++) { byte[] arr = rr.Read8(COPY_LEN); if (!rw.WriteStream8(arr)) { e.Result = -1; return; } int percentage = (int)((i + 1) * 100 / max); worker.ReportProgress(percentage); } if (!rw.WriteFinalize()) { return; } } } catch { // エラー e.Result = -3; return; } e.Result = 0; }
public static FileData RebuildSample(FileData file, SortedList <int, TrackData> tracks, FileInfo srsFile, DirectoryInfo outDir) { uint crc = Crc32.StartValue; using (RiffReader rdr = new RiffReader(srsFile.FullName, RiffReadMode.SRS)) using (FileStream fsOut = new FileStream(Path.Combine(outDir.FullName, file.Name), FileMode.Create)) { int blockcount = 0; while (rdr.Read()) { // skip over our custom chunks in rebuild mode (only read it in load mode) if (rdr.Chunk.FourCC == "SRSF" || rdr.Chunk.FourCC == "SRST") { rdr.SkipContents(); continue; } fsOut.Write(rdr.Chunk.RawHeader, 0, rdr.Chunk.RawHeader.Length); crc = Crc32.GetCrc(crc, rdr.Chunk.RawHeader); if (rdr.ChunkType == RiffChunkType.List) { rdr.MoveToChild(); } else { if (rdr.ChunkType == RiffChunkType.Movi) { if (++blockcount % 15 == 0) { Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]); } TrackData track = tracks[rdr.MoviChunk.StreamNumber]; byte[] buff = new byte[rdr.MoviChunk.Length]; track.TrackFile.Read(buff, 0, buff.Length); fsOut.Write(buff, 0, buff.Length); crc = Crc32.GetCrc(crc, buff); rdr.SkipContents(); } else { byte[] buff = rdr.ReadContents(); fsOut.Write(buff, 0, buff.Length); crc = Crc32.GetCrc(crc, buff); } if (rdr.HasPad) { fsOut.WriteByte(rdr.PadByte); crc = Crc32.GetCrc(crc, new byte[] { rdr.PadByte }); } } } } Console.Write('\b'); FileData newFile = new FileData(Path.Combine(outDir.FullName, file.Name)); newFile.Crc32 = ~crc; return(newFile); }
public static void ExtractSampleStreams(SortedList <int, TrackData> tracks, FileData file, FileInfo inFile, DirectoryInfo outDir) { Stream fs; if (RarFileNameComparer.IsRarFile(inFile.Name)) { fs = new RarStream(inFile.FullName); } else { fs = inFile.OpenRead(); } using (RiffReader rdr = new RiffReader(fs, RiffReadMode.AVI)) { long startOffset = long.MaxValue; foreach (TrackData track in tracks.Values) { if (track.MatchOffset > 0) { startOffset = Math.Min(track.MatchOffset, startOffset); } } int blockcount = 0; bool done = false; while (rdr.Read() && !done) { if (rdr.ChunkType == RiffChunkType.List) { rdr.MoveToChild(); } else // normal chunk { if (rdr.ChunkType == RiffChunkType.Movi) { if (++blockcount % 15 == 0) { Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]); } if (!tracks.ContainsKey(rdr.MoviChunk.StreamNumber)) { tracks.Add(rdr.MoviChunk.StreamNumber, new TrackData()); } TrackData track = tracks[rdr.MoviChunk.StreamNumber]; if (rdr.MoviChunk.ChunkStartPos + rdr.MoviChunk.RawHeader.Length + rdr.MoviChunk.Length > track.MatchOffset) { if (track.TrackFile == null) { track.TrackFile = new FileStream(Path.Combine(outDir.FullName, inFile.Name + "." + track.TrackNumber.ToString("d3")), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 0x10000, FileOptions.DeleteOnClose); } if (track.TrackFile.Position < track.DataLength) { if (rdr.MoviChunk.ChunkStartPos + rdr.MoviChunk.RawHeader.Length >= track.MatchOffset) { track.TrackFile.Write(rdr.ReadContents(), 0, (int)rdr.MoviChunk.Length); } else { int chunkOffset = (int)(track.MatchOffset - (rdr.MoviChunk.ChunkStartPos + rdr.MoviChunk.RawHeader.Length)); track.TrackFile.Write(rdr.ReadContents(), chunkOffset, (int)rdr.MoviChunk.Length - chunkOffset); } } bool tracksDone = true; foreach (TrackData t in tracks.Values) { if (t.TrackFile == null || t.TrackFile.Length < t.DataLength) { tracksDone = false; break; } } done = tracksDone; } rdr.SkipContents(); } else { rdr.SkipContents(); } } } } Console.Write('\b'); }
public static void FindSampleStreams(SortedList <int, TrackData> tracks, FileInfo inFile) { Stream fs; if (RarFileNameComparer.IsRarFile(inFile.Name)) { fs = new RarStream(inFile.FullName); } else { fs = inFile.OpenRead(); } using (RiffReader rdr = new RiffReader(fs, RiffReadMode.AVI)) { int blockcount = 0; bool done = false; while (rdr.Read() && !done) { if (rdr.ChunkType == RiffChunkType.List) { rdr.MoveToChild(); } else // normal chunk { if (rdr.ChunkType == RiffChunkType.Movi) { if (++blockcount % 15 == 0) { Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]); } int trackno = rdr.MoviChunk.StreamNumber; if (!tracks.ContainsKey(trackno)) { tracks.Add(trackno, new TrackData()); } TrackData track = tracks[trackno]; track.TrackNumber = (byte)trackno; if (track.MatchOffset == 0 || track.CheckBytes.Length < track.SignatureBytes.Length) { // it's possible the sample didn't require or contain data for all tracks in the main file // if that happens, we obviously don't want to try to match the data if (track.SignatureBytes != null) { if (track.CheckBytes != null && track.CheckBytes.Length < track.SignatureBytes.Length) { byte[] checkBytes = new byte[Math.Min(track.SignatureBytes.Length, rdr.MoviChunk.Length + track.CheckBytes.Length)]; track.CheckBytes.CopyTo(checkBytes, 0); Buffer.BlockCopy(rdr.ReadContents(), 0, checkBytes, track.CheckBytes.Length, checkBytes.Length - track.CheckBytes.Length); if (ByteArrayComparer.AreEqual(track.SignatureBytes, checkBytes, checkBytes.Length)) { track.CheckBytes = checkBytes; } else { // it was only a partial match. start over track.CheckBytes = null; track.MatchOffset = 0; track.MatchLength = 0; } } // this is a bit weird, but if we had a false positive match going and discovered it above, we check this frame again // to see if it's the start of a new match (probably will never happen with AVI, but it does in MKV, so just in case...) if (track.CheckBytes == null) { byte[] chunkBytes = rdr.ReadContents(); byte searchByte = track.SignatureBytes[0]; int foundPos = -1; while ((foundPos = Array.IndexOf <byte>(chunkBytes, searchByte, foundPos + 1)) > -1) { byte[] checkBytes = new byte[Math.Min(track.SignatureBytes.Length, chunkBytes.Length - foundPos)]; Buffer.BlockCopy(chunkBytes, foundPos, checkBytes, 0, checkBytes.Length); if (ByteArrayComparer.AreEqual(track.SignatureBytes, checkBytes, checkBytes.Length)) { track.CheckBytes = checkBytes; track.MatchOffset = rdr.Chunk.ChunkStartPos + rdr.Chunk.RawHeader.Length + foundPos; track.MatchLength = Math.Min(track.DataLength, chunkBytes.Length - foundPos); break; } } } else { track.MatchLength += Math.Min(track.DataLength - track.MatchLength, rdr.MoviChunk.Length); } } } else if (track.MatchLength < track.DataLength) { track.MatchLength += Math.Min(track.DataLength - track.MatchLength, rdr.MoviChunk.Length); bool tracksDone = true; foreach (TrackData t in tracks.Values) { if (t.MatchLength < t.DataLength) { tracksDone = false; break; } } done = tracksDone; } rdr.SkipContents(); } else { rdr.SkipContents(); } } } } Console.Write('\b'); }
public static int ProfileSample(FileData file, SortedList <int, TrackData> tracks) { long otherLength = 0; int blockcount = 0; file.Crc32 = Crc32.StartValue; using (RiffReader rdr = new RiffReader(file.Name, RiffReadMode.Sample)) { while (rdr.Read()) { otherLength += rdr.Chunk.RawHeader.Length; file.Crc32 = Crc32.GetCrc(file.Crc32, rdr.Chunk.RawHeader); if (rdr.ChunkType == RiffChunkType.List) { if (rdr.List.ListType == "RIFF" && rdr.List.ChunkStartPos + rdr.List.RawHeader.Length + rdr.List.Length > file.Size) { Program.ReportError(string.Format("\nWarning: File size does not appear to be correct!\n\t Expected at least: {0:n0}\n\t Found : {1:n0}\n", rdr.List.ChunkStartPos + rdr.List.RawHeader.Length + rdr.List.Length, file.Size)); } rdr.MoveToChild(); } else // normal chunk { if (rdr.ChunkType == RiffChunkType.Movi) // chunk containing stream data (our main focus) { if (++blockcount % 15 == 0) { Console.Write("\b{0}", Program.spinners[blockcount % Program.spinners.Length]); } int trackno = rdr.MoviChunk.StreamNumber; if (!tracks.ContainsKey(trackno)) { tracks.Add(trackno, new TrackData()); } TrackData track = tracks[trackno]; track.TrackNumber = (byte)trackno; track.DataLength += rdr.MoviChunk.Length; byte[] moviData = rdr.ReadContents(); file.Crc32 = Crc32.GetCrc(file.Crc32, moviData); // in profile mode, we want to build track signatures if (track.SignatureBytes == null || track.SignatureBytes.Length < Program.sigSize) { if (track.SignatureBytes != null) { byte[] sig = new byte[Math.Min(Program.sigSize, track.SignatureBytes.Length + rdr.MoviChunk.Length)]; track.SignatureBytes.CopyTo(sig, 0); Buffer.BlockCopy(moviData, 0, sig, track.SignatureBytes.Length, sig.Length - track.SignatureBytes.Length); track.SignatureBytes = sig; } else { track.SignatureBytes = new byte[Math.Min(Program.sigSize, rdr.MoviChunk.Length)]; Buffer.BlockCopy(moviData, 0, track.SignatureBytes, 0, track.SignatureBytes.Length); } } } else { otherLength += rdr.Chunk.Length; file.Crc32 = Crc32.GetCrc(file.Crc32, rdr.ReadContents()); } if (rdr.HasPad) { otherLength++; file.Crc32 = Crc32.GetCrc(file.Crc32, new byte[] { rdr.PadByte }); } } } } Console.Write('\b'); file.Crc32 = ~file.Crc32; long totalSize = otherLength; Console.WriteLine("File Details: Size CRC"); Console.WriteLine(" ------------- --------"); Console.WriteLine(" {0,13:n0} {1:X8}\n", file.Size, file.Crc32); Console.WriteLine(); Console.WriteLine("Stream Details: Stream Length"); Console.WriteLine(" ------ -------------"); foreach (TrackData track in tracks.Values) { Console.WriteLine(" {0,6:n0} {1,13:n0}", track.TrackNumber, track.DataLength); totalSize += track.DataLength; } Console.WriteLine(); Console.WriteLine("Parse Details: Metadata Stream Data Total"); Console.WriteLine(" ----------- ------------- -------------"); Console.WriteLine(" {0,11:n0} {1,13:n0} {2,13:n0}\n", otherLength, totalSize - otherLength, totalSize); if (file.Size != totalSize) { Program.ReportError("\nError: Parsed size does not equal file size.\n The sample is likely corrupted or incomplete.\n"); return(2); } return(0); }
private bool CheckFileType() { try { using (RiffReader f1 = new RiffReader(textBoxFile1.Text)) using (RiffReader f2 = new RiffReader(textBoxFile2.Text)) { bool b1 = f1.Parse(); bool b2 = f2.Parse(); if (b1 && b2) { if (f1.WaveFormat.Channels != f2.WaveFormat.Channels) { MessageBox.Show("チャンネル数が異なります。比較を中断します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(false); } else if (f1.WaveFormat.FormatTag != f2.WaveFormat.FormatTag) { MessageBox.Show("フォーマットが異なります。比較を中断します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(false); } else if (f1.WaveFormat.SamplesPerSecond != f2.WaveFormat.SamplesPerSecond) { MessageBox.Show("サンプリングレートが異なります。比較を中断します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(false); } else if (f1.WaveFormat.BitsPerSample != f2.WaveFormat.BitsPerSample) { MessageBox.Show("量子化ビット数が異なります。比較を中断します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(false); } else { m_Comp.type = CompType.Wavs; } } else if (!b1 && !b2) { MessageBox.Show("どちらもWAVファイルではありません。先頭からバイト単位で比較します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); m_Comp.type = CompType.Raws; } else { #if true m_Comp.type = CompType.Raws; if (b1) { MessageBox.Show("ファイル2はWAVファイルではありません。先頭からバイト単位で比較します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); m_Comp.rawFile = 1; } else { MessageBox.Show("ファイル1はWAVファイルではありません。先頭からバイト単位で比較します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); m_Comp.rawFile = 0; } #else m_Comp.type = CompType.RawWav; if (b1) { MessageBox.Show("ファイル2はWAVファイルではありません。Rawストリームとみなして比較します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); m_Comp.rawFile = 1; } else { MessageBox.Show("ファイル1はWAVファイルではありません。Rawストリームとみなして比較します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); m_Comp.rawFile = 0; } #endif } return(true); } } catch (Exception) { MessageBox.Show("ファイルがオープンできません。比較を中断します。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(false); } }
private int CompareWav(BackgroundWorker worker, string[] files, CompareInfo ci, DiffWriter sw) { CompareCore cc = new CompareCore(sw); cc.HexOut = ci.setting.hexOut; int ret = 0; try { using (RiffReader rr1 = new RiffReader(files[0])) using (RiffReader rr2 = new RiffReader(files[1])) { if (!rr1.Parse()) { return(-1); } if (!rr2.Parse()) { return(-1); } if (!ci.setting.streamOrigin) { cc.Offset = rr1.StreamOffset; } // 読み込み終端。単位に注意 long limit = 0; if (ci.setting.sampleOrder) { limit = (rr1.Samples > rr2.Samples) ? rr2.Samples : rr1.Samples; } else { limit = (rr1.Length > rr2.Length) ? rr2.Length : rr1.Length; } // 現在処理位置。単位に注意 long read = 0; int prevProgress = 0; int BLOCK_LENGTH = 2 * 1024 * 1024; while (read < limit) { int size = BLOCK_LENGTH; if (read + BLOCK_LENGTH > limit) { size = (int)(limit - read); } if (ci.setting.sampleOrder) { int q = rr1.WaveFormat.BitsPerSample / 8; // まとめて読んで比較 if (q == 1) { byte[] ba1 = rr1.Read8(size); byte[] ba2 = rr2.Read8(size); if (cc.CompareLoop(ba1, ba2, read)) { ret = 1; } } else if (q == 2) { short[] sa1 = rr1.Read16(size); short[] sa2 = rr2.Read16(size); if (cc.CompareLoop(sa1, sa2, read * q)) { ret = 1; } } else if (q == 3) { int[] sa1 = rr1.Read24(size); int[] sa2 = rr2.Read24(size); if (cc.CompareLoop(sa1, sa2, read * q, q)) { ret = 1; } } else if (q == 4) { if (rr1.WaveFormat.FormatTag == WaveFormatTag.IEEE_FLOAT) { float[] sa1 = rr1.Read32F(size); float[] sa2 = rr2.Read32F(size); if (cc.CompareLoop(sa1, sa2, read * q)) { ret = 1; } } else { int[] sa1 = rr1.Read32(size); int[] sa2 = rr2.Read32(size); if (cc.CompareLoop(sa1, sa2, read * q, q)) { ret = 1; } } } else { return(-1); } } else { // まとめて読んで比較 byte[] ba1 = rr1.Read8(size); byte[] ba2 = rr2.Read8(size); if (cc.CompareLoop(ba1, ba2, read)) { ret = 1; } } read += size; // 進捗を通知 int progress = (int)(read * 100 / limit); if (progress > prevProgress) { prevProgress = progress; worker.ReportProgress(progress); } } } } catch { return(-1); } if (sw != null && ret == 1) { if (cc.DiffType) { sw.PrintResult(cc.Count, cc.Max); } else { sw.PrintResult(cc.Count, cc.fMax); } } return(ret); }
public CprFileFormat(string filename) { using var reader = new RiffReader(filename); _content = reader.Read(); }
/// <summary> /// Read the file. /// </summary> /// <param name="r2">The file reader.</param> public override void Read(FileReader r2) { //Use a RIFF reader. using (RiffReader r = new RiffReader(r2.BaseStream)) { //Get the number of instruments. r.OpenChunk(r.GetChunk("colh")); uint numInsts = r.ReadUInt32(); //Pointer table is skipped since it's just offsets to wave data relative to the first wave identifier. //Read wave data. Waves = new List <RiffWave>(); foreach (var c in (r.GetChunk("wvpl") as ListChunk).Chunks) { //Open block. r.OpenChunk(c); //Set position for proper RIFF reading. r.BaseStream.Position -= 8; int len = r.ReadInt32() + 8; r.BaseStream.Position -= 8; RiffWave wav = new RiffWave(); wav.Read(r.ReadBytes(len)); Waves.Add(wav); } //Read each instrument. foreach (ListChunk c in (r.GetChunk("lins") as ListChunk).Chunks) { //Open block. r.OpenChunk(c); //New instrument. Instrument inst = new Instrument(); //Read header. r.OpenChunk(c.GetChunk("insh")); r.ReadUInt32(); inst.BankId = r.ReadUInt32(); inst.InstrumentId = r.ReadUInt32(); //Read regions. foreach (ListChunk g in (c.GetChunk("lrgn") as ListChunk).Chunks) { //New region. Region reg = new Region(); //Region header. r.OpenChunk(g.GetChunk("rgnh")); reg.NoteLow = r.ReadUInt16(); reg.NoteHigh = r.ReadUInt16(); reg.VelocityLow = r.ReadUInt16(); reg.VelocityHigh = r.ReadUInt16(); reg.DoublePlayback = r.ReadUInt16() > 0; reg.KeyGroup = (byte)r.ReadUInt16(); reg.Layer = r.ReadUInt16(); //Note information. r.OpenChunk(g.GetChunk("wsmp")); r.ReadUInt32(); reg.RootNote = (byte)r.ReadUInt16(); reg.Tuning = r.ReadInt16(); reg.Gain = r.ReadInt32(); uint flags = r.ReadUInt32(); reg.NoTruncation = (flags & 0b1) > 0; reg.NoCompression = (flags & 0b10) > 0; reg.Loops = r.ReadUInt32() > 0; if (reg.Loops) { r.ReadUInt32(); reg.LoopAndRelease = r.ReadUInt32() > 0; reg.LoopStart = r.ReadUInt32(); reg.LoopLength = r.ReadUInt32(); } //Wave link. r.OpenChunk(g.GetChunk("wlnk")); uint flg = r.ReadUInt16(); reg.PhaseMaster = (flg & 0b1) > 0; reg.MultiChannel = (flg & 0b10) > 0; reg.PhaseGroup = r.ReadUInt16(); reg.ChannelFlags = r.ReadUInt32(); reg.WaveId = r.ReadUInt32(); //Loop. Waves[(int)reg.WaveId].Loops = reg.Loops; if (reg.Loops) { Waves[(int)reg.WaveId].LoopStart = reg.LoopStart; Waves[(int)reg.WaveId].LoopEnd = reg.LoopLength == 0 ? (uint)Waves[(int)reg.WaveId].Audio.NumSamples : reg.LoopStart + reg.LoopLength; } //Articulators. var lar = g.GetChunk("lar2"); if (lar == null) { lar = g.GetChunk("lar1"); } foreach (Chunk art in (g.GetChunk("lar2") as ListChunk).Chunks) { //Read articulator. Articulator a = new Articulator(); r.OpenChunk(art); r.ReadUInt32(); uint numCons = r.ReadUInt32(); for (uint i = 0; i < numCons; i++) { Connection con = new Connection(); con.SourceConnection = (SourceConnection)r.ReadUInt16(); con.ControlConnection = r.ReadUInt16(); con.DestinationConnection = (DestinationConnection)r.ReadUInt16(); con.TransformConnection = (TransformConnection)r.ReadUInt16(); con.Scale = r.ReadInt32(); a.Connections.Add(con); } reg.Articulators.Add(a); } //Add region. inst.Regions.Add(reg); } //Read name. var info = c.GetChunk("INFO"); if (info != null) { var inam = (info as ListChunk).GetChunk("INAM"); if (inam != null) { r.OpenChunk(inam); r.BaseStream.Position -= 4; uint siz = r.ReadUInt32(); inst.Name = new string(r.ReadChars((int)siz).Where(x => x != 0).ToArray()); } } //Add instrument. Instruments.Add(inst); } } }
/// <summary> /// Read the file. /// </summary> /// <param name="r2">The reader.</param> public override void Read(FileReader r2) { //Use a RIFF reader. using (RiffReader r = new RiffReader(r2.BaseStream)) { //Get INFO data. var info = (ListChunk)r.GetChunk("INFO"); //Sound engine. r.OpenChunk(info.GetChunk("isng")); SoundEngine = r.ReadNullTerminated(); //Bank name. r.OpenChunk(info.GetChunk("INAM")); BankName = r.ReadNullTerminated(); //ROM name. if (info.GetChunk("irom") != null) { r.OpenChunk(info.GetChunk("irom")); RomName = r.ReadNullTerminated(); } //ROM version. if (info.GetChunk("iver") != null) { r.OpenChunk(info.GetChunk("iver")); RomVersion = new Tuple <ushort, ushort>(r.ReadUInt16(), r.ReadUInt16()); } //Creation date. if (info.GetChunk("ICRD") != null) { r.OpenChunk(info.GetChunk("ICRD")); CreationDate = r.ReadNullTerminated(); } //Sound designer. if (info.GetChunk("IENG") != null) { r.OpenChunk(info.GetChunk("IENG")); SoundDesigner = r.ReadNullTerminated(); } //Product. if (info.GetChunk("IPRD") != null) { r.OpenChunk(info.GetChunk("IPRD")); Product = r.ReadNullTerminated(); } //Copyright. if (info.GetChunk("ICOP") != null) { r.OpenChunk(info.GetChunk("ICOP")); Copyright = r.ReadNullTerminated(); } //Comment. if (info.GetChunk("ICMT") != null) { r.OpenChunk(info.GetChunk("ICMT")); Comment = r.ReadNullTerminated(); } //Tools. if (info.GetChunk("ISFT") != null) { r.OpenChunk(info.GetChunk("ISFT")); Tools = r.ReadNullTerminated(); } //Get wave table position. long waveTablePos = ((ListChunk)r.GetChunk("sdta")).GetChunk("smpl").Pos; //The hydra. Presets = new List <Preset>(); Instruments = new List <Instrument>(); Samples = new List <SampleItem>(); var hydra = (ListChunk)r.GetChunk("pdta"); //Get presets. r.OpenChunk(hydra.GetChunk("phdr")); uint numPresets = hydra.GetChunk("phdr").Size / 38 - 1; for (uint i = 0; i < numPresets; i++) { Presets.Add(r.Read <Preset>()); } //Get preset bags. List <Tuple <ushort, ushort> > presetGenModIndices = new List <Tuple <ushort, ushort> >(); List <Zone> presetZones = new List <Zone>(); r.OpenChunk(hydra.GetChunk("pbag")); uint numPbags = hydra.GetChunk("pbag").Size / 4 - 1; for (uint i = 0; i < numPbags; i++) { presetGenModIndices.Add(new Tuple <ushort, ushort>(r.ReadUInt16(), r.ReadUInt16())); presetZones.Add(new Zone()); } //Get preset modulators. List <Modulator> pMods = new List <Modulator>(); r.OpenChunk(hydra.GetChunk("pmod")); uint numPmods = hydra.GetChunk("pmod").Size / 10 - 1; for (uint i = 0; i < numPmods; i++) { pMods.Add(r.Read <Modulator>()); } //Get preset generators. List <Generator> pGens = new List <Generator>(); r.OpenChunk(hydra.GetChunk("pgen")); uint numPgens = hydra.GetChunk("pgen").Size / 4 - 1; for (uint i = 0; i < numPgens; i++) { pGens.Add(r.Read <Generator>()); } //Get true generators and modulators. for (int i = 0; i < presetGenModIndices.Count; i++) { //Index. int startGen = presetGenModIndices[i].Item1; int startMod = presetGenModIndices[i].Item2; int numGen = pGens.Count - startGen; int numMod = pMods.Count - startMod; if (i + 1 <= presetGenModIndices.Count - 1) { numGen = presetGenModIndices[i + 1].Item1 - startGen; numMod = presetGenModIndices[i + 1].Item2 - startMod; } //Get stuff. for (int j = startGen; j < startGen + numGen; j++) { presetZones[i].Generators.Add(pGens[j]); } for (int j = startMod; j < startMod + numMod; j++) { presetZones[i].Modulators.Add(pMods[j]); } } //Add the zones to the presets. for (int i = 0; i < Presets.Count; i++) { //Index. int startZone = Presets[i].ReadingBagIndex; int numZones = presetGenModIndices.Count - startZone; if (i + 1 <= Presets.Count - 1) { numZones = Presets[i + 1].ReadingBagIndex - startZone; } //Get stuff. for (int j = startZone; j < startZone + numZones; j++) { if (Presets[i].Zones.Count == 0 && presetZones[j].Generators.Where(x => x.Gen == SF2Generators.Instrument).Where(x => x.Gen == SF2Generators.Instrument).Count() < 1) { Presets[i].GlobalZone = presetZones[j]; } else { Presets[i].Zones.Add(presetZones[j]); } } } //Get instruments. r.OpenChunk(hydra.GetChunk("inst")); uint numInstruments = hydra.GetChunk("inst").Size / 22 - 1; for (uint i = 0; i < numInstruments; i++) { Instruments.Add(r.Read <Instrument>()); } //Get instrument bags. List <Tuple <ushort, ushort> > instrumentGenModIndices = new List <Tuple <ushort, ushort> >(); List <Zone> instrumentZones = new List <Zone>(); r.OpenChunk(hydra.GetChunk("ibag")); uint numIbags = hydra.GetChunk("ibag").Size / 4 - 1; for (uint i = 0; i < numIbags; i++) { instrumentGenModIndices.Add(new Tuple <ushort, ushort>(r.ReadUInt16(), r.ReadUInt16())); instrumentZones.Add(new Zone()); } //Get instrument modulators. List <Modulator> iMods = new List <Modulator>(); r.OpenChunk(hydra.GetChunk("imod")); uint numImods = hydra.GetChunk("imod").Size / 10 - 1; for (uint i = 0; i < numImods; i++) { iMods.Add(r.Read <Modulator>()); } //Get instrument generators. List <Generator> iGens = new List <Generator>(); r.OpenChunk(hydra.GetChunk("igen")); uint numIgens = hydra.GetChunk("igen").Size / 4 - 1; for (uint i = 0; i < numIgens; i++) { iGens.Add(r.Read <Generator>()); } //Get true generators and modulators. for (int i = 0; i < instrumentGenModIndices.Count; i++) { //Index. int startGen = instrumentGenModIndices[i].Item1; int startMod = instrumentGenModIndices[i].Item2; int numGen = iGens.Count - startGen; int numMod = iMods.Count - startMod; if (i + 1 <= instrumentGenModIndices.Count - 1) { numGen = instrumentGenModIndices[i + 1].Item1 - startGen; numMod = instrumentGenModIndices[i + 1].Item2 - startMod; } //Get stuff. for (int j = startGen; j < startGen + numGen; j++) { instrumentZones[i].Generators.Add(iGens[j]); } for (int j = startMod; j < startMod + numMod; j++) { instrumentZones[i].Modulators.Add(iMods[j]); } } //Add the zones to the instruments. for (int i = 0; i < Instruments.Count; i++) { //Index. int startZone = Instruments[i].ReadingBagIndex; int numZones = instrumentGenModIndices.Count - startZone; if (i + 1 <= Instruments.Count - 1) { numZones = Instruments[i + 1].ReadingBagIndex - startZone; } //Get stuff. for (int j = startZone; j < startZone + numZones; j++) { if (Instruments[i].Zones.Count == 0 && instrumentZones[j].Generators.Where(x => x.Gen == SF2Generators.SampleID).Count() < 1) { Instruments[i].GlobalZone = instrumentZones[j]; } else { Instruments[i].Zones.Add(instrumentZones[j]); } } } //Get samples. r.OpenChunk(hydra.GetChunk("shdr")); uint numSamples = hydra.GetChunk("shdr").Size / 46 - 1; r.CurrentOffset = waveTablePos; for (uint i = 0; i < numSamples; i++) { Samples.Add(r.Read <SampleItem>()); } } }