/// <summary>
        /// Create a DLS from a sound font.
        /// </summary>
        /// <param name="sf2">The SF2 file.</param>
        public DownloadableSounds(SoundFont sf2)
        {
            //Get waves.
            List <string>            waveMd5s     = new List <string>();
            Dictionary <int, string> newWaveIds   = new Dictionary <int, string>();
            Dictionary <int, sbyte>  tunings      = new Dictionary <int, sbyte>();
            Dictionary <int, byte>   origPitches  = new Dictionary <int, byte>();
            Dictionary <int, uint>   channelFlags = new Dictionary <int, uint>();

            Waves = new List <RiffWave>();
            foreach (var i in sf2.Instruments)
            {
                foreach (var z in i.GetAllZones())
                {
                    foreach (var g in z.Generators.Where(x => x.Gen == SF2Generators.SampleID))
                    {
                        var      s   = sf2.Samples[g.Amount.UAmount];
                        RiffWave wav = new RiffWave();
                        wav.Loops          = s.Wave.Loops;
                        wav.LoopStart      = s.Wave.LoopStart;
                        wav.LoopEnd        = s.Wave.LoopEnd;
                        wav.SampleRate     = s.Wave.SampleRate;
                        wav.Audio.Channels = new List <List <GotaSoundIO.Sound.Encoding.IAudioEncoding> >();
                        switch (s.LinkType)
                        {
                        case SF2LinkTypes.Left:
                            wav.Audio.Channels.Add(s.Wave.Audio.Channels[0]);
                            try {
                                wav.Audio.Channels.Add(sf2.Samples.Where(x => x.Link == s.Link && x.LinkType == SF2LinkTypes.Right).FirstOrDefault().Wave.Audio.Channels[0]);
                            } catch { }
                            if (!channelFlags.ContainsKey(g.Amount.UAmount))
                            {
                                channelFlags.Add(g.Amount.UAmount, 0b11);
                            }
                            break;

                        case SF2LinkTypes.Right:
                            try {
                                wav.Audio.Channels.Add(sf2.Samples.Where(x => x.Link == s.Link && x.LinkType == SF2LinkTypes.Left).FirstOrDefault().Wave.Audio.Channels[0]);
                            } catch { }
                            wav.Audio.Channels.Add(s.Wave.Audio.Channels[0]);
                            if (!channelFlags.ContainsKey(g.Amount.UAmount))
                            {
                                channelFlags.Add(g.Amount.UAmount, 0b11);
                            }
                            break;

                        case SF2LinkTypes.Mono:
                            wav.Audio.Channels.Add(s.Wave.Audio.Channels[0]);
                            if (!channelFlags.ContainsKey(g.Amount.UAmount))
                            {
                                channelFlags.Add(g.Amount.UAmount, 0b1);
                            }
                            break;

                        case SF2LinkTypes.Linked:
                            foreach (var w in sf2.Samples)
                            {
                                if (w.LinkType == SF2LinkTypes.Linked && w.Link == s.Link)
                                {
                                    wav.Audio.Channels.Add(w.Wave.Audio.Channels[0]);
                                    if (!channelFlags.ContainsKey(g.Amount.UAmount))
                                    {
                                        channelFlags.Add(g.Amount.UAmount, 0);
                                    }
                                    channelFlags[g.Amount.UAmount] <<= 1;
                                    channelFlags[g.Amount.UAmount]  |= 0b1;
                                }
                            }
                            break;
                        }
                        string md5 = wav.Md5Sum;
                        if (!newWaveIds.ContainsKey(g.Amount.UAmount))
                        {
                            newWaveIds.Add(g.Amount.UAmount, md5);
                            tunings.Add(g.Amount.UAmount, sf2.Samples[g.Amount.UAmount].PitchCorrection);
                            origPitches.Add(g.Amount.UAmount, sf2.Samples[g.Amount.UAmount].OriginalPitch);
                        }
                        if (!waveMd5s.Contains(md5))
                        {
                            waveMd5s.Add(md5);
                            Waves.Add(wav);
                        }
                    }
                }
            }

            //Get instruments.
            Instruments = new List <Instrument>();
            int instId = 0;

            foreach (var inst in sf2.Instruments)
            {
                //Instrument.
                Instrument i = new Instrument();
                i.Name    = inst.Name;
                i.Regions = new List <Region>();
                i.BankId  = 0;
                foreach (var p in sf2.Presets)
                {
                    foreach (var z in p.GetAllZones())
                    {
                        foreach (var g in z.Generators)
                        {
                            if (g.Gen == SF2Generators.Instrument && g.Amount.Amount == instId)
                            {
                                i.BankId       = p.Bank;
                                i.InstrumentId = p.PresetNumber;
                            }
                        }
                    }
                }
                instId++;

                //Get regions.
                foreach (var z in inst.Zones)
                {
                    var reg = GetInstrumentRegion(z, inst.GlobalZone);
                    if (reg != null)
                    {
                        i.Regions.Add(reg);
                    }
                }
                if (i.Regions.Count < 1)
                {
                    var reg = GetInstrumentRegion(inst.GlobalZone, null);
                    if (reg != null)
                    {
                        i.Regions.Add(reg);
                    }
                }

                //Add instrument.
                Instruments.Add(i);
            }

            //Get an instrument region from an SF2 zone.
            Region GetInstrumentRegion(Zone z, Zone g)
            {
                //Null region.
                if (z == null)
                {
                    return(null);
                }

                //New region.
                Region r = new Region();

                //Get sample.
                int sampleNumRaw = SF2Value(SF2Generators.SampleID).UAmount;
                int sampleNum    = waveMd5s.IndexOf(newWaveIds[sampleNumRaw]);

                r.WaveId       = (uint)sampleNum;
                r.Tuning       = (short)(tunings[sampleNumRaw] % 12 * 65536);
                r.RootNote     = (byte)(origPitches[sampleNumRaw] + tunings[sampleNumRaw] / 12);
                r.ChannelFlags = channelFlags[sampleNumRaw];
                r.Loops        = Waves[sampleNum].Loops;
                r.LoopStart    = Waves[sampleNum].LoopStart;
                r.LoopLength   = Waves[sampleNum].LoopEnd - Waves[sampleNum].LoopStart;
                Articulator art = new Articulator();

                art.Connections = new List <Connection>();
                var c = art.Connections;

                //Get generators.
                foreach (var gen in z.Generators)
                {
                    DestinationConnection d = DestinationConnection.Center;
                    switch (gen.Gen)
                    {
                    case SF2Generators.OverridingRootKey:
                        r.RootNote = (byte)(gen.Amount.Amount + tunings[sampleNumRaw] / 12);
                        continue;

                    case SF2Generators.KeyRange:
                        r.NoteLow  = gen.Amount.LowByte;
                        r.NoteHigh = gen.Amount.HighByte;
                        continue;

                    case SF2Generators.VelRange:
                        r.VelocityLow  = gen.Amount.LowByte;
                        r.VelocityHigh = gen.Amount.HighByte;
                        continue;

                    case SF2Generators.ChorusEffectsSend:
                        d = DestinationConnection.Chorus;
                        break;

                    case SF2Generators.AttackVolEnv:
                        d = DestinationConnection.EG1AttackTime;
                        break;

                    case SF2Generators.DecayVolEnv:
                        d = DestinationConnection.EG1DecayTime;
                        break;

                    case SF2Generators.DelayVolEnv:
                        d = DestinationConnection.EG1DelayTime;
                        break;

                    case SF2Generators.HoldVolEnv:
                        d = DestinationConnection.EG1HoldTime;
                        break;

                    case SF2Generators.ReleaseVolEnv:
                        d = DestinationConnection.EG1ReleaseTime;
                        break;

                    case SF2Generators.SustainVolEnv:
                        d = DestinationConnection.EG1SustainLevel;
                        c.Add(new Connection()
                        {
                            DestinationConnection = d, Scale = (int)((1 - (gen.Amount.Amount / 1000d)) * 1000 * 65536)
                        });
                        continue;

                    case SF2Generators.Keynum:
                        d = DestinationConnection.KeyNumber;
                        break;

                    case SF2Generators.Pan:
                        d = DestinationConnection.Pan;
                        break;

                    case SF2Generators.FreqModLFO:
                        d = DestinationConnection.LFOFrequency;
                        break;

                    case SF2Generators.DelayModLFO:
                        d = DestinationConnection.LFOStartDelayTime;
                        break;

                    default:
                        continue;
                    }
                    c.Add(new Connection()
                    {
                        DestinationConnection = d, Scale = gen.Amount.Amount * 65536
                    });
                }

                //Get the SF2 value.
                SF2GeneratorAmount SF2Value(SF2Generators gen)
                {
                    var ret = new SF2GeneratorAmount();

                    if (g != null)
                    {
                        var a = g.Generators.Where(x => x.Gen == gen).FirstOrDefault();
                        if (a != null)
                        {
                            ret.Amount += a.Amount.Amount;
                        }
                    }
                    var b = z.Generators.Where(x => x.Gen == gen).FirstOrDefault();

                    if (b != null)
                    {
                        ret.Amount = b.Amount.Amount;
                    }
                    return(ret);
                }

                //Add articulators.
                r.Articulators = new List <Articulator>()
                {
                    art
                };

                //Return the region.
                return(r);
            }
        }
        /// <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);
                }
            }
        }