/// <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>()); } } }