private static SampleSoundGenerator ImportPreset(SoundFont sf2, Preset preset, SampleGeneratingArgs args) { /* * == Aproximate Pesdo Code of importing a preset from sf2 == * - Get all preset zones from soundfont (sf2) * - get the instrument and double check if it's not null (if it is, "continue" the method) * - is the instrument grabbed the same as what args is asking for? (if not, "continue" method) * - get each zone within instrument and create wav file from information * - get Sample Header of instrument zone and double check if null (if so, "continue") * - get the Key range of spesified zone and create high and low keys 8 bit's in difference. * - is the key not the same as what the args asked for? (yes, then "continue") * - Get the velocity range of spesified zone and create high and low keys 8 bits' in difference. * - is the velocity not the same as what the args asked for? (yes, then "continue") * - Find the closest key from instrument zone to the key spesified from args. * - is the closest key lower than the maximum integer value or, is the key of args just not spesified? * - if so, set the closest zone (initial = null) to the current zone, * - if so, set the bdist (initial = maximum integer value) to the closest key. * - Is there a zone found from above? * - If so, create a wave from zone information using the SampleData. */ return(ImportInstruments(sf2, preset.Zones.Select(z => z.Instrument()), args)); }
private void LoadSf2(Stream stream) { SoundFont sf = new SoundFont(stream); bankName = sf.Info.BankName; comment = sf.Info.Comments; //load samples for (int x = 0; x < sf.Presets.SampleHeaders.Length; x++) { assets.SampleAssetList.Add(new SampleDataAsset(sf.Presets.SampleHeaders[x], sf.SampleData)); } //create instrument regions first Sf2Region[][] inst = ReadSf2Instruments(sf.Presets.Instruments); //load each patch foreach (PresetHeader p in sf.Presets.PresetHeaders) { Generator[] globalGens = null; int i; if (p.Zones[0].Generators.Length == 0 || p.Zones[0].Generators[p.Zones[0].Generators.Length - 1].GeneratorType != GeneratorEnum.Instrument) { globalGens = p.Zones[0].Generators; i = 1; } else { i = 0; } List <Sf2Region> regionList = new List <Sf2Region>(); while (i < p.Zones.Length) { byte presetLoKey = 0; byte presetHiKey = 127; byte presetLoVel = 0; byte presetHiVel = 127; if (p.Zones[i].Generators[0].GeneratorType == GeneratorEnum.KeyRange) { if (BitConverter.IsLittleEndian) { presetLoKey = (byte)(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetHiKey = (byte)((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } else { presetHiKey = (byte)(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetLoKey = (byte)((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } if (p.Zones[i].Generators.Length > 1 && p.Zones[i].Generators[1].GeneratorType == GeneratorEnum.VelocityRange) { if (BitConverter.IsLittleEndian) { presetLoVel = (byte)(p.Zones[i].Generators[1].AmountInt16 & 0xFF); presetHiVel = (byte)((p.Zones[i].Generators[1].AmountInt16 >> 8) & 0xFF); } else { presetHiVel = (byte)(p.Zones[i].Generators[1].AmountInt16 & 0xFF); presetLoVel = (byte)((p.Zones[i].Generators[1].AmountInt16 >> 8) & 0xFF); } } } else if (p.Zones[i].Generators[0].GeneratorType == GeneratorEnum.VelocityRange) { if (BitConverter.IsLittleEndian) { presetLoVel = (byte)(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetHiVel = (byte)((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } else { presetHiVel = (byte)(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetLoVel = (byte)((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } } if (p.Zones[i].Generators[p.Zones[i].Generators.Length - 1].GeneratorType == GeneratorEnum.Instrument) { Sf2Region[] insts = inst[p.Zones[i].Generators[p.Zones[i].Generators.Length - 1].AmountInt16]; for (int x = 0; x < insts.Length; x++) { byte instLoKey; byte instHiKey; byte instLoVel; byte instHiVel; if (BitConverter.IsLittleEndian) { instLoKey = (byte)(insts[x].Generators[(int)GeneratorEnum.KeyRange] & 0xFF); instHiKey = (byte)((insts[x].Generators[(int)GeneratorEnum.KeyRange] >> 8) & 0xFF); instLoVel = (byte)(insts[x].Generators[(int)GeneratorEnum.VelocityRange] & 0xFF); instHiVel = (byte)((insts[x].Generators[(int)GeneratorEnum.VelocityRange] >> 8) & 0xFF); } else { instHiKey = (byte)(insts[x].Generators[(int)GeneratorEnum.KeyRange] & 0xFF); instLoKey = (byte)((insts[x].Generators[(int)GeneratorEnum.KeyRange] >> 8) & 0xFF); instHiVel = (byte)(insts[x].Generators[(int)GeneratorEnum.VelocityRange] & 0xFF); instLoVel = (byte)((insts[x].Generators[(int)GeneratorEnum.VelocityRange] >> 8) & 0xFF); } if ((instLoKey <= presetHiKey && presetLoKey <= instHiKey) && (instLoVel <= presetHiVel && presetLoVel <= instHiVel)) { Sf2Region r = new Sf2Region(); Array.Copy(insts[x].Generators, r.Generators, r.Generators.Length); ReadSf2Region(r, globalGens, p.Zones[i].Generators, true); regionList.Add(r); } } } i++; } MultiPatch mp = new MultiPatch(p.Name); mp.LoadSf2(regionList.ToArray(), assets); assets.PatchAssetList.Add(new PatchAsset(mp.Name, mp)); AssignPatchToBank(mp, p.BankNumber, p.PatchNumber, p.PatchNumber); } }
/// <summary> /// Imports all samples specified by <see cref="SampleGeneratingArgs"/> and returns a dictionary which maps the <see cref="SampleGeneratingArgs"/> /// to their <see cref="SampleSoundGenerator"/>. If a sample couldn't be imported then it has a null instead. /// </summary> /// <param name="argsList"></param> /// <returns></returns> public static Dictionary <SampleGeneratingArgs, SampleSoundGenerator> ImportSamples(IEnumerable <SampleGeneratingArgs> argsList) { var samples = new Dictionary <SampleGeneratingArgs, SampleSoundGenerator>(); var separatedByPath = new Dictionary <string, HashSet <SampleGeneratingArgs> >(); foreach (var args in argsList) { if (separatedByPath.TryGetValue(args.Path, out HashSet <SampleGeneratingArgs> value)) { value.Add(args); } else { separatedByPath.Add(args.Path, new HashSet <SampleGeneratingArgs> { args }); } } foreach (var pair in separatedByPath) { var path = pair.Key; if (!ValidateSampleArgs(path)) { foreach (var args in pair.Value) { samples.Add(args, null); } continue; } try { switch (Path.GetExtension(path)) { case ".sf2": { var sf2 = new SoundFont(path); foreach (var args in pair.Value) { var sample = ImportFromSoundFont(args, sf2); samples.Add(args, sample); } break; } case ".ogg": { foreach (var args in pair.Value) { samples.Add(args, ImportFromVorbis(args)); } break; } default: { foreach (var args in pair.Value) { samples.Add(args, ImportFromAudio(args)); } break; } } } catch (Exception ex) { Console.WriteLine(ex.Message); foreach (var args in pair.Value) { samples.Add(args, null); } } GC.Collect(); } return(samples); }
private static SampleSoundGenerator ImportInstruments(SoundFont sf2, SampleGeneratingArgs args) { return(ImportInstruments(sf2, sf2.Instruments, args)); }
// TODO: format soundfont import to detect file versions and types of files. public static SampleSoundGenerator ImportFromSoundFont(SampleGeneratingArgs args, SoundFont sf2) { SampleSoundGenerator wave = null; foreach (var preset in sf2.Presets) { if (preset.PatchNumber != args.Patch && args.Patch != -1) { continue; } if (preset.Bank != args.Bank && args.Bank != -1) { continue; } wave = ImportPreset(sf2, preset, args); if (wave != null) { break; } } return(wave ?? ImportInstruments(sf2, args)); }
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.SoundFontDetails); var sf = Intent.GetStringExtra("soundfont"); var model = ApplicationModel.Instance; var mod = model.Database.Modules.First(m => m.Name == sf); var sfFile = model.Files.FirstOrDefault(p => p.Value == mod.Name).Key; if (!File.Exists(sfFile)) { Toast.MakeText(this, string.Format("SoundFont file '{0}' was not found. Details not shown", sfFile), ToastLength.Long).Show(); } else { var sf2 = new SoundFont(new MemoryStream(File.ReadAllBytes(sfFile))); var infoList = new JavaList <IDictionary <string, object> > (); var map = mod.Instrument.Maps.First(); var labels = new string [] { "BankName", "FileName", "Author", "Copyright", "Comments", "Created", "SFVersion", "ROMVersion", "WaveTableEngine", "Tools", "TargetProduct", "DataROM" }; var values = new string [] { mod.Name, sfFile, sf2.FileInfo.Author, sf2.FileInfo.Copyright, sf2.FileInfo.Comments, sf2.FileInfo.SoundFontVersion == null ? null : string.Format("{0}.{1}", sf2.FileInfo.SoundFontVersion.Major, sf2.FileInfo.SoundFontVersion.Minor), sf2.FileInfo.ROMVersion == null ? null : string.Format("{0}.{1}", sf2.FileInfo.ROMVersion.Major, sf2.FileInfo.ROMVersion.Minor), sf2.FileInfo.CreationDate, sf2.FileInfo.WaveTableSoundEngine, sf2.FileInfo.Tools, sf2.FileInfo.TargetProduct, sf2.FileInfo.DataROM, }; for (int i = 0; i < labels.Length; i++) { var items = new JavaDictionary <string, object> (); items.Add("text1", labels [i]); items.Add("text2", values [i]); infoList.Add(items); } var bankList = new JavaList <IDictionary <string, object> > (); foreach (var p in map.Programs) { foreach (var b in p.Banks) { var items = new JavaDictionary <string, object> (); items.Add("text1", string.Format("{0:D03}.{1:D03}.{2:D03}", p.Index, b.Msb, b.Lsb)); items.Add("text2", b.Name); bankList.Add(items); } } var fromKeys = new string [] { "text1", "text2" }; var toIds = new int [] { Resource.Id.soundFontDetailFileInfoLabel, Resource.Id.soundFontDetailFileInfoValue }; var lvfi = FindViewById <ListView> (Resource.Id.soundFontDetailsFileInfo); lvfi.Adapter = new SimpleAdapter(this, infoList, Resource.Layout.SoundFontFileInfoItem, fromKeys, toIds); var lvbanks = FindViewById <ListView> (Resource.Id.soundFontDetailsBankList); lvbanks.Adapter = new SimpleAdapter(this, bankList, Resource.Layout.SoundFontFileInfoItem, fromKeys, toIds); } }
public void LoadSf2(IReadable input) { Reset(); Logger.Debug("Reading SF2"); var sf = new SoundFont(); sf.Load(input); Logger.Debug("Building patchbank"); Name = sf.Info.BankName; Comments = sf.Info.Comments; //load samples foreach (var sampleHeader in sf.Presets.SampleHeaders) { _assets.SampleAssets.Add(new SampleDataAsset(sampleHeader, sf.SampleData)); } //create instrument regions first var sfinsts = ReadSf2Instruments(sf.Presets.Instruments); //load each patch foreach (var p in sf.Presets.PresetHeaders) { Generator[] globalGens = null; int i; if (p.Zones[0].Generators.Length == 0 || p.Zones[0].Generators[p.Zones[0].Generators.Length - 1].GeneratorType != GeneratorEnum.Instrument) { globalGens = p.Zones[0].Generators; i = 1; } else { i = 0; } var regionList = new FastList <Sf2Region>(); while (i < p.Zones.Length) { byte presetLoKey = 0; byte presetHiKey = 127; byte presetLoVel = 0; byte presetHiVel = 127; if (p.Zones[i].Generators[0].GeneratorType == GeneratorEnum.KeyRange) { if (TypeUtils.IsLittleEndian) { presetLoKey = TypeUtils.ToUInt8(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetHiKey = TypeUtils.ToUInt8((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } else { presetHiKey = TypeUtils.ToUInt8(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetLoKey = TypeUtils.ToUInt8((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } if (p.Zones[i].Generators.Length > 1 && p.Zones[i].Generators[1].GeneratorType == GeneratorEnum.VelocityRange) { if (TypeUtils.IsLittleEndian) { presetLoVel = TypeUtils.ToUInt8(p.Zones[i].Generators[1].AmountInt16 & 0xFF); presetHiVel = TypeUtils.ToUInt8((p.Zones[i].Generators[1].AmountInt16 >> 8) & 0xFF); } else { presetHiVel = TypeUtils.ToUInt8(p.Zones[i].Generators[1].AmountInt16 & 0xFF); presetLoVel = TypeUtils.ToUInt8((p.Zones[i].Generators[1].AmountInt16 >> 8) & 0xFF); } } } else if (p.Zones[i].Generators[0].GeneratorType == GeneratorEnum.VelocityRange) { if (TypeUtils.IsLittleEndian) { presetLoVel = TypeUtils.ToUInt8(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetHiVel = TypeUtils.ToUInt8((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } else { presetHiVel = TypeUtils.ToUInt8(p.Zones[i].Generators[0].AmountInt16 & 0xFF); presetLoVel = TypeUtils.ToUInt8((p.Zones[i].Generators[0].AmountInt16 >> 8) & 0xFF); } } if (p.Zones[i].Generators[p.Zones[i].Generators.Length - 1].GeneratorType == GeneratorEnum.Instrument) { var insts = sfinsts[p.Zones[i].Generators[p.Zones[i].Generators.Length - 1].AmountInt16]; foreach (var inst in insts) { byte instLoKey; byte instHiKey; byte instLoVel; byte instHiVel; if (TypeUtils.IsLittleEndian) { instLoKey = TypeUtils.ToUInt8(inst.Generators[(int)GeneratorEnum.KeyRange] & 0xFF); instHiKey = TypeUtils.ToUInt8((inst.Generators[(int)GeneratorEnum.KeyRange] >> 8) & 0xFF); instLoVel = TypeUtils.ToUInt8(inst.Generators[(int)GeneratorEnum.VelocityRange] & 0xFF); instHiVel = TypeUtils.ToUInt8((inst.Generators[(int)GeneratorEnum.VelocityRange] >> 8) & 0xFF); } else { instHiKey = TypeUtils.ToUInt8(inst.Generators[(int)GeneratorEnum.KeyRange] & 0xFF); instLoKey = TypeUtils.ToUInt8((inst.Generators[(int)GeneratorEnum.KeyRange] >> 8) & 0xFF); instHiVel = TypeUtils.ToUInt8(inst.Generators[(int)GeneratorEnum.VelocityRange] & 0xFF); instLoVel = TypeUtils.ToUInt8((inst.Generators[(int)GeneratorEnum.VelocityRange] >> 8) & 0xFF); } if ((instLoKey <= presetHiKey && presetLoKey <= instHiKey) && (instLoVel <= presetHiVel && presetLoVel <= instHiVel)) { var r = new Sf2Region(); Std.ArrayCopy(inst.Generators, 0, r.Generators, 0, r.Generators.Length); ReadSf2Region(r, globalGens, p.Zones[i].Generators, true); regionList.Add(r); } } } i++; } var mp = new MultiPatch(p.Name); mp.LoadSf2(regionList.ToArray(), _assets); _assets.PatchAssets.Add(new PatchAsset(mp.Name, mp)); AssignPatchToBank(mp, p.BankNumber, p.PatchNumber, p.PatchNumber); } }
public IMidiRenderer GetNewRenderer() { if (!FluidsynthInitialized) { InitializeFluidsynth(); if (!FluidsynthInitialized) // init failed { return(null); } } var soundfontLoader = SoundFontLoader.NewDefaultSoundFontLoader(_settings); // Just making double sure these don't get GC'd. // They shouldn't, MidiRenderer keeps a ref, but making sure... var handle = GCHandle.Alloc(soundfontLoader); try { soundfontLoader.SetCallbacks(_soundfontLoaderCallbacks); var renderer = new MidiRenderer(_settings, soundfontLoader); // Since the last loaded soundfont takes priority, we load the fallback soundfont first. renderer.LoadSoundfont(FallbackSoundfont); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { foreach (var filepath in LinuxSoundfonts) { if (!File.Exists(filepath) || !SoundFont.IsSoundFont(filepath)) { continue; } try { renderer.LoadSoundfont(filepath, true); } catch (Exception) { continue; } break; } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { if (File.Exists(OsxSoundfont) && SoundFont.IsSoundFont(OsxSoundfont)) { renderer.LoadSoundfont(OsxSoundfont, true); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (File.Exists(WindowsSoundfont) && SoundFont.IsSoundFont(WindowsSoundfont)) { renderer.LoadSoundfont(WindowsSoundfont, true); } } lock (_renderers) _renderers.Add(renderer); return(renderer); } finally { handle.Free(); } }
public bool IsSoundfontFile(string filename) { return(SoundFont.IsSoundFont(filename)); }
public bool IsMidiFile(string filename) { return(SoundFont.IsMidiFile(filename)); }
void ImportSamples(SoundFont sf2, Preset preset, XInstrument xrni) { var xl = new List <XSample> (); var ml = new List <SampleMap> (); var il = new List <int> (); foreach (var pzone in preset.Zones) // perc. bank likely has more than one instrument here. { var i = pzone.Instrument(); var kr = pzone.KeyRange(); // FIXME: where should I use it? if (i == null) { continue; // FIXME: is it possible? } var vr = pzone.VelocityRange(); // an Instrument contains a set of zones that contain sample headers. int sampleCount = 0; foreach (var izone in i.Zones) { var ikr = izone.KeyRange(); var ivr = izone.VelocityRange(); var sh = izone.SampleHeader(); if (sh == null) { continue; // FIXME: is it possible? } // FIXME: sample data must become monoral (panpot neutral) var xs = ConvertSample(sampleCount++, sh, sf2.SampleData, izone); xs.Name = NormalizePathName(sh.SampleName); ml.Add(new SampleMap(ikr, ivr, xs, sh)); } } ml.Sort((m1, m2) => m1.KeyLowRange != m2.KeyLowRange ? m1.KeyLowRange - m2.KeyLowRange : m1.KeyHighRange != m2.KeyHighRange ? m1.KeyHighRange - m2.KeyHighRange : m1.VelocityLowRange != m2.VelocityLowRange ? m1.VelocityLowRange - m2.VelocityLowRange : m1.VelocityHighRange - m2.VelocityHighRange); int prev = -1; foreach (var m in ml) { prev = m.KeyLowRange; il.Add(m.KeyLowRange); xl.Add(m.Sample); } xrni.SampleSplitMap = new SampleSplitMap(); xrni.SampleSplitMap.NoteOnMappings = new SampleSplitMapNoteOnMappings(); var nm = new SampleSplitMapping [ml.Count]; xrni.SampleSplitMap.NoteOnMappings.NoteOnMapping = nm; for (int i = 0; i < ml.Count; i++) { var m = ml [i]; var n = new SampleSplitMapping(); n.BaseNote = m.Sample.BaseNote; n.NoteStart = m.KeyLowRange; n.NoteEnd = m.KeyHighRange <= 0 ? 128 : m.KeyHighRange; n.SampleIndex = i; if (m.VelocityHighRange > 0) { n.MapVelocityToVolume = true; n.VelocityStart = m.VelocityLowRange; n.VelocityEnd = m.VelocityHighRange; } nm [i] = n; } xrni.Samples = new RenoiseInstrumentSamples(); xrni.Samples.Sample = xl.ToArray(); }
/// <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); } }