/// <summary> /// Convert the bank to downloadable sounds. /// </summary> /// <param name="a">The sound archive.</param> /// <param name="b">The bank info.</param> /// <returns>The bank as DLS.</returns> public DownloadableSounds ToDLS(SoundArchive a, BankInfo b) { //New DLS. DownloadableSounds d = new DownloadableSounds(); //Wave map. Dictionary <uint, RiffWave> waveMap = new Dictionary <uint, RiffWave>(); Dictionary <ushort, RiffWave> psgMap = new Dictionary <ushort, RiffWave>(); Dictionary <ushort, RiffWave> noiseMap = new Dictionary <ushort, RiffWave>(); d.Waves.Add(new RiffWave("Hardware/Null.wav")); //Add each instrument. foreach (var inst in Instruments) { //New instrument. GotaSoundBank.DLS.Instrument im = new GotaSoundBank.DLS.Instrument(); im.BankId = (uint)(inst.Index / 128); im.InstrumentId = (uint)(inst.Index % 128); im.Name = "Instrument " + im.InstrumentId; //Add regions. byte lastNote = inst as DrumSetInstrument != null ? (inst as DrumSetInstrument).Min : (byte)0; foreach (var n in inst.NoteInfo) { //New region. Region r = new Region(); //Set note info. r.VelocityLow = 0; r.VelocityHigh = 127; r.NoteLow = lastNote; r.NoteHigh = (inst as DirectInstrument != null) ? (byte)127 : (byte)n.Key; lastNote = (byte)(n.Key + 1); r.ChannelFlags = 1; r.DoublePlayback = true; r.Layer = 1; r.NoTruncation = true; r.RootNote = (byte)n.BaseNote; //Wave data. int wavInd = 0; switch (n.InstrumentType) { case InstrumentType.PCM: uint key = 0xFFFFFFFF; try { var p = b.WaveArchives[n.WarId].File.Waves[n.WaveId]; key = (uint)(b.WaveArchives[n.WarId].Index << 16) | n.WaveId; } catch { } if (key != 0xFFFFFFFF) { if (!waveMap.ContainsKey(key)) { RiffWave pcm = new RiffWave(); pcm.FromOtherStreamFile(b.WaveArchives[n.WarId].File.Waves[n.WaveId]); waveMap.Add(key, pcm); d.Waves.Add(pcm); } wavInd = d.Waves.IndexOf(waveMap[key]); } break; case InstrumentType.PSG: if (!psgMap.ContainsKey(n.WaveId)) { RiffWave psg = new RiffWave("Hardware/DutyCycle" + (n.WaveId + 1) + ".wav"); psgMap.Add(n.WaveId, psg); d.Waves.Add(psg); } wavInd = d.Waves.IndexOf(psgMap[n.WaveId]); break; case InstrumentType.Noise: if (!noiseMap.ContainsKey(0)) { RiffWave noise = new RiffWave("Hardware/WhiteNoise.wav"); noiseMap.Add(0, noise); d.Waves.Add(noise); wavInd = d.Waves.IndexOf(noise); } else { wavInd = d.Waves.IndexOf(noiseMap[0]); } break; } //Set wave data. r.WaveId = (uint)wavInd; r.Loops = d.Waves[wavInd].Loops; if (r.Loops) { r.LoopStart = d.Waves[wavInd].LoopStart; r.LoopLength = d.Waves[wavInd].LoopEnd - d.Waves[wavInd].LoopStart; if (r.LoopLength < 0) { r.LoopLength = 0; } } //Articulator. Articulator ar = new Articulator(); ar.Connections.Add(new Connection() { DestinationConnection = DestinationConnection.EG1AttackTime, Scale = n.Attack >= 127 ? int.MinValue : MillisecondsToTimecents(AttackTable[n.Attack]) * 65536 }); ar.Connections.Add(new Connection() { DestinationConnection = DestinationConnection.EG1DecayTime, Scale = n.Decay >= 127 ? int.MinValue : MillisecondsToTimecents(MaxReleaseTimes[n.Decay]) * 65536 }); ar.Connections.Add(new Connection() { DestinationConnection = DestinationConnection.EG1SustainLevel, Scale = (int)Math.Round(Sustain2Fraction(n.Sustain) * 1000, MidpointRounding.AwayFromZero) * 65536 }); ar.Connections.Add(new Connection() { DestinationConnection = DestinationConnection.EG1ReleaseTime, Scale = n.Release >= 127 ? int.MinValue : MillisecondsToTimecents(MaxReleaseTimes[n.Release]) * 65536 }); ar.Connections.Add(new Connection() { DestinationConnection = DestinationConnection.Pan, Scale = GetPan(n.Pan) * 65536 }); r.Articulators.Add(ar); //Add region. im.Regions.Add(r); } //Add the instrument. d.Instruments.Add(im); } //Return the DLS. return(d); }
/// <summary> /// Create a sound font from a downloadable sounds file. /// </summary> /// <param name="dls">A DLS file.</param> public SoundFont(DownloadableSounds dls) { //Get samples. Dictionary <int, int> waveLink; dls.AssignLoops(); CreateSampleTable(dls.Waves, out waveLink); //Get instruments. foreach (var i in dls.Instruments) { Instrument inst = new Instrument(); inst.Name = i.Name; foreach (var r in i.Regions) { //New zone. Zone z = new Zone(); //Key range. if (r.NoteHigh != 127 || r.NoteLow != 0) { z.Generators.Add(new Generator() { Gen = SF2Generators.KeyRange, Amount = new SF2GeneratorAmount() { LowByte = (byte)r.NoteLow, HighByte = (byte)r.NoteHigh } }); } //Velocity range. if (r.VelocityHigh != 127 || r.VelocityLow != 0) { z.Generators.Add(new Generator() { Gen = SF2Generators.VelRange, Amount = new SF2GeneratorAmount() { LowByte = (byte)r.VelocityLow, HighByte = (byte)r.VelocityHigh } }); } //Root key. z.Generators.Add(new Generator() { Gen = SF2Generators.OverridingRootKey, Amount = new SF2GeneratorAmount() { UAmount = r.RootNote } }); //Pitch correction. Samples[waveLink[(int)r.WaveId]].PitchCorrection = (sbyte)(r.Tuning / 65536); //Sample Id. z.Generators.Add(new Generator() { Gen = SF2Generators.SampleID, Amount = new SF2GeneratorAmount() { UAmount = (ushort)waveLink[(int)r.WaveId] } }); if (dls.Waves[(int)r.WaveId].Loops) { z.Generators.Add(new Generator() { Gen = SF2Generators.SampleModes, Amount = new SF2GeneratorAmount() { Amount = 1 } }); } //Articulators. foreach (var a in r.Articulators) { foreach (var c in a.Connections) { //Generator. SF2Generators gen = (SF2Generators)100; SF2GeneratorAmount amount = new SF2GeneratorAmount(); //Switch connection type. switch (c.DestinationConnection) { case DestinationConnection.Chorus: gen = SF2Generators.ChorusEffectsSend; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.EG1AttackTime: gen = SF2Generators.AttackVolEnv; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.EG1DecayTime: gen = SF2Generators.DecayVolEnv; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.EG1DelayTime: gen = SF2Generators.DelayVolEnv; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.EG1HoldTime: gen = SF2Generators.HoldVolEnv; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.EG1ReleaseTime: gen = SF2Generators.ReleaseVolEnv; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.EG1SustainLevel: gen = SF2Generators.SustainVolEnv; amount.Amount = (short)((1 - c.Scale / 65536d / 1000) * 1000); break; case DestinationConnection.KeyNumber: gen = SF2Generators.Keynum; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.Pan: gen = SF2Generators.Pan; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.LFOFrequency: gen = SF2Generators.FreqModLFO; amount.Amount = (short)(c.Scale / 65536); break; case DestinationConnection.LFOStartDelayTime: gen = SF2Generators.DelayModLFO; amount.Amount = (short)(c.Scale / 65536); break; } //Add generator. if ((int)gen != 100) { z.Generators.Add(new Generator() { Gen = gen, Amount = amount }); } //Modulator used. if (c.TransformConnection != TransformConnection.None) { //Nah, I'm lazy. } } } //Add zone. inst.Zones.Add(z); } Instruments.Add(inst); } //Set presets. ushort instNum = 0; foreach (var i in dls.Instruments) { Presets.Add(new Preset() { Bank = (ushort)i.BankId, Name = i.Name, PresetNumber = (ushort)i.InstrumentId, Zones = new List <Zone>() { new Zone() { Generators = new List <Generator>() { new Generator() { Gen = SF2Generators.Instrument, Amount = new SF2GeneratorAmount() { UAmount = instNum++ } } } } } }); } }