internal M4ASMulti(M4AVoice ks) : base(ks) { Table = VoiceTable.LoadTable <M4AVoiceTable>(ks.Table, true); var keys = ROM.Instance.ReadBytes(256, ks.Keys); var loading = new List <Triple <byte, byte, byte> >(); // Key, min, max int prev = -1; for (int i = 0; i < 256; i++) { byte a = keys[i]; byte bi = (byte)i; if (prev == a) { loading[loading.Count - 1].Item3 = bi; } else { prev = a; loading.Add(new Triple <byte, byte, byte>(a, bi, bi)); } } Keys = loading.ToArray(); }
void AddPSG(M4AVoice voice, byte low = 0, byte high = 127) { dynamic v = voice; int sample; if (voice is M4APSG_Square_1 || voice is M4APSG_Square_2) { sample = AddSample(SongPlayer.Sounds[SongPlayer.SQUARE12_ID - v.Pattern], "Square Wave " + v.Pattern); } else if (voice is M4APSG_Wave wave) { sample = AddSample(SongPlayer.Sounds[wave.Address], string.Format("PSG Wave 0x{0:X}", wave.Address)); } else { sample = AddSample(SongPlayer.Sounds[SongPlayer.NOISE0_ID - v.Pattern], "Noise " + v.Pattern); } sf2.AddINSTBag(); // ADSR if (v.A != 0) { // Compute attack time - the sound engine is called 60 times per second // and adds "attack" to envelope every time the engine is called double att_time = v.A / 5.0; double att = 1200 * Math.Log(att_time, 2); sf2.AddINSTGenerator(SF2Generator.attackVolEnv, new GenAmountType((ushort)att)); } if (v.S != 15) { double sus; // Compute attenuation in cB if sustain is non-zero if (v.S != 0) { sus = 100 * Math.Log(15d / v.S); } // Special case where attenuation is infinite -> use max value else { sus = 1000; } sf2.AddINSTGenerator(SF2Generator.sustainVolEnv, new GenAmountType((ushort)sus)); double dec_time = v.D / 5d; double dec = 1200 * Math.Log(dec_time + 1, 2); sf2.AddINSTGenerator(SF2Generator.decayVolEnv, new GenAmountType((ushort)dec)); } if (v.R != 0) { double rel_time = v.R / 5d; double rel = 1200 * Math.Log(rel_time, 2); sf2.AddINSTGenerator(SF2Generator.releaseVolEnv, new GenAmountType((ushort)rel)); } high = Math.Min((byte)127, high); if (!(low == 0 && high == 127)) { sf2.AddINSTGenerator(SF2Generator.keyRange, new GenAmountType(low, high)); } if (voice is M4APSG_Noise noise && noise.Panpot != 0) { sf2.AddINSTGenerator(SF2Generator.pan, new GenAmountType((ushort)((noise.Panpot - 0xC0) * (500d / 0x80)))); } sf2.AddINSTGenerator(SF2Generator.sampleModes, new GenAmountType(1)); sf2.AddINSTGenerator(SF2Generator.sampleID, new GenAmountType((ushort)(sample))); }
internal M4ASDirect(M4AVoice direct) : base(direct) => Sample = new M4ASSample(direct.Address);
internal M4ASWave(M4AVoice wave) : base(wave) => sample = ROM.Instance.ReadBytes(16, wave.Address);
internal M4ASDrum(M4AVoice d) : base(d) { Table = VoiceTable.LoadTable <M4AVoiceTable>(d.Table, true); }