some updates
[iv.d.git] / nukedopl3.d
blobaa360c7a9de59009e8944a4a1a0fe3538801388b
1 // Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT)
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
14 // Nuked OPL3 emulator.
15 // Thanks:
16 // MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
17 // Feedback and Rhythm part calculation information.
18 // forums.submarine.org.uk(carbon14, opl3):
19 // Tremolo and phase generator calculation information.
20 // OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
21 // OPL2 ROMs.
23 // version: 1.7.4
24 module iv.nukedopl3 /*is aliced*/;
25 import iv.alice;
26 nothrow @trusted @nogc:
28 public:
29 enum OPL_WRITEBUF_SIZE = 1024;
30 enum OPL_WRITEBUF_DELAY = 2;
33 // ////////////////////////////////////////////////////////////////////////// //
34 version(genmidi_dumper) import iv.strex;
37 // ////////////////////////////////////////////////////////////////////////// //
38 private:
39 enum OPL_RATE = 49716;
41 struct OPL3Slot {
42 OPL3Channel* channel;
43 OPL3Chip* chip;
44 short out_;
45 short fbmod;
46 short* mod;
47 short prout;
48 short eg_rout;
49 short eg_out;
50 ubyte eg_inc;
51 ubyte eg_gen;
52 ubyte eg_rate;
53 ubyte eg_ksl;
54 ubyte *trem;
55 ubyte reg_vib;
56 ubyte reg_type;
57 ubyte reg_ksr;
58 ubyte reg_mult;
59 ubyte reg_ksl;
60 ubyte reg_tl;
61 ubyte reg_ar;
62 ubyte reg_dr;
63 ubyte reg_sl;
64 ubyte reg_rr;
65 ubyte reg_wf;
66 ubyte key;
67 uint pg_phase;
68 uint timer;
71 struct OPL3Channel {
72 OPL3Slot*[2] slots;
73 OPL3Channel* pair;
74 OPL3Chip* chip;
75 short*[4] out_;
76 ubyte chtype;
77 ushort f_num;
78 ubyte block;
79 ubyte fb;
80 ubyte con;
81 ubyte alg;
82 ubyte ksv;
83 ushort cha, chb;
86 struct OPL3WriteBuf {
87 ulong time;
88 ushort reg;
89 ubyte data;
92 ///
93 public struct OPL3Chip {
94 private:
95 OPL3Channel[18] channel;
96 OPL3Slot[36] slot;
97 ushort timer;
98 ubyte newm;
99 ubyte nts;
100 ubyte rhy;
101 ubyte vibpos;
102 ubyte vibshift;
103 ubyte tremolo;
104 ubyte tremolopos;
105 ubyte tremoloshift;
106 uint noise;
107 short zeromod;
108 int[2] mixbuff;
109 //OPL3L
110 int rateratio;
111 int samplecnt;
112 short[2] oldsamples;
113 short[2] samples;
115 ulong writebuf_samplecnt;
116 uint writebuf_cur;
117 uint writebuf_last;
118 ulong writebuf_lasttime;
119 OPL3WriteBuf[OPL_WRITEBUF_SIZE] writebuf;
123 private:
124 enum RSM_FRAC = 10;
126 // Channel types
128 enum {
129 ch_2op = 0,
130 ch_4op = 1,
131 ch_4op2 = 2,
132 ch_drum = 3
135 // Envelope key types
137 enum {
138 egk_norm = 0x01,
139 egk_drum = 0x02
144 // logsin table
147 static immutable ushort[256] logsinrom = [
148 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471,
149 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365,
150 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd,
151 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261,
152 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f,
153 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd,
154 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195,
155 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166,
156 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c,
157 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118,
158 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8,
159 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db,
160 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1,
161 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9,
162 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094,
163 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081,
164 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070,
165 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060,
166 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052,
167 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045,
168 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039,
169 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f,
170 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026,
171 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e,
172 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017,
173 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011,
174 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c,
175 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007,
176 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004,
177 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002,
178 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
179 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
183 // exp table
186 static immutable ushort[256] exprom = [
187 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014,
188 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a,
189 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042,
190 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a,
191 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072,
192 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b,
193 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4,
194 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be,
195 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9,
196 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4,
197 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110,
198 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c,
199 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149,
200 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167,
201 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185,
202 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4,
203 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4,
204 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4,
205 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205,
206 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227,
207 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249,
208 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d,
209 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291,
210 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5,
211 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db,
212 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302,
213 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329,
214 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351,
215 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a,
216 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4,
217 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf,
218 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa
222 // freq mult table multiplied by 2
224 // 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15
227 static immutable ubyte[16] mt = [
228 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
232 // ksl table
235 static immutable ubyte[16] kslrom = [
236 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
239 static immutable ubyte[4] kslshift = [
240 8, 1, 2, 0
244 // envelope generator constants
247 static immutable ubyte[8][4][3] eg_incstep = [
249 [ 0, 0, 0, 0, 0, 0, 0, 0 ],
250 [ 0, 0, 0, 0, 0, 0, 0, 0 ],
251 [ 0, 0, 0, 0, 0, 0, 0, 0 ],
252 [ 0, 0, 0, 0, 0, 0, 0, 0 ]
255 [ 0, 1, 0, 1, 0, 1, 0, 1 ],
256 [ 0, 1, 0, 1, 1, 1, 0, 1 ],
257 [ 0, 1, 1, 1, 0, 1, 1, 1 ],
258 [ 0, 1, 1, 1, 1, 1, 1, 1 ]
261 [ 1, 1, 1, 1, 1, 1, 1, 1 ],
262 [ 2, 2, 1, 1, 1, 1, 1, 1 ],
263 [ 2, 2, 1, 1, 2, 2, 1, 1 ],
264 [ 2, 2, 2, 2, 2, 2, 1, 1 ]
268 static immutable ubyte[16] eg_incdesc = [
269 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2
272 static immutable byte[16] eg_incsh = [
273 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2
277 // address decoding
280 static immutable byte[0x20] ad_slot = [
281 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1,
282 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
285 static immutable ubyte[18] ch_slot = [
286 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32
290 // Envelope generator
293 alias envelope_sinfunc = short function (ushort phase, ushort envelope) nothrow @trusted @nogc;
294 alias envelope_genfunc = void function (OPL3Slot *slott) nothrow @trusted @nogc;
296 private short OPL3_EnvelopeCalcExp (uint level) {
297 if (level > 0x1fff) level = 0x1fff;
298 return cast(short)(((exprom.ptr[(level&0xff)^0xff]|0x400)<<1)>>(level>>8));
301 private short OPL3_EnvelopeCalcSin0 (ushort phase, ushort envelope) {
302 ushort out_ = 0;
303 ushort neg = 0;
304 phase &= 0x3ff;
305 if (phase&0x200) neg = ushort.max;
306 if (phase&0x100) out_ = logsinrom.ptr[(phase&0xff)^0xff]; else out_ = logsinrom.ptr[phase&0xff];
307 return OPL3_EnvelopeCalcExp(out_+(envelope<<3))^neg;
310 private short OPL3_EnvelopeCalcSin1 (ushort phase, ushort envelope) {
311 ushort out_ = 0;
312 phase &= 0x3ff;
313 if (phase&0x200) out_ = 0x1000;
314 else if (phase&0x100) out_ = logsinrom.ptr[(phase&0xff)^0xff];
315 else out_ = logsinrom.ptr[phase&0xff];
316 return OPL3_EnvelopeCalcExp(out_+(envelope<<3));
319 private short OPL3_EnvelopeCalcSin2 (ushort phase, ushort envelope) {
320 ushort out_ = 0;
321 phase &= 0x3ff;
322 if (phase&0x100) out_ = logsinrom.ptr[(phase&0xff)^0xff]; else out_ = logsinrom.ptr[phase&0xff];
323 return OPL3_EnvelopeCalcExp(out_+(envelope<<3));
326 private short OPL3_EnvelopeCalcSin3 (ushort phase, ushort envelope) {
327 ushort out_ = 0;
328 phase &= 0x3ff;
329 if (phase&0x100) out_ = 0x1000; else out_ = logsinrom.ptr[phase&0xff];
330 return OPL3_EnvelopeCalcExp(out_+(envelope<<3));
333 private short OPL3_EnvelopeCalcSin4 (ushort phase, ushort envelope) {
334 ushort out_ = 0;
335 ushort neg = 0;
336 phase &= 0x3ff;
337 if ((phase&0x300) == 0x100) neg = ushort.max;
338 if (phase&0x200) out_ = 0x1000;
339 else if (phase&0x80) out_ = logsinrom.ptr[((phase^0xff)<<1)&0xff];
340 else out_ = logsinrom.ptr[(phase<<1)&0xff];
341 return OPL3_EnvelopeCalcExp(out_+(envelope<<3))^neg;
344 private short OPL3_EnvelopeCalcSin5 (ushort phase, ushort envelope) {
345 ushort out_ = 0;
346 phase &= 0x3ff;
347 if (phase&0x200) out_ = 0x1000;
348 else if (phase&0x80) out_ = logsinrom.ptr[((phase^0xff)<<1)&0xff];
349 else out_ = logsinrom.ptr[(phase<<1)&0xff];
350 return OPL3_EnvelopeCalcExp(out_+(envelope<<3));
353 private short OPL3_EnvelopeCalcSin6 (ushort phase, ushort envelope) {
354 ushort neg = 0;
355 phase &= 0x3ff;
356 if (phase&0x200) neg = ushort.max;
357 return OPL3_EnvelopeCalcExp(envelope<<3)^neg;
360 private short OPL3_EnvelopeCalcSin7 (ushort phase, ushort envelope) {
361 ushort out_ = 0;
362 ushort neg = 0;
363 phase &= 0x3ff;
364 if (phase&0x200) {
365 neg = ushort.max;
366 phase = (phase&0x1ff)^0x1ff;
368 out_ = cast(ushort)(phase<<3);
369 return OPL3_EnvelopeCalcExp(out_+(envelope<<3))^neg;
372 static immutable envelope_sinfunc[8] envelope_sin = [
373 &OPL3_EnvelopeCalcSin0,
374 &OPL3_EnvelopeCalcSin1,
375 &OPL3_EnvelopeCalcSin2,
376 &OPL3_EnvelopeCalcSin3,
377 &OPL3_EnvelopeCalcSin4,
378 &OPL3_EnvelopeCalcSin5,
379 &OPL3_EnvelopeCalcSin6,
380 &OPL3_EnvelopeCalcSin7
383 static immutable envelope_genfunc[5] envelope_gen = [
384 &OPL3_EnvelopeGenOff,
385 &OPL3_EnvelopeGenAttack,
386 &OPL3_EnvelopeGenDecay,
387 &OPL3_EnvelopeGenSustain,
388 &OPL3_EnvelopeGenRelease
391 alias envelope_gen_num = int;
392 enum /*envelope_gen_num*/:int {
393 envelope_gen_num_off = 0,
394 envelope_gen_num_attack = 1,
395 envelope_gen_num_decay = 2,
396 envelope_gen_num_sustain = 3,
397 envelope_gen_num_release = 4
400 private ubyte OPL3_EnvelopeCalcRate (OPL3Slot* slot, ubyte reg_rate) {
401 if (reg_rate == 0x00) return 0x00;
402 ubyte rate = cast(ubyte)((reg_rate<<2)+(slot.reg_ksr ? slot.channel.ksv : (slot.channel.ksv>>2)));
403 if (rate > 0x3c) rate = 0x3c;
404 return rate;
407 private void OPL3_EnvelopeUpdateKSL (OPL3Slot* slot) {
408 short ksl = (kslrom.ptr[slot.channel.f_num>>6]<<2)-((0x08-slot.channel.block)<<5);
409 if (ksl < 0) ksl = 0;
410 slot.eg_ksl = cast(ubyte)ksl;
413 private void OPL3_EnvelopeUpdateRate (OPL3Slot* slot) {
414 switch (slot.eg_gen) {
415 case envelope_gen_num_off:
416 case envelope_gen_num_attack:
417 slot.eg_rate = OPL3_EnvelopeCalcRate(slot, slot.reg_ar);
418 break;
419 case envelope_gen_num_decay:
420 slot.eg_rate = OPL3_EnvelopeCalcRate(slot, slot.reg_dr);
421 break;
422 case envelope_gen_num_sustain:
423 case envelope_gen_num_release:
424 slot.eg_rate = OPL3_EnvelopeCalcRate(slot, slot.reg_rr);
425 break;
426 default: break;
430 private void OPL3_EnvelopeGenOff (OPL3Slot* slot) {
431 slot.eg_rout = 0x1ff;
434 private void OPL3_EnvelopeGenAttack (OPL3Slot* slot) {
435 if (slot.eg_rout == 0x00) {
436 slot.eg_gen = envelope_gen_num_decay;
437 OPL3_EnvelopeUpdateRate(slot);
438 } else {
439 slot.eg_rout += ((~cast(uint)slot.eg_rout)*slot.eg_inc)>>3;
440 if (slot.eg_rout < 0x00) slot.eg_rout = 0x00;
444 private void OPL3_EnvelopeGenDecay (OPL3Slot* slot) {
445 if (slot.eg_rout >= slot.reg_sl<<4) {
446 slot.eg_gen = envelope_gen_num_sustain;
447 OPL3_EnvelopeUpdateRate(slot);
448 } else {
449 slot.eg_rout += slot.eg_inc;
453 private void OPL3_EnvelopeGenSustain (OPL3Slot* slot) {
454 if (!slot.reg_type) OPL3_EnvelopeGenRelease(slot);
457 private void OPL3_EnvelopeGenRelease (OPL3Slot* slot) {
458 if (slot.eg_rout >= 0x1ff) {
459 slot.eg_gen = envelope_gen_num_off;
460 slot.eg_rout = 0x1ff;
461 OPL3_EnvelopeUpdateRate(slot);
462 } else {
463 slot.eg_rout += slot.eg_inc;
467 private void OPL3_EnvelopeCalc (OPL3Slot* slot) {
468 ubyte rate_h, rate_l;
469 ubyte inc = 0;
470 rate_h = slot.eg_rate>>2;
471 rate_l = slot.eg_rate&3;
472 if (eg_incsh.ptr[rate_h] > 0) {
473 if ((slot.chip.timer&((1<<eg_incsh.ptr[rate_h])-1)) == 0) {
474 inc = eg_incstep.ptr[eg_incdesc.ptr[rate_h]].ptr[rate_l].ptr[((slot.chip.timer)>> eg_incsh.ptr[rate_h])&0x07];
476 } else {
477 inc = cast(ubyte)(eg_incstep.ptr[eg_incdesc.ptr[rate_h]].ptr[rate_l].ptr[slot.chip.timer&0x07]<<(-(eg_incsh.ptr[rate_h])));
479 slot.eg_inc = inc;
480 slot.eg_out = cast(short)(slot.eg_rout+(slot.reg_tl<<2)+(slot.eg_ksl>>kslshift.ptr[slot.reg_ksl])+*slot.trem);
481 envelope_gen[slot.eg_gen](slot);
484 private void OPL3_EnvelopeKeyOn (OPL3Slot* slot, ubyte type) {
485 if (!slot.key) {
486 slot.eg_gen = envelope_gen_num_attack;
487 OPL3_EnvelopeUpdateRate(slot);
488 if ((slot.eg_rate>>2) == 0x0f) {
489 slot.eg_gen = envelope_gen_num_decay;
490 OPL3_EnvelopeUpdateRate(slot);
491 slot.eg_rout = 0x00;
493 slot.pg_phase = 0x00;
495 slot.key |= type;
498 private void OPL3_EnvelopeKeyOff (OPL3Slot* slot, ubyte type) {
499 if (slot.key) {
500 slot.key &= (~cast(uint)type);
501 if (!slot.key) {
502 slot.eg_gen = envelope_gen_num_release;
503 OPL3_EnvelopeUpdateRate(slot);
509 // Phase Generator
512 private void OPL3_PhaseGenerate (OPL3Slot* slot) {
513 ushort f_num;
514 uint basefreq;
516 f_num = slot.channel.f_num;
517 if (slot.reg_vib) {
518 byte range;
519 ubyte vibpos;
521 range = (f_num>>7)&7;
522 vibpos = slot.chip.vibpos;
524 if (!(vibpos&3)) range = 0;
525 else if (vibpos&1) range >>= 1;
526 range >>= slot.chip.vibshift;
528 if (vibpos&4) range = -(range);
529 f_num += range;
531 basefreq = (f_num<<slot.channel.block)>>1;
532 slot.pg_phase += (basefreq*mt.ptr[slot.reg_mult])>>1;
536 // Noise Generator
539 private void OPL3_NoiseGenerate (OPL3Chip* chip) {
540 if (chip.noise&0x01) chip.noise ^= 0x800302;
541 chip.noise >>= 1;
545 // Slot
548 private void OPL3_SlotWrite20 (OPL3Slot* slot, ubyte data) {
549 slot.trem = ((data>>7)&0x01 ? &slot.chip.tremolo : cast(ubyte*)&slot.chip.zeromod);
550 slot.reg_vib = (data>>6)&0x01;
551 slot.reg_type = (data>>5)&0x01;
552 slot.reg_ksr = (data>>4)&0x01;
553 slot.reg_mult = data&0x0f;
554 OPL3_EnvelopeUpdateRate(slot);
557 private void OPL3_SlotWrite40 (OPL3Slot* slot, ubyte data) {
558 slot.reg_ksl = (data>>6)&0x03;
559 slot.reg_tl = data&0x3f;
560 OPL3_EnvelopeUpdateKSL(slot);
563 private void OPL3_SlotWrite60 (OPL3Slot* slot, ubyte data) {
564 slot.reg_ar = (data>>4)&0x0f;
565 slot.reg_dr = data&0x0f;
566 OPL3_EnvelopeUpdateRate(slot);
569 private void OPL3_SlotWrite80 (OPL3Slot* slot, ubyte data) {
570 slot.reg_sl = (data>>4)&0x0f;
571 if (slot.reg_sl == 0x0f) slot.reg_sl = 0x1f;
572 slot.reg_rr = data&0x0f;
573 OPL3_EnvelopeUpdateRate(slot);
576 private void OPL3_SlotWriteE0 (OPL3Slot* slot, ubyte data) {
577 slot.reg_wf = data&0x07;
578 if (slot.chip.newm == 0x00) slot.reg_wf &= 0x03;
581 private void OPL3_SlotGeneratePhase (OPL3Slot* slot, ushort phase) {
582 slot.out_ = envelope_sin[slot.reg_wf](phase, slot.eg_out);
585 private void OPL3_SlotGenerate (OPL3Slot* slot) {
586 OPL3_SlotGeneratePhase(slot, cast(ushort)(cast(ushort)(slot.pg_phase>>9)+*slot.mod));
589 private void OPL3_SlotGenerateZM (OPL3Slot* slot) {
590 OPL3_SlotGeneratePhase(slot, cast(ushort)(slot.pg_phase>>9));
593 private void OPL3_SlotCalcFB (OPL3Slot* slot) {
594 slot.fbmod = (slot.channel.fb != 0x00 ? cast(short)((slot.prout+slot.out_)>>(0x09-slot.channel.fb)) : 0);
595 slot.prout = slot.out_;
599 // Channel
602 private void OPL3_ChannelUpdateRhythm (OPL3Chip* chip, ubyte data) {
603 OPL3Channel* channel6;
604 OPL3Channel* channel7;
605 OPL3Channel* channel8;
606 ubyte chnum;
608 chip.rhy = data&0x3f;
609 if (chip.rhy&0x20) {
610 channel6 = &chip.channel.ptr[6];
611 channel7 = &chip.channel.ptr[7];
612 channel8 = &chip.channel.ptr[8];
613 channel6.out_.ptr[0] = &channel6.slots.ptr[1].out_;
614 channel6.out_.ptr[1] = &channel6.slots.ptr[1].out_;
615 channel6.out_.ptr[2] = &chip.zeromod;
616 channel6.out_.ptr[3] = &chip.zeromod;
617 channel7.out_.ptr[0] = &channel7.slots.ptr[0].out_;
618 channel7.out_.ptr[1] = &channel7.slots.ptr[0].out_;
619 channel7.out_.ptr[2] = &channel7.slots.ptr[1].out_;
620 channel7.out_.ptr[3] = &channel7.slots.ptr[1].out_;
621 channel8.out_.ptr[0] = &channel8.slots.ptr[0].out_;
622 channel8.out_.ptr[1] = &channel8.slots.ptr[0].out_;
623 channel8.out_.ptr[2] = &channel8.slots.ptr[1].out_;
624 channel8.out_.ptr[3] = &channel8.slots.ptr[1].out_;
625 for (chnum = 6; chnum < 9; ++chnum) chip.channel.ptr[chnum].chtype = ch_drum;
626 OPL3_ChannelSetupAlg(channel6);
627 //hh
628 if (chip.rhy&0x01) {
629 OPL3_EnvelopeKeyOn(channel7.slots.ptr[0], egk_drum);
630 } else {
631 OPL3_EnvelopeKeyOff(channel7.slots.ptr[0], egk_drum);
633 //tc
634 if (chip.rhy&0x02) {
635 OPL3_EnvelopeKeyOn(channel8.slots.ptr[1], egk_drum);
636 } else {
637 OPL3_EnvelopeKeyOff(channel8.slots.ptr[1], egk_drum);
639 //tom
640 if (chip.rhy&0x04) {
641 OPL3_EnvelopeKeyOn(channel8.slots.ptr[0], egk_drum);
642 } else {
643 OPL3_EnvelopeKeyOff(channel8.slots.ptr[0], egk_drum);
645 //sd
646 if (chip.rhy&0x08) {
647 OPL3_EnvelopeKeyOn(channel7.slots.ptr[1], egk_drum);
648 } else {
649 OPL3_EnvelopeKeyOff(channel7.slots.ptr[1], egk_drum);
651 //bd
652 if (chip.rhy&0x10) {
653 OPL3_EnvelopeKeyOn(channel6.slots.ptr[0], egk_drum);
654 OPL3_EnvelopeKeyOn(channel6.slots.ptr[1], egk_drum);
655 } else {
656 OPL3_EnvelopeKeyOff(channel6.slots.ptr[0], egk_drum);
657 OPL3_EnvelopeKeyOff(channel6.slots.ptr[1], egk_drum);
659 } else {
660 for (chnum = 6; chnum < 9; ++chnum) {
661 chip.channel.ptr[chnum].chtype = ch_2op;
662 OPL3_ChannelSetupAlg(&chip.channel.ptr[chnum]);
663 OPL3_EnvelopeKeyOff(chip.channel.ptr[chnum].slots.ptr[0], egk_drum);
664 OPL3_EnvelopeKeyOff(chip.channel.ptr[chnum].slots.ptr[1], egk_drum);
669 private void OPL3_ChannelWriteA0 (OPL3Channel* channel, ubyte data) {
670 if (channel.chip.newm && channel.chtype == ch_4op2) return;
671 channel.f_num = (channel.f_num&0x300)|data;
672 channel.ksv = cast(ubyte)((channel.block<<1)|((channel.f_num>>(0x09-channel.chip.nts))&0x01));
673 OPL3_EnvelopeUpdateKSL(channel.slots.ptr[0]);
674 OPL3_EnvelopeUpdateKSL(channel.slots.ptr[1]);
675 OPL3_EnvelopeUpdateRate(channel.slots.ptr[0]);
676 OPL3_EnvelopeUpdateRate(channel.slots.ptr[1]);
677 if (channel.chip.newm && channel.chtype == ch_4op) {
678 channel.pair.f_num = channel.f_num;
679 channel.pair.ksv = channel.ksv;
680 OPL3_EnvelopeUpdateKSL(channel.pair.slots.ptr[0]);
681 OPL3_EnvelopeUpdateKSL(channel.pair.slots.ptr[1]);
682 OPL3_EnvelopeUpdateRate(channel.pair.slots.ptr[0]);
683 OPL3_EnvelopeUpdateRate(channel.pair.slots.ptr[1]);
687 private void OPL3_ChannelWriteB0 (OPL3Channel* channel, ubyte data) {
688 if (channel.chip.newm && channel.chtype == ch_4op2) return;
689 channel.f_num = (channel.f_num&0xff)|((data&0x03)<<8);
690 channel.block = (data>>2)&0x07;
691 channel.ksv = cast(ubyte)((channel.block<<1)|((channel.f_num>>(0x09-channel.chip.nts))&0x01));
692 OPL3_EnvelopeUpdateKSL(channel.slots.ptr[0]);
693 OPL3_EnvelopeUpdateKSL(channel.slots.ptr[1]);
694 OPL3_EnvelopeUpdateRate(channel.slots.ptr[0]);
695 OPL3_EnvelopeUpdateRate(channel.slots.ptr[1]);
696 if (channel.chip.newm && channel.chtype == ch_4op) {
697 channel.pair.f_num = channel.f_num;
698 channel.pair.block = channel.block;
699 channel.pair.ksv = channel.ksv;
700 OPL3_EnvelopeUpdateKSL(channel.pair.slots.ptr[0]);
701 OPL3_EnvelopeUpdateKSL(channel.pair.slots.ptr[1]);
702 OPL3_EnvelopeUpdateRate(channel.pair.slots.ptr[0]);
703 OPL3_EnvelopeUpdateRate(channel.pair.slots.ptr[1]);
707 private void OPL3_ChannelSetupAlg (OPL3Channel* channel) {
708 if (channel.chtype == ch_drum) {
709 final switch (channel.alg&0x01) {
710 case 0x00:
711 channel.slots.ptr[0].mod = &channel.slots.ptr[0].fbmod;
712 channel.slots.ptr[1].mod = &channel.slots.ptr[0].out_;
713 break;
714 case 0x01:
715 channel.slots.ptr[0].mod = &channel.slots.ptr[0].fbmod;
716 channel.slots.ptr[1].mod = &channel.chip.zeromod;
717 break;
719 return;
721 if (channel.alg&0x08) return;
722 if (channel.alg&0x04) {
723 channel.pair.out_.ptr[0] = &channel.chip.zeromod;
724 channel.pair.out_.ptr[1] = &channel.chip.zeromod;
725 channel.pair.out_.ptr[2] = &channel.chip.zeromod;
726 channel.pair.out_.ptr[3] = &channel.chip.zeromod;
727 final switch (channel.alg&0x03) {
728 case 0x00:
729 channel.pair.slots.ptr[0].mod = &channel.pair.slots.ptr[0].fbmod;
730 channel.pair.slots.ptr[1].mod = &channel.pair.slots.ptr[0].out_;
731 channel.slots.ptr[0].mod = &channel.pair.slots.ptr[1].out_;
732 channel.slots.ptr[1].mod = &channel.slots.ptr[0].out_;
733 channel.out_.ptr[0] = &channel.slots.ptr[1].out_;
734 channel.out_.ptr[1] = &channel.chip.zeromod;
735 channel.out_.ptr[2] = &channel.chip.zeromod;
736 channel.out_.ptr[3] = &channel.chip.zeromod;
737 break;
738 case 0x01:
739 channel.pair.slots.ptr[0].mod = &channel.pair.slots.ptr[0].fbmod;
740 channel.pair.slots.ptr[1].mod = &channel.pair.slots.ptr[0].out_;
741 channel.slots.ptr[0].mod = &channel.chip.zeromod;
742 channel.slots.ptr[1].mod = &channel.slots.ptr[0].out_;
743 channel.out_.ptr[0] = &channel.pair.slots.ptr[1].out_;
744 channel.out_.ptr[1] = &channel.slots.ptr[1].out_;
745 channel.out_.ptr[2] = &channel.chip.zeromod;
746 channel.out_.ptr[3] = &channel.chip.zeromod;
747 break;
748 case 0x02:
749 channel.pair.slots.ptr[0].mod = &channel.pair.slots.ptr[0].fbmod;
750 channel.pair.slots.ptr[1].mod = &channel.chip.zeromod;
751 channel.slots.ptr[0].mod = &channel.pair.slots.ptr[1].out_;
752 channel.slots.ptr[1].mod = &channel.slots.ptr[0].out_;
753 channel.out_.ptr[0] = &channel.pair.slots.ptr[0].out_;
754 channel.out_.ptr[1] = &channel.slots.ptr[1].out_;
755 channel.out_.ptr[2] = &channel.chip.zeromod;
756 channel.out_.ptr[3] = &channel.chip.zeromod;
757 break;
758 case 0x03:
759 channel.pair.slots.ptr[0].mod = &channel.pair.slots.ptr[0].fbmod;
760 channel.pair.slots.ptr[1].mod = &channel.chip.zeromod;
761 channel.slots.ptr[0].mod = &channel.pair.slots.ptr[1].out_;
762 channel.slots.ptr[1].mod = &channel.chip.zeromod;
763 channel.out_.ptr[0] = &channel.pair.slots.ptr[0].out_;
764 channel.out_.ptr[1] = &channel.slots.ptr[0].out_;
765 channel.out_.ptr[2] = &channel.slots.ptr[1].out_;
766 channel.out_.ptr[3] = &channel.chip.zeromod;
767 break;
769 } else {
770 final switch (channel.alg&0x01) {
771 case 0x00:
772 channel.slots.ptr[0].mod = &channel.slots.ptr[0].fbmod;
773 channel.slots.ptr[1].mod = &channel.slots.ptr[0].out_;
774 channel.out_.ptr[0] = &channel.slots.ptr[1].out_;
775 channel.out_.ptr[1] = &channel.chip.zeromod;
776 channel.out_.ptr[2] = &channel.chip.zeromod;
777 channel.out_.ptr[3] = &channel.chip.zeromod;
778 break;
779 case 0x01:
780 channel.slots.ptr[0].mod = &channel.slots.ptr[0].fbmod;
781 channel.slots.ptr[1].mod = &channel.chip.zeromod;
782 channel.out_.ptr[0] = &channel.slots.ptr[0].out_;
783 channel.out_.ptr[1] = &channel.slots.ptr[1].out_;
784 channel.out_.ptr[2] = &channel.chip.zeromod;
785 channel.out_.ptr[3] = &channel.chip.zeromod;
786 break;
791 private void OPL3_ChannelWriteC0 (OPL3Channel* channel, ubyte data) {
792 channel.fb = (data&0x0e)>>1;
793 channel.con = data&0x01;
794 channel.alg = channel.con;
795 if (channel.chip.newm) {
796 if (channel.chtype == ch_4op) {
797 channel.pair.alg = cast(ubyte)(0x04|(channel.con<<1)|(channel.pair.con));
798 channel.alg = 0x08;
799 OPL3_ChannelSetupAlg(channel.pair);
800 } else if (channel.chtype == ch_4op2) {
801 channel.alg = cast(ubyte)(0x04|(channel.pair.con<<1)|(channel.con));
802 channel.pair.alg = 0x08;
803 OPL3_ChannelSetupAlg(channel);
804 } else {
805 OPL3_ChannelSetupAlg(channel);
807 } else {
808 OPL3_ChannelSetupAlg(channel);
810 if (channel.chip.newm) {
811 channel.cha = ((data>>4)&0x01 ? ushort.max : 0);
812 channel.chb = ((data>>5)&0x01 ? ushort.max : 0);
813 } else {
814 channel.cha = channel.chb = ushort.max;
818 private void OPL3_ChannelKeyOn (OPL3Channel* channel) {
819 if (channel.chip.newm) {
820 if (channel.chtype == ch_4op) {
821 OPL3_EnvelopeKeyOn(channel.slots.ptr[0], egk_norm);
822 OPL3_EnvelopeKeyOn(channel.slots.ptr[1], egk_norm);
823 OPL3_EnvelopeKeyOn(channel.pair.slots.ptr[0], egk_norm);
824 OPL3_EnvelopeKeyOn(channel.pair.slots.ptr[1], egk_norm);
825 } else if (channel.chtype == ch_2op || channel.chtype == ch_drum) {
826 OPL3_EnvelopeKeyOn(channel.slots.ptr[0], egk_norm);
827 OPL3_EnvelopeKeyOn(channel.slots.ptr[1], egk_norm);
829 } else {
830 OPL3_EnvelopeKeyOn(channel.slots.ptr[0], egk_norm);
831 OPL3_EnvelopeKeyOn(channel.slots.ptr[1], egk_norm);
835 private void OPL3_ChannelKeyOff (OPL3Channel* channel) {
836 if (channel.chip.newm) {
837 if (channel.chtype == ch_4op) {
838 OPL3_EnvelopeKeyOff(channel.slots.ptr[0], egk_norm);
839 OPL3_EnvelopeKeyOff(channel.slots.ptr[1], egk_norm);
840 OPL3_EnvelopeKeyOff(channel.pair.slots.ptr[0], egk_norm);
841 OPL3_EnvelopeKeyOff(channel.pair.slots.ptr[1], egk_norm);
842 } else if (channel.chtype == ch_2op || channel.chtype == ch_drum) {
843 OPL3_EnvelopeKeyOff(channel.slots.ptr[0], egk_norm);
844 OPL3_EnvelopeKeyOff(channel.slots.ptr[1], egk_norm);
846 } else {
847 OPL3_EnvelopeKeyOff(channel.slots.ptr[0], egk_norm);
848 OPL3_EnvelopeKeyOff(channel.slots.ptr[1], egk_norm);
852 private void OPL3_ChannelSet4Op (OPL3Chip* chip, ubyte data) {
853 ubyte bit;
854 ubyte chnum;
855 for (bit = 0; bit < 6; ++bit) {
856 chnum = bit;
857 if (bit >= 3) chnum += 9-3;
858 if ((data>>bit)&0x01) {
859 chip.channel.ptr[chnum].chtype = ch_4op;
860 chip.channel.ptr[chnum+3].chtype = ch_4op2;
861 } else {
862 chip.channel.ptr[chnum].chtype = ch_2op;
863 chip.channel.ptr[chnum+3].chtype = ch_2op;
868 private short OPL3_ClipSample (int sample) pure {
869 pragma(inline, true);
870 if (sample > 32767) sample = 32767;
871 else if (sample < -32768) sample = -32768;
872 return cast(short)sample;
875 private void OPL3_GenerateRhythm1 (OPL3Chip* chip) {
876 OPL3Channel* channel6;
877 OPL3Channel* channel7;
878 OPL3Channel* channel8;
879 ushort phase14;
880 ushort phase17;
881 ushort phase;
882 ushort phasebit;
884 channel6 = &chip.channel.ptr[6];
885 channel7 = &chip.channel.ptr[7];
886 channel8 = &chip.channel.ptr[8];
887 OPL3_SlotGenerate(channel6.slots.ptr[0]);
888 phase14 = (channel7.slots.ptr[0].pg_phase>>9)&0x3ff;
889 phase17 = (channel8.slots.ptr[1].pg_phase>>9)&0x3ff;
890 phase = 0x00;
891 //hh tc phase bit
892 phasebit = ((phase14&0x08)|(((phase14>>5)^phase14)&0x04)|(((phase17>>2)^phase17)&0x08)) ? 0x01 : 0x00;
893 //hh
894 phase = cast(ushort)((phasebit<<9)|(0x34<<((phasebit^(chip.noise&0x01))<<1)));
895 OPL3_SlotGeneratePhase(channel7.slots.ptr[0], phase);
896 //tt
897 OPL3_SlotGenerateZM(channel8.slots.ptr[0]);
900 private void OPL3_GenerateRhythm2 (OPL3Chip* chip) {
901 OPL3Channel* channel6;
902 OPL3Channel* channel7;
903 OPL3Channel* channel8;
904 ushort phase14;
905 ushort phase17;
906 ushort phase;
907 ushort phasebit;
909 channel6 = &chip.channel.ptr[6];
910 channel7 = &chip.channel.ptr[7];
911 channel8 = &chip.channel.ptr[8];
912 OPL3_SlotGenerate(channel6.slots.ptr[1]);
913 phase14 = (channel7.slots.ptr[0].pg_phase>>9)&0x3ff;
914 phase17 = (channel8.slots.ptr[1].pg_phase>>9)&0x3ff;
915 phase = 0x00;
916 //hh tc phase bit
917 phasebit = ((phase14&0x08)|(((phase14>>5)^phase14)&0x04)|(((phase17>>2)^phase17)&0x08)) ? 0x01 : 0x00;
918 //sd
919 phase = (0x100<<((phase14>>8)&0x01))^((chip.noise&0x01)<<8);
920 OPL3_SlotGeneratePhase(channel7.slots.ptr[1], phase);
921 //tc
922 phase = cast(ushort)(0x100|(phasebit<<9));
923 OPL3_SlotGeneratePhase(channel8.slots.ptr[1], phase);
927 // ////////////////////////////////////////////////////////////////////////// //
928 /// OPL3_Generate
929 public void generate (ref OPL3Chip chip, short* buf) {
930 ubyte ii;
931 ubyte jj;
932 short accm;
934 buf[1] = OPL3_ClipSample(chip.mixbuff.ptr[1]);
936 for (ii = 0; ii < 12; ++ii) {
937 OPL3_SlotCalcFB(&chip.slot.ptr[ii]);
938 OPL3_PhaseGenerate(&chip.slot.ptr[ii]);
939 OPL3_EnvelopeCalc(&chip.slot.ptr[ii]);
940 OPL3_SlotGenerate(&chip.slot.ptr[ii]);
943 for (ii = 12; ii < 15; ++ii) {
944 OPL3_SlotCalcFB(&chip.slot.ptr[ii]);
945 OPL3_PhaseGenerate(&chip.slot.ptr[ii]);
946 OPL3_EnvelopeCalc(&chip.slot.ptr[ii]);
949 if (chip.rhy&0x20) {
950 OPL3_GenerateRhythm1(&chip);
951 } else {
952 OPL3_SlotGenerate(&chip.slot.ptr[12]);
953 OPL3_SlotGenerate(&chip.slot.ptr[13]);
954 OPL3_SlotGenerate(&chip.slot.ptr[14]);
957 chip.mixbuff.ptr[0] = 0;
958 for (ii = 0; ii < 18; ++ii) {
959 accm = 0;
960 for (jj = 0; jj < 4; ++jj) accm += *chip.channel.ptr[ii].out_.ptr[jj];
961 chip.mixbuff.ptr[0] += cast(short)(accm&chip.channel.ptr[ii].cha);
964 for (ii = 15; ii < 18; ++ii) {
965 OPL3_SlotCalcFB(&chip.slot.ptr[ii]);
966 OPL3_PhaseGenerate(&chip.slot.ptr[ii]);
967 OPL3_EnvelopeCalc(&chip.slot.ptr[ii]);
970 if (chip.rhy&0x20) {
971 OPL3_GenerateRhythm2(&chip);
972 } else {
973 OPL3_SlotGenerate(&chip.slot.ptr[15]);
974 OPL3_SlotGenerate(&chip.slot.ptr[16]);
975 OPL3_SlotGenerate(&chip.slot.ptr[17]);
978 buf[0] = OPL3_ClipSample(chip.mixbuff.ptr[0]);
980 for (ii = 18; ii < 33; ++ii) {
981 OPL3_SlotCalcFB(&chip.slot.ptr[ii]);
982 OPL3_PhaseGenerate(&chip.slot.ptr[ii]);
983 OPL3_EnvelopeCalc(&chip.slot.ptr[ii]);
984 OPL3_SlotGenerate(&chip.slot.ptr[ii]);
987 chip.mixbuff.ptr[1] = 0;
988 for (ii = 0; ii < 18; ++ii) {
989 accm = 0;
990 for (jj = 0; jj < 4; jj++) accm += *chip.channel.ptr[ii].out_.ptr[jj];
991 chip.mixbuff.ptr[1] += cast(short)(accm&chip.channel.ptr[ii].chb);
994 for (ii = 33; ii < 36; ++ii) {
995 OPL3_SlotCalcFB(&chip.slot.ptr[ii]);
996 OPL3_PhaseGenerate(&chip.slot.ptr[ii]);
997 OPL3_EnvelopeCalc(&chip.slot.ptr[ii]);
998 OPL3_SlotGenerate(&chip.slot.ptr[ii]);
1001 OPL3_NoiseGenerate(&chip);
1003 if ((chip.timer&0x3f) == 0x3f) chip.tremolopos = (chip.tremolopos+1)%210;
1004 chip.tremolo = (chip.tremolopos < 105 ? chip.tremolopos>>chip.tremoloshift : cast(ubyte)((210-chip.tremolopos)>>chip.tremoloshift));
1005 if ((chip.timer&0x3ff) == 0x3ff) chip.vibpos = (chip.vibpos+1)&7;
1007 ++chip.timer;
1009 while (chip.writebuf.ptr[chip.writebuf_cur].time <= chip.writebuf_samplecnt) {
1010 if (!(chip.writebuf.ptr[chip.writebuf_cur].reg&0x200)) break;
1011 chip.writebuf.ptr[chip.writebuf_cur].reg &= 0x1ff;
1012 chip.writeReg(chip.writebuf.ptr[chip.writebuf_cur].reg, chip.writebuf.ptr[chip.writebuf_cur].data);
1013 chip.writebuf_cur = (chip.writebuf_cur+1)%OPL_WRITEBUF_SIZE;
1015 ++chip.writebuf_samplecnt;
1019 /// OPL3_GenerateResampled
1020 public void generateResampled (ref OPL3Chip chip, short* buf) {
1021 while (chip.samplecnt >= chip.rateratio) {
1022 chip.oldsamples.ptr[0] = chip.samples.ptr[0];
1023 chip.oldsamples.ptr[1] = chip.samples.ptr[1];
1024 chip.generate(chip.samples.ptr);
1025 chip.samplecnt -= chip.rateratio;
1027 buf[0] = cast(short)((chip.oldsamples.ptr[0]*(chip.rateratio-chip.samplecnt)+chip.samples.ptr[0]*chip.samplecnt)/chip.rateratio);
1028 buf[1] = cast(short)((chip.oldsamples.ptr[1]*(chip.rateratio-chip.samplecnt)+chip.samples.ptr[1]*chip.samplecnt)/chip.rateratio);
1029 chip.samplecnt += 1<<RSM_FRAC;
1033 /// OPL3_Reset
1034 public void reset (ref OPL3Chip chip, uint samplerate) {
1035 ubyte slotnum;
1036 ubyte channum;
1038 //ubyte* cc = cast(ubyte*)chip;
1039 //cc[0..OPL3Chip.sizeof] = 0;
1040 chip = chip.init;
1042 for (slotnum = 0; slotnum < 36; ++slotnum) {
1043 chip.slot.ptr[slotnum].chip = &chip;
1044 chip.slot.ptr[slotnum].mod = &chip.zeromod;
1045 chip.slot.ptr[slotnum].eg_rout = 0x1ff;
1046 chip.slot.ptr[slotnum].eg_out = 0x1ff;
1047 chip.slot.ptr[slotnum].eg_gen = envelope_gen_num_off;
1048 chip.slot.ptr[slotnum].trem = cast(ubyte*)&chip.zeromod;
1050 for (channum = 0; channum < 18; ++channum) {
1051 chip.channel.ptr[channum].slots.ptr[0] = &chip.slot.ptr[ch_slot.ptr[channum]];
1052 chip.channel.ptr[channum].slots.ptr[1] = &chip.slot.ptr[ch_slot.ptr[channum]+3];
1053 chip.slot.ptr[ch_slot.ptr[channum]].channel = &chip.channel.ptr[channum];
1054 chip.slot.ptr[ch_slot.ptr[channum]+3].channel = &chip.channel.ptr[channum];
1055 if ((channum%9) < 3) chip.channel.ptr[channum].pair = &chip.channel.ptr[channum+3];
1056 else if ((channum%9) < 6) chip.channel.ptr[channum].pair = &chip.channel.ptr[channum-3];
1057 chip.channel.ptr[channum].chip = &chip;
1058 chip.channel.ptr[channum].out_.ptr[0] = &chip.zeromod;
1059 chip.channel.ptr[channum].out_.ptr[1] = &chip.zeromod;
1060 chip.channel.ptr[channum].out_.ptr[2] = &chip.zeromod;
1061 chip.channel.ptr[channum].out_.ptr[3] = &chip.zeromod;
1062 chip.channel.ptr[channum].chtype = ch_2op;
1063 chip.channel.ptr[channum].cha = ushort.max;
1064 chip.channel.ptr[channum].chb = ushort.max;
1065 OPL3_ChannelSetupAlg(&chip.channel.ptr[channum]);
1067 chip.noise = 0x306600;
1068 chip.rateratio = (samplerate<<RSM_FRAC)/OPL_RATE;
1069 chip.tremoloshift = 4;
1070 chip.vibshift = 1;
1074 /// OPL3_WriteReg
1075 public void writeReg (ref OPL3Chip chip, ushort reg, ubyte v) {
1076 ubyte high = (reg>>8)&0x01;
1077 ubyte regm = reg&0xff;
1078 switch (regm&0xf0) {
1079 case 0x00:
1080 if (high) {
1081 switch (regm&0x0f) {
1082 case 0x04:
1083 OPL3_ChannelSet4Op(&chip, v);
1084 break;
1085 case 0x05:
1086 chip.newm = v&0x01;
1087 break;
1088 default: break;
1090 } else {
1091 switch (regm&0x0f) {
1092 case 0x08:
1093 chip.nts = (v>>6)&0x01;
1094 break;
1095 default: break;
1098 break;
1099 case 0x20:
1100 case 0x30:
1101 if (ad_slot.ptr[regm&0x1f] >= 0) OPL3_SlotWrite20(&chip.slot.ptr[18*high+ad_slot.ptr[regm&0x1f]], v);
1102 break;
1103 case 0x40:
1104 case 0x50:
1105 if (ad_slot.ptr[regm&0x1f] >= 0) OPL3_SlotWrite40(&chip.slot.ptr[18*high+ad_slot.ptr[regm&0x1f]], v);
1106 break;
1107 case 0x60:
1108 case 0x70:
1109 if (ad_slot.ptr[regm&0x1f] >= 0) OPL3_SlotWrite60(&chip.slot.ptr[18*high+ad_slot.ptr[regm&0x1f]], v);
1110 break;
1111 case 0x80:
1112 case 0x90:
1113 if (ad_slot.ptr[regm&0x1f] >= 0) OPL3_SlotWrite80(&chip.slot.ptr[18*high+ad_slot.ptr[regm&0x1f]], v);
1114 break;
1115 case 0xe0:
1116 case 0xf0:
1117 if (ad_slot.ptr[regm&0x1f] >= 0) OPL3_SlotWriteE0(&chip.slot.ptr[18*high+ad_slot.ptr[regm&0x1f]], v);
1118 break;
1119 case 0xa0:
1120 if ((regm&0x0f) < 9) OPL3_ChannelWriteA0(&chip.channel.ptr[9*high+(regm&0x0f)], v);
1121 break;
1122 case 0xb0:
1123 if (regm == 0xbd && !high) {
1124 chip.tremoloshift = (((v>>7)^1)<<1)+2;
1125 chip.vibshift = ((v>>6)&0x01)^1;
1126 OPL3_ChannelUpdateRhythm(&chip, v);
1127 } else if ((regm&0x0f) < 9) {
1128 OPL3_ChannelWriteB0(&chip.channel.ptr[9*high+(regm&0x0f)], v);
1129 if (v&0x20) OPL3_ChannelKeyOn(&chip.channel.ptr[9*high+(regm&0x0f)]); else OPL3_ChannelKeyOff(&chip.channel.ptr[9*high+(regm&0x0f)]);
1131 break;
1132 case 0xc0:
1133 if ((regm&0x0f) < 9) OPL3_ChannelWriteC0(&chip.channel.ptr[9*high+(regm&0x0f)], v);
1134 break;
1135 default: break;
1140 /// OPL3_WriteRegBuffered
1141 public void writeRegBuffered (ref OPL3Chip chip, ushort reg, ubyte v) {
1142 ulong time1, time2;
1144 if (chip.writebuf.ptr[chip.writebuf_last].reg&0x200) {
1145 chip.writeReg(chip.writebuf.ptr[chip.writebuf_last].reg&0x1ff, chip.writebuf.ptr[chip.writebuf_last].data);
1146 chip.writebuf_cur = (chip.writebuf_last+1)%OPL_WRITEBUF_SIZE;
1147 chip.writebuf_samplecnt = chip.writebuf.ptr[chip.writebuf_last].time;
1150 chip.writebuf.ptr[chip.writebuf_last].reg = reg|0x200;
1151 chip.writebuf.ptr[chip.writebuf_last].data = v;
1152 time1 = chip.writebuf_lasttime+OPL_WRITEBUF_DELAY;
1153 time2 = chip.writebuf_samplecnt;
1155 if (time1 < time2) time1 = time2;
1157 chip.writebuf.ptr[chip.writebuf_last].time = time1;
1158 chip.writebuf_lasttime = time1;
1159 chip.writebuf_last = (chip.writebuf_last+1)%OPL_WRITEBUF_SIZE;
1163 /// OPL3_GenerateStream; outputs STEREO stream
1164 public void generateStream (ref OPL3Chip chip, short[] smpbuf) {
1165 auto sndptr = smpbuf.ptr;
1166 foreach (immutable _; 0..smpbuf.length/2) {
1167 chip.generateResampled(sndptr);
1168 sndptr += 2;
1173 // ////////////////////////////////////////////////////////////////////////// //
1174 // simple DooM MUS / Midi player
1175 public final class OPLPlayer {
1176 private:
1177 static immutable ubyte[128] opl_voltable = [
1178 0x00, 0x01, 0x03, 0x05, 0x06, 0x08, 0x0a, 0x0b,
1179 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, 0x16, 0x17,
1180 0x19, 0x1a, 0x1b, 0x1d, 0x1e, 0x20, 0x21, 0x22,
1181 0x24, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x2f, 0x31,
1182 0x32, 0x34, 0x36, 0x37, 0x39, 0x3b, 0x3c, 0x3d,
1183 0x3f, 0x40, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48,
1184 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4f, 0x50, 0x51,
1185 0x52, 0x53, 0x54, 0x54, 0x55, 0x56, 0x57, 0x58,
1186 0x59, 0x5a, 0x5b, 0x5c, 0x5c, 0x5d, 0x5e, 0x5f,
1187 0x60, 0x60, 0x61, 0x62, 0x63, 0x63, 0x64, 0x65,
1188 0x65, 0x66, 0x67, 0x67, 0x68, 0x69, 0x69, 0x6a,
1189 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6f,
1190 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73,
1191 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78,
1192 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b,
1193 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f
1196 static immutable ushort[284+384] opl_freqtable = [
1197 0x0133, 0x0133, 0x0134, 0x0134, 0x0135, 0x0136, 0x0136, 0x0137,
1198 0x0137, 0x0138, 0x0138, 0x0139, 0x0139, 0x013a, 0x013b, 0x013b,
1199 0x013c, 0x013c, 0x013d, 0x013d, 0x013e, 0x013f, 0x013f, 0x0140,
1200 0x0140, 0x0141, 0x0142, 0x0142, 0x0143, 0x0143, 0x0144, 0x0144,
1201 0x0145, 0x0146, 0x0146, 0x0147, 0x0147, 0x0148, 0x0149, 0x0149,
1202 0x014a, 0x014a, 0x014b, 0x014c, 0x014c, 0x014d, 0x014d, 0x014e,
1203 0x014f, 0x014f, 0x0150, 0x0150, 0x0151, 0x0152, 0x0152, 0x0153,
1204 0x0153, 0x0154, 0x0155, 0x0155, 0x0156, 0x0157, 0x0157, 0x0158,
1205 0x0158, 0x0159, 0x015a, 0x015a, 0x015b, 0x015b, 0x015c, 0x015d,
1206 0x015d, 0x015e, 0x015f, 0x015f, 0x0160, 0x0161, 0x0161, 0x0162,
1207 0x0162, 0x0163, 0x0164, 0x0164, 0x0165, 0x0166, 0x0166, 0x0167,
1208 0x0168, 0x0168, 0x0169, 0x016a, 0x016a, 0x016b, 0x016c, 0x016c,
1209 0x016d, 0x016e, 0x016e, 0x016f, 0x0170, 0x0170, 0x0171, 0x0172,
1210 0x0172, 0x0173, 0x0174, 0x0174, 0x0175, 0x0176, 0x0176, 0x0177,
1211 0x0178, 0x0178, 0x0179, 0x017a, 0x017a, 0x017b, 0x017c, 0x017c,
1212 0x017d, 0x017e, 0x017e, 0x017f, 0x0180, 0x0181, 0x0181, 0x0182,
1213 0x0183, 0x0183, 0x0184, 0x0185, 0x0185, 0x0186, 0x0187, 0x0188,
1214 0x0188, 0x0189, 0x018a, 0x018a, 0x018b, 0x018c, 0x018d, 0x018d,
1215 0x018e, 0x018f, 0x018f, 0x0190, 0x0191, 0x0192, 0x0192, 0x0193,
1216 0x0194, 0x0194, 0x0195, 0x0196, 0x0197, 0x0197, 0x0198, 0x0199,
1217 0x019a, 0x019a, 0x019b, 0x019c, 0x019d, 0x019d, 0x019e, 0x019f,
1218 0x01a0, 0x01a0, 0x01a1, 0x01a2, 0x01a3, 0x01a3, 0x01a4, 0x01a5,
1219 0x01a6, 0x01a6, 0x01a7, 0x01a8, 0x01a9, 0x01a9, 0x01aa, 0x01ab,
1220 0x01ac, 0x01ad, 0x01ad, 0x01ae, 0x01af, 0x01b0, 0x01b0, 0x01b1,
1221 0x01b2, 0x01b3, 0x01b4, 0x01b4, 0x01b5, 0x01b6, 0x01b7, 0x01b8,
1222 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bc, 0x01bd, 0x01be,
1223 0x01bf, 0x01c0, 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c4, 0x01c4,
1224 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01c9, 0x01ca, 0x01cb,
1225 0x01cc, 0x01cd, 0x01ce, 0x01ce, 0x01cf, 0x01d0, 0x01d1, 0x01d2,
1226 0x01d3, 0x01d3, 0x01d4, 0x01d5, 0x01d6, 0x01d7, 0x01d8, 0x01d8,
1227 0x01d9, 0x01da, 0x01db, 0x01dc, 0x01dd, 0x01de, 0x01de, 0x01df,
1228 0x01e0, 0x01e1, 0x01e2, 0x01e3, 0x01e4, 0x01e5, 0x01e5, 0x01e6,
1229 0x01e7, 0x01e8, 0x01e9, 0x01ea, 0x01eb, 0x01ec, 0x01ed, 0x01ed,
1230 0x01ee, 0x01ef, 0x01f0, 0x01f1, 0x01f2, 0x01f3, 0x01f4, 0x01f5,
1231 0x01f6, 0x01f6, 0x01f7, 0x01f8, 0x01f9, 0x01fa, 0x01fb, 0x01fc,
1232 0x01fd, 0x01fe, 0x01ff, 0x0200, 0x0201, 0x0201, 0x0202, 0x0203,
1233 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020b,
1234 0x020c, 0x020d, 0x020e, 0x020f, 0x0210, 0x0210, 0x0211, 0x0212,
1235 0x0213, 0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021a,
1236 0x021b, 0x021c, 0x021d, 0x021e, 0x021f, 0x0220, 0x0221, 0x0222,
1237 0x0223, 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022a,
1238 0x022b, 0x022c, 0x022d, 0x022e, 0x022f, 0x0230, 0x0231, 0x0232,
1239 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023a,
1240 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, 0x0240, 0x0241, 0x0242,
1241 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b,
1242 0x024c, 0x024d, 0x024e, 0x024f, 0x0250, 0x0251, 0x0252, 0x0253,
1243 0x0254, 0x0256, 0x0257, 0x0258, 0x0259, 0x025a, 0x025b, 0x025c,
1244 0x025d, 0x025e, 0x025f, 0x0260, 0x0262, 0x0263, 0x0264, 0x0265,
1245 0x0266, 0x0267, 0x0268, 0x0269, 0x026a, 0x026c, 0x026d, 0x026e,
1246 0x026f, 0x0270, 0x0271, 0x0272, 0x0273, 0x0275, 0x0276, 0x0277,
1247 0x0278, 0x0279, 0x027a, 0x027b, 0x027d, 0x027e, 0x027f, 0x0280,
1248 0x0281, 0x0282, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289,
1249 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, 0x0290, 0x0292, 0x0293,
1250 0x0294, 0x0295, 0x0296, 0x0298, 0x0299, 0x029a, 0x029b, 0x029c,
1251 0x029e, 0x029f, 0x02a0, 0x02a1, 0x02a2, 0x02a4, 0x02a5, 0x02a6,
1252 0x02a7, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ae, 0x02af, 0x02b0,
1253 0x02b1, 0x02b2, 0x02b4, 0x02b5, 0x02b6, 0x02b7, 0x02b9, 0x02ba,
1254 0x02bb, 0x02bd, 0x02be, 0x02bf, 0x02c0, 0x02c2, 0x02c3, 0x02c4,
1255 0x02c5, 0x02c7, 0x02c8, 0x02c9, 0x02cb, 0x02cc, 0x02cd, 0x02ce,
1256 0x02d0, 0x02d1, 0x02d2, 0x02d4, 0x02d5, 0x02d6, 0x02d8, 0x02d9,
1257 0x02da, 0x02dc, 0x02dd, 0x02de, 0x02e0, 0x02e1, 0x02e2, 0x02e4,
1258 0x02e5, 0x02e6, 0x02e8, 0x02e9, 0x02ea, 0x02ec, 0x02ed, 0x02ee,
1259 0x02f0, 0x02f1, 0x02f2, 0x02f4, 0x02f5, 0x02f6, 0x02f8, 0x02f9,
1260 0x02fb, 0x02fc, 0x02fd, 0x02ff, 0x0300, 0x0302, 0x0303, 0x0304,
1261 0x0306, 0x0307, 0x0309, 0x030a, 0x030b, 0x030d, 0x030e, 0x0310,
1262 0x0311, 0x0312, 0x0314, 0x0315, 0x0317, 0x0318, 0x031a, 0x031b,
1263 0x031c, 0x031e, 0x031f, 0x0321, 0x0322, 0x0324, 0x0325, 0x0327,
1264 0x0328, 0x0329, 0x032b, 0x032c, 0x032e, 0x032f, 0x0331, 0x0332,
1265 0x0334, 0x0335, 0x0337, 0x0338, 0x033a, 0x033b, 0x033d, 0x033e,
1266 0x0340, 0x0341, 0x0343, 0x0344, 0x0346, 0x0347, 0x0349, 0x034a,
1267 0x034c, 0x034d, 0x034f, 0x0350, 0x0352, 0x0353, 0x0355, 0x0357,
1268 0x0358, 0x035a, 0x035b, 0x035d, 0x035e, 0x0360, 0x0361, 0x0363,
1269 0x0365, 0x0366, 0x0368, 0x0369, 0x036b, 0x036c, 0x036e, 0x0370,
1270 0x0371, 0x0373, 0x0374, 0x0376, 0x0378, 0x0379, 0x037b, 0x037c,
1271 0x037e, 0x0380, 0x0381, 0x0383, 0x0384, 0x0386, 0x0388, 0x0389,
1272 0x038b, 0x038d, 0x038e, 0x0390, 0x0392, 0x0393, 0x0395, 0x0397,
1273 0x0398, 0x039a, 0x039c, 0x039d, 0x039f, 0x03a1, 0x03a2, 0x03a4,
1274 0x03a6, 0x03a7, 0x03a9, 0x03ab, 0x03ac, 0x03ae, 0x03b0, 0x03b1,
1275 0x03b3, 0x03b5, 0x03b7, 0x03b8, 0x03ba, 0x03bc, 0x03bd, 0x03bf,
1276 0x03c1, 0x03c3, 0x03c4, 0x03c6, 0x03c8, 0x03ca, 0x03cb, 0x03cd,
1277 0x03cf, 0x03d1, 0x03d2, 0x03d4, 0x03d6, 0x03d8, 0x03da, 0x03db,
1278 0x03dd, 0x03df, 0x03e1, 0x03e3, 0x03e4, 0x03e6, 0x03e8, 0x03ea,
1279 0x03ec, 0x03ed, 0x03ef, 0x03f1, 0x03f3, 0x03f5, 0x03f6, 0x03f8,
1280 0x03fa, 0x03fc, 0x03fe, 0x036c
1283 private:
1284 // GenMidi lump structure
1285 static align(1) struct GenMidi {
1286 align(1):
1287 public:
1288 static align(1) struct Operator {
1289 align(1):
1290 ubyte mult; /* Tremolo / vibrato / sustain / KSR / multi */
1291 ubyte attack; /* Attack rate / decay rate */
1292 ubyte sustain; /* Sustain level / release rate */
1293 ubyte wave; /* Waveform select */
1294 ubyte ksl; /* Key scale level */
1295 ubyte level; /* Output level */
1296 ubyte feedback; /* Feedback for modulator, unused for carrier */
1299 static align(1) struct Voice {
1300 align(1):
1301 Operator mod; /* modulator */
1302 Operator car; /* carrier */
1303 /* Base note offset. This is used to offset the MIDI note values.
1304 Several of the GENMIDI instruments have a base note offset of -12,
1305 causing all notes to be offset down by one octave. */
1306 short offset;
1309 static align(1) struct Patch {
1310 align(1):
1311 public:
1312 enum Flag : ushort {
1313 Fixed = 0x01,
1314 DualVoice = 0x04,
1316 public:
1317 /* bit 0: Fixed pitch - Instrument always plays the same note.
1318 Most MIDI instruments play a note that is specified in the MIDI "key on" event,
1319 but some (most notably percussion instruments) always play the same fixed note.
1320 bit 1: Unknown - used in instrument #65 of the Doom GENMIDI lump.
1321 bit 2: Double voice - Play two voices simultaneously. This is used even on an OPL2 chip.
1322 If this is not set, only the first voice is played. If it is set, the fine tuning
1323 field (see below) can be used to adjust the pitch of the second voice relative to
1324 the first.
1326 version(genmidi_dumper) {
1327 ushort flags;
1328 } else {
1329 ubyte flags;
1331 /* Fine tuning - This normally has a value of 128, but can be adjusted to adjust the tuning of
1332 the instrument. This field only applies to the second voice of double-voice instruments;
1333 for single voice instruments it has no effect. The offset values are similar to MIDI pitch
1334 bends; for example, a value of 82 (hex) in this field is equivalent to a MIDI pitch bend of +256.
1336 ubyte finetune;
1337 /* Note number used for fixed pitch instruments */
1338 ubyte note;
1339 Voice[2] voice;
1340 version(genmidi_dumper) {
1341 // no name in this mode
1342 } else {
1343 string name; // patch name
1347 public:
1348 //char[8] header;
1349 Patch[175] patch;
1350 version(genmidi_dumper) {
1351 char[32][175] namestrs; // patch names
1352 @property const(char)[] name (usize patchidx) const pure nothrow @safe @nogc {
1353 const(char)[] res = namestrs[patchidx][];
1354 foreach (immutable idx, immutable char ch; res) if (ch == 0) return res[0..idx];
1355 return res;
1359 public:
1360 version(genmidi_dumper) {
1361 void dump (VFile fo) {
1362 fo.writeln("static immutable GenMidi mGenMidi = GenMidi([");
1363 foreach (immutable idx, const ref Patch pt; patch[]) {
1364 fo.write(" GenMidi.Patch(");
1365 fo.writef("0x%02x,", pt.flags);
1366 fo.writef("%3u,", pt.finetune);
1367 fo.writef("%3u,[", pt.note);
1368 // voices
1369 foreach (immutable vidx, const ref v; pt.voice[]) {
1370 fo.write("GenMidi.Voice(");
1371 fo.write("GenMidi.Operator(");
1372 fo.writef("%3u,", v.mod.mult);
1373 fo.writef("%3u,", v.mod.attack);
1374 fo.writef("%3u,", v.mod.sustain);
1375 fo.writef("%3u,", v.mod.wave);
1376 fo.writef("%3u,", v.mod.ksl);
1377 fo.writef("%3u,", v.mod.level);
1378 fo.writef("%3u),", v.mod.feedback);
1379 fo.write("GenMidi.Operator(");
1380 fo.writef("%3u,", v.car.mult);
1381 fo.writef("%3u,", v.car.attack);
1382 fo.writef("%3u,", v.car.sustain);
1383 fo.writef("%3u,", v.car.wave);
1384 fo.writef("%3u,", v.car.ksl);
1385 fo.writef("%3u,", v.car.level);
1386 fo.writef("%3u),", v.car.feedback);
1387 fo.writef("%4d),", v.offset);
1389 fo.write("],", name(idx).quote);
1390 fo.writeln("),");
1392 fo.writeln("]);");
1397 version(genmidi_dumper) {
1398 } else {
1399 //mixin(import("zgenmidi.d"));
1400 static immutable GenMidi mGenMidi = GenMidi([
1401 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,240,243, 1, 64, 20, 10),GenMidi.Operator( 48,241,244, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Acoustic Grand Piano"),
1402 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,240,243, 0, 64, 18, 10),GenMidi.Operator( 48,241,244, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Bright Acoustic Piano"),
1403 GenMidi.Patch(0x04,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,225,243, 1, 64, 14, 8),GenMidi.Operator( 48,241,244, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 17,232, 21, 0, 0, 0, 1),GenMidi.Operator( 18,247, 20, 0, 0, 0, 0), 0),],"Electric Grand Piano"),
1404 GenMidi.Patch(0x04,130, 0,[GenMidi.Voice(GenMidi.Operator( 16,241, 83, 1, 64, 15, 6),GenMidi.Operator( 16,209,244, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 17,241, 83, 0, 64, 15, 6),GenMidi.Operator( 17,209,244, 0, 0, 0, 0), 0),],"Honky-tonk Piano"),
1405 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 33,241, 81, 0, 64, 38, 6),GenMidi.Operator( 49,210,229, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Rhodes Paino"),
1406 GenMidi.Patch(0x04,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,241,230, 0, 64, 17, 6),GenMidi.Operator(176,241,229, 0, 64, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 18,242,121, 0, 64, 3, 9),GenMidi.Operator( 16,241,153, 0, 64, 0, 0), 0),],"Chorused Piano"),
1407 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,242, 1, 2,128, 7, 6),GenMidi.Operator( 48,193,244, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Harpsichord"),
1408 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(144,161, 98, 1,128, 14, 12),GenMidi.Operator( 16,145,167, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Clavinet"),
1409 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 40,242,100, 1, 64, 15, 8),GenMidi.Operator( 49,242,228, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Celesta"),
1410 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 19,145, 17, 0, 0, 14, 9),GenMidi.Operator( 20,125, 52, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Glockenspiel"),
1411 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(178,246, 65, 0, 0, 15, 0),GenMidi.Operator(144,210,146, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Music Box"),
1412 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(240,241,243, 0, 0, 2, 1),GenMidi.Operator(242,241,244, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Vibraphone"),
1413 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(128,121, 21, 0, 0, 0, 1),GenMidi.Operator(131,248,117, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Marimba"),
1414 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 20,246,147, 0, 0, 31, 8),GenMidi.Operator( 16,246, 83, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Xylophone"),
1415 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(129,182, 19, 1,128, 25, 10),GenMidi.Operator( 2,255, 19, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Tubular-bell"),
1416 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,145, 17, 0, 64, 7, 8),GenMidi.Operator( 17, 82, 83, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Dulcimer"),
1417 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(160,177, 22, 0,128, 8, 7),GenMidi.Operator( 97,209, 23, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Hammond Organ"),
1418 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,241, 5, 1, 0, 0, 7),GenMidi.Operator(148,244, 54, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Percussive Organ"),
1419 GenMidi.Patch(0x04,138, 0,[GenMidi.Voice(GenMidi.Operator(226,242, 23, 0,128, 30, 0),GenMidi.Operator( 96,255, 7, 1,128, 0, 0), -12),GenMidi.Voice(GenMidi.Operator(224,242, 23, 1,128, 30, 0),GenMidi.Operator(160,255, 7, 0,128, 0, 0), 0),],"Rock Organ"),
1420 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48, 48, 4, 0,128, 18, 9),GenMidi.Operator( 49, 84, 20, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 49, 84, 20, 2,128, 18, 9),GenMidi.Operator( 48,253, 68, 0,128, 0, 0), 0),],"Church Organ"),
1421 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 0,128, 23, 0, 64, 9, 6),GenMidi.Operator(129, 96, 23, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Reed Organ"),
1422 GenMidi.Patch(0x04,125, 0,[GenMidi.Voice(GenMidi.Operator( 32,162, 21, 0, 64, 8, 10),GenMidi.Operator( 49, 65, 38, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 32,130, 21, 0, 64, 10, 10),GenMidi.Operator( 49, 70, 38, 1, 0, 0, 0), 0),],"Accordion"),
1423 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(176, 96, 52, 0, 0, 12, 8),GenMidi.Operator(178, 66, 22, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(176, 96, 52, 0, 0, 12, 8),GenMidi.Operator(178, 66, 22, 0,128, 0, 0), 12),],"Harmonica"),
1424 GenMidi.Patch(0x04,129, 0,[GenMidi.Voice(GenMidi.Operator( 32,240, 5, 1,128, 18, 8),GenMidi.Operator( 49, 82, 5, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 32,240, 5, 1,128, 18, 0),GenMidi.Operator( 49, 82, 5, 2, 0, 0, 0), 0),],"Tango Accordion"),
1425 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,241,245, 0,128, 13, 0),GenMidi.Operator( 32,241,246, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Acoustic Guitar (nylon)"),
1426 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,225,228, 1, 0, 13, 10),GenMidi.Operator( 48,242,227, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Acoustic Guitar (steel)"),
1427 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 0,241, 31, 2, 0, 33, 10),GenMidi.Operator( 0,244,136, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Electric Guitar (jazz)"),
1428 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 16,234, 50, 1,128, 7, 2),GenMidi.Operator( 16,210,231, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Electric Guitar (clean)"),
1429 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,224,244, 0,128, 18, 0),GenMidi.Operator( 48,242,245, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Electric Guitar (muted)"),
1430 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 0,241,255, 0, 0, 16, 10),GenMidi.Operator( 81,240,255, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0, 0, 0, 0, 0, 0),GenMidi.Operator( 0, 0, 0, 0, 0, 0, 0), 0),],"Overdriven Guitar"),
1431 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 16,241,255, 0, 0, 13, 12),GenMidi.Operator( 81,240,255, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0, 0, 0, 0, 0, 0),GenMidi.Operator( 0, 0, 0, 0, 0, 0, 0), 0),],"Distortion Guitar"),
1432 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 16,161,151, 2, 64, 3, 0),GenMidi.Operator( 17,225,231, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Guitar Harmonics"),
1433 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,196, 32, 0, 0, 14, 0),GenMidi.Operator(176,195,246, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0, 0, 0, 0, 0, 0),GenMidi.Operator( 0, 0, 0, 0, 0, 0, 0), 0),],"Acoustic Bass"),
1434 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,240,255, 0,128, 22, 10),GenMidi.Operator( 49,241,248, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Electric Bass (finger)"),
1435 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,224, 20, 0,128, 15, 8),GenMidi.Operator( 48,225,214, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Electric Bass (pick)"),
1436 GenMidi.Patch(0x04,126, 0,[GenMidi.Voice(GenMidi.Operator(225, 81, 69, 1, 64, 13, 0),GenMidi.Operator(160,145, 70, 1, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator(161, 81, 69, 1, 64, 13, 0),GenMidi.Operator(160,129, 70, 1, 0, 0, 0), 0),],"Fretless Bass"),
1437 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,240,231, 2, 0, 0, 0),GenMidi.Operator( 49,241, 71, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 16,245,231, 1, 0, 13, 13),GenMidi.Operator( 16,246,231, 2, 0, 0, 0), 0),],"* Slap Bass 1"),
1438 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,240,229, 0,128, 16, 8),GenMidi.Operator( 49,241,245, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Slap Bass 2"),
1439 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,244,245, 1, 0, 10, 10),GenMidi.Operator( 48,243,246, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Synth Bass 1"),
1440 GenMidi.Patch(0x04,118, 0,[GenMidi.Voice(GenMidi.Operator( 48,131, 70, 1, 0, 21, 10),GenMidi.Operator( 49,210, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 48,131, 70, 1, 0, 21, 10),GenMidi.Operator( 49,210, 23, 0, 0, 0, 0), 0),],"Synth Bass 2"),
1441 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 96, 80, 69, 1, 0, 23, 6),GenMidi.Operator(161, 97, 70, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Violin"),
1442 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(240, 96, 68, 0,128, 15, 2),GenMidi.Operator(113, 65, 21, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Viola"),
1443 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(176,208, 20, 2, 0, 15, 6),GenMidi.Operator( 97, 98, 23, 1,128, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Cello"),
1444 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(240,177, 17, 2,128, 10, 6),GenMidi.Operator( 32,160, 21, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Contrabass"),
1445 GenMidi.Patch(0x04,139, 0,[GenMidi.Voice(GenMidi.Operator(240,195, 1, 2,128, 9, 6),GenMidi.Operator( 97,131, 5, 0, 64, 0, 0), -12),GenMidi.Voice(GenMidi.Operator(112,179, 1, 2,128, 9, 6),GenMidi.Operator( 96,147, 5, 1, 64, 0, 0), 0),],"Tremolo Strings"),
1446 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,248,249, 2,128, 23, 14),GenMidi.Operator( 32,118,230, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Pizzicato Strings"),
1447 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 49,241, 53, 0, 0, 36, 0),GenMidi.Operator( 32,243,179, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Orchestral Harp"),
1448 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 0,170,200, 0, 0, 4, 10),GenMidi.Operator( 16,210,179, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Timpani"),
1449 GenMidi.Patch(0x04,120, 0,[GenMidi.Voice(GenMidi.Operator( 96,192, 4, 1, 64, 17, 4),GenMidi.Operator(177, 85, 4, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(160,144, 4, 1, 64, 18, 6),GenMidi.Operator( 49, 85, 4, 1,128, 0, 0), 0),],"String Ensemble 1"),
1450 GenMidi.Patch(0x04,133, 0,[GenMidi.Voice(GenMidi.Operator( 32,144, 5, 1, 64, 17, 4),GenMidi.Operator(161, 53, 5, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(160,144, 5, 1, 64, 18, 6),GenMidi.Operator( 33, 53, 5, 1,128, 0, 0), 0),],"String Ensemble 2"),
1451 GenMidi.Patch(0x04,123, 0,[GenMidi.Voice(GenMidi.Operator(161,105, 5, 2,128, 19, 10),GenMidi.Operator(241,102, 2, 2, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator(161,105, 5, 2,128, 19, 10),GenMidi.Operator(241,102, 2, 2, 0, 0, 0), -12),],"Synth Strings 1"),
1452 GenMidi.Patch(0x04,132, 0,[GenMidi.Voice(GenMidi.Operator( 33, 17, 3, 0, 64, 13, 0),GenMidi.Operator( 32, 49, 4, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 17, 51, 2,128, 2, 8),GenMidi.Operator( 0, 49, 54, 1,128, 0, 0), 0),],"Synth Strings 2"),
1453 GenMidi.Patch(0x04,138, 0,[GenMidi.Voice(GenMidi.Operator( 96,144, 84, 0, 64, 22, 0),GenMidi.Operator( 96,112, 4, 0, 64, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 32,144, 84, 0,128, 18, 0),GenMidi.Operator( 96,112, 4, 0,192, 0, 0), 0),],"Choir Aahs"),
1454 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(160,177,183, 0,128, 25, 0),GenMidi.Operator(160,114,133, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 18,102,240, 0,192, 6, 12),GenMidi.Operator( 81,174,182, 0,192, 0, 0), -12),],"Voice Oohs"),
1455 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(176, 96, 84, 0, 64, 26, 0),GenMidi.Operator(176, 48,116, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Synth Voice"),
1456 GenMidi.Patch(0x04,128, 0,[GenMidi.Voice(GenMidi.Operator( 16, 48, 67, 0,128, 16, 2),GenMidi.Operator( 16,100, 20, 0, 0, 0, 0), -24),GenMidi.Voice(GenMidi.Operator(144, 80, 66, 0,128, 15, 2),GenMidi.Operator( 17, 84, 69, 0, 0, 0, 0), -12),],"Orchestra Hit"),
1457 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,128, 21, 1,128, 14, 10),GenMidi.Operator( 48, 81, 54, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Trumpet"),
1458 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(176,113, 31, 0, 0, 26, 14),GenMidi.Operator( 32,114, 59, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Trombone"),
1459 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,128, 70, 0, 0, 22, 12),GenMidi.Operator( 32,146, 86, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0,128, 0, 0),GenMidi.Operator( 0, 0,240, 0,128, 0, 0), 0),],"Tuba"),
1460 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(128,128,230, 1,128, 13, 12),GenMidi.Operator(144, 81,246, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Muted Trumpet"),
1461 GenMidi.Patch(0x04,129, 0,[GenMidi.Voice(GenMidi.Operator( 32,112,184, 0, 0, 34, 14),GenMidi.Operator( 32, 97,150, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 32,112,184, 0, 0, 35, 14),GenMidi.Operator( 32, 97,150, 0,128, 0, 0), 0),],"French Horn"),
1462 GenMidi.Patch(0x04,131, 0,[GenMidi.Voice(GenMidi.Operator( 32, 96, 21, 1,128, 14, 10),GenMidi.Operator( 48, 81, 54, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 48,112, 23, 1,128, 18, 14),GenMidi.Operator( 48, 97, 54, 1, 0, 0, 0), 0),],"Brass Section"),
1463 GenMidi.Patch(0x04,134, 0,[GenMidi.Voice(GenMidi.Operator( 32,145,166, 2, 64, 13, 12),GenMidi.Operator( 32,129,151, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 32,145,166, 2,128, 12, 12),GenMidi.Operator( 32,145,151, 1, 0, 0, 0), 0),],"Synth Brass 1"),
1464 GenMidi.Patch(0x04,134, 0,[GenMidi.Voice(GenMidi.Operator( 48,129,166, 2, 64, 16, 12),GenMidi.Operator( 48, 97,151, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 48,129,166, 2, 64, 10, 10),GenMidi.Operator( 48, 97,151, 1, 0, 0, 0), 0),],"Synth Bass 2"),
1465 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(160, 96, 5, 0,128, 22, 6),GenMidi.Operator(177, 82, 22, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Soprano Sax"),
1466 GenMidi.Patch(0x02,128, 0,[GenMidi.Voice(GenMidi.Operator(160,112, 6, 1,128, 9, 6),GenMidi.Operator(176, 98, 22, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Alto Sax"),
1467 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(160,152, 11, 0, 64, 10, 10),GenMidi.Operator(176,115, 11, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Tenor Sax"),
1468 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(160,144, 11, 1,128, 5, 10),GenMidi.Operator(176, 99, 27, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Baritone Sax"),
1469 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(112,112, 22, 0,128, 16, 6),GenMidi.Operator(162, 92, 8, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Oboe"),
1470 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,200, 7, 0, 64, 15, 10),GenMidi.Operator( 49,115, 7, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"English Horn"),
1471 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,144, 25, 0,128, 17, 10),GenMidi.Operator( 49, 97, 27, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Bassoon"),
1472 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,165, 23, 0,128, 13, 8),GenMidi.Operator(176, 99, 23, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Clarinet"),
1473 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(240,110,143, 0,128, 0, 14),GenMidi.Operator(112, 53, 42, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Piccolo"),
1474 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(160, 80,136, 0,128, 19, 8),GenMidi.Operator( 96, 85, 42, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Flute"),
1475 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,101, 23, 0, 0, 10, 11),GenMidi.Operator(160,116, 39, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Recorder"),
1476 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(176, 36, 39, 1,128, 4, 9),GenMidi.Operator(176, 69, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 23,240, 2, 0, 0, 14),GenMidi.Operator( 0, 37,240, 0, 0, 0, 0), 0),],"Pan Flute"),
1477 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(225, 87, 4, 0,128, 45, 14),GenMidi.Operator( 96, 87, 55, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Bottle Blow"),
1478 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(241, 87, 52, 3, 0, 40, 14),GenMidi.Operator(225,103, 93, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Shakuhachi"),
1479 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(208, 49, 15, 0,192, 7, 11),GenMidi.Operator(112, 50, 5, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Whistle"),
1480 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(176, 81, 5, 0,192, 7, 11),GenMidi.Operator( 48, 66, 41, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Ocarina"),
1481 GenMidi.Patch(0x04,130, 0,[GenMidi.Voice(GenMidi.Operator( 34, 81, 91, 1, 64, 18, 0),GenMidi.Operator( 48, 96, 37, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 34,145, 91, 1, 64, 13, 0),GenMidi.Operator( 48,240, 37, 1, 0, 0, 0), 0),],"Lead 1 (square)"),
1482 GenMidi.Patch(0x04,127, 0,[GenMidi.Voice(GenMidi.Operator( 32,193,155, 1, 64, 3, 8),GenMidi.Operator( 49,192,101, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 96,177,171, 1, 64, 1, 8),GenMidi.Operator( 49,241, 5, 0, 0, 0, 0), 0),],"Lead 2 (sawtooth)"),
1483 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(240, 87, 51, 3, 0, 40, 14),GenMidi.Operator(224,103, 7, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Lead 3 (calliope)"),
1484 GenMidi.Patch(0x04,130, 0,[GenMidi.Voice(GenMidi.Operator(224, 87, 4, 3, 0, 35, 14),GenMidi.Operator(224,103, 77, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(224,247, 4, 3, 0, 35, 14),GenMidi.Operator(224,135, 77, 0, 0, 0, 0), 0),],"Lead 4 (chiffer)"),
1485 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(161,120, 11, 1, 64, 2, 8),GenMidi.Operator( 48,241, 43, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Lead 5 (charang)"),
1486 GenMidi.Patch(0x04,122, 0,[GenMidi.Voice(GenMidi.Operator( 96,128, 85, 0, 0, 33, 8),GenMidi.Operator(224,242, 20, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 32,144, 85, 0, 0, 33, 8),GenMidi.Operator(160,162, 20, 0, 0, 0, 0), 0),],"Lead 6 (voice)"),
1487 GenMidi.Patch(0x04,125, 0,[GenMidi.Voice(GenMidi.Operator( 32,193,149, 1, 64, 3, 10),GenMidi.Operator(176,112, 99, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(160,145,149, 1, 64, 9, 10),GenMidi.Operator( 49, 97, 99, 1, 0, 0, 0), -5),],"Lead 7 (5th sawtooth)"),
1488 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 36, 81, 7, 1, 64, 0, 9),GenMidi.Operator(160,253, 41, 2, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Lead 8 (bass & lead)"),
1489 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 36, 81, 7, 1, 64, 0, 9),GenMidi.Operator(160,253, 41, 2, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* Lead 8 (bass & lead)"),
1490 GenMidi.Patch(0x04,130, 0,[GenMidi.Voice(GenMidi.Operator(128, 50, 5, 0,192, 0, 9),GenMidi.Operator( 96, 51, 5, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 64, 50, 5, 0, 64, 0, 9),GenMidi.Operator(224, 51, 5, 0, 0, 0, 0), 0),],"Pad 2 (warm)"),
1491 GenMidi.Patch(0x04,130, 0,[GenMidi.Voice(GenMidi.Operator(160,161,165, 2,128, 15, 12),GenMidi.Operator(160,161,150, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(160,161,165, 2,128, 15, 12),GenMidi.Operator(160,161,150, 1, 0, 0, 0), 0),],"Pad 3 (polysynth)"),
1492 GenMidi.Patch(0x04,139, 0,[GenMidi.Voice(GenMidi.Operator(224,240, 5, 0, 64, 4, 1),GenMidi.Operator( 96,129, 84, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(224,240, 5, 1, 64, 4, 1),GenMidi.Operator( 96,113, 84, 0,128, 0, 0), 0),],"Pad 4 (choir)"),
1493 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(128,161, 51, 0,128, 10, 7),GenMidi.Operator(224, 82, 84, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Pad 5 (bowed glass)"),
1494 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(129,128, 82, 1,128, 29, 14),GenMidi.Operator( 64, 35, 83, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Pad 6 (metal)"),
1495 GenMidi.Patch(0x04,126, 0,[GenMidi.Voice(GenMidi.Operator(225, 81, 69, 1, 64, 13, 0),GenMidi.Operator(160,145, 70, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(161, 81, 69, 1, 64, 13, 0),GenMidi.Operator(160,129, 70, 1, 0, 0, 0), 0),],"Pad 7 (halo)"),
1496 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(225, 17, 82, 1,128, 12, 8),GenMidi.Operator(224,128,115, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Pad 8 (sweep)"),
1497 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,114, 71, 0, 64, 0, 11),GenMidi.Operator(131,248, 25, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"FX 1 (rain)"),
1498 GenMidi.Patch(0x04,136, 0,[GenMidi.Voice(GenMidi.Operator( 0,133, 2, 1,192, 18, 10),GenMidi.Operator(193, 69, 18, 1, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 34, 69, 3, 0,192, 18, 10),GenMidi.Operator(227, 53, 53, 2, 0, 0, 0), -5),],"FX 2 (soundtrack)"),
1499 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 4,246,116, 0,192, 0, 0),GenMidi.Operator( 2,163, 36, 0, 0, 0, 0), -24),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* FX 3 (crystal)"),
1500 GenMidi.Patch(0x04,126, 0,[GenMidi.Voice(GenMidi.Operator(144,192,210, 0,128, 14, 0),GenMidi.Operator( 48,209,210, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(144,208,210, 0,128, 14, 0),GenMidi.Operator( 48,241,210, 0, 0, 0, 0), 0),],"FX 4 (atmosphere)"),
1501 GenMidi.Patch(0x04,116, 0,[GenMidi.Voice(GenMidi.Operator(208,144,243, 0, 0, 18, 0),GenMidi.Operator(192,194,243, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator(208,144,243, 0, 0, 18, 0),GenMidi.Operator(192,194,242, 0,128, 0, 0), 0),],"FX 5 (brightness)"),
1502 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(224, 19, 82, 1, 0, 26, 0),GenMidi.Operator(241, 51, 19, 2,128, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"FX 6 (goblin)"),
1503 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(224, 69,186, 0, 0, 26, 0),GenMidi.Operator(240, 50,145, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"FX 7 (echo drops)"),
1504 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 16, 88, 2, 1, 0, 24, 10),GenMidi.Operator( 2, 66,114, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"* FX 8 (star-theme)"),
1505 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32, 99,179, 0, 0, 8, 2),GenMidi.Operator( 36, 99,179, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Sitar"),
1506 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,119, 18, 0, 0, 13, 4),GenMidi.Operator( 16,243,244, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0,249,250, 2, 0, 10, 15),GenMidi.Operator( 0,249,250, 3, 64, 0, 0), 0),],"Banjo"),
1507 GenMidi.Patch(0x04,128, 0,[GenMidi.Voice(GenMidi.Operator( 0,249, 51, 0,128, 0, 0),GenMidi.Operator( 0,244,115, 2,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 7,249,172, 2, 0, 26, 0),GenMidi.Operator( 15,249, 41, 2, 0, 0, 0), 0),],"Shamisen"),
1508 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,242, 83, 1, 0, 33, 8),GenMidi.Operator( 34,145,228, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Koto"),
1509 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 3,241, 57, 3, 64, 15, 6),GenMidi.Operator( 21,214,116, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Kalimba"),
1510 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,137, 21, 1, 64, 2, 10),GenMidi.Operator( 33,107, 7, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Bag Pipe"),
1511 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48,161, 3, 0, 0, 31, 14),GenMidi.Operator( 33, 82, 38, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Fiddle"),
1512 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 48, 64, 19, 0, 0, 19, 8),GenMidi.Operator( 48, 97, 22, 1,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Shanai"),
1513 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 19,161, 50, 0, 0, 0, 1),GenMidi.Operator( 18,178,114, 1,128, 0, 0), -7),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Tinkle Bell"),
1514 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(149,231, 1, 0,128, 1, 4),GenMidi.Operator( 22,150,103, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Agogo"),
1515 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 3,240, 4, 1, 64, 9, 6),GenMidi.Operator( 32,130, 5, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Steel Drums"),
1516 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 19,248,209, 0, 64, 4, 6),GenMidi.Operator( 18,245,120, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Woodblock"),
1517 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 16,167,236, 0, 0, 11, 0),GenMidi.Operator( 16,213,245, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Taiko Drum"),
1518 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 32,168,200, 0, 0, 11, 0),GenMidi.Operator( 1,214,183, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Melodic Tom"),
1519 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 0,248,196, 0, 0, 11, 0),GenMidi.Operator( 0,211,183, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Synth Drum"),
1520 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 12, 65, 49, 0,128, 15, 14),GenMidi.Operator( 16, 33, 29, 3,128, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Reverse Cymbal"),
1521 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 50, 52,179, 1, 0, 33, 14),GenMidi.Operator( 49, 84,247, 3, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Guitar Fret Noise"),
1522 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(209, 55, 4, 0,128, 45, 14),GenMidi.Operator( 80, 55, 52, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Breath Noise"),
1523 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 2, 62, 1, 2, 0, 0, 14),GenMidi.Operator( 8, 20,243, 2, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Seashore"),
1524 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(245,235, 3, 0,192, 20, 7),GenMidi.Operator(246, 69,104, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Bird Tweet"),
1525 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator(240,218,113, 1, 0, 0, 8),GenMidi.Operator(202,176, 23, 1,192, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Telephone Ring"),
1526 GenMidi.Patch(0x01,128, 17,[GenMidi.Voice(GenMidi.Operator(240, 30, 17, 1, 0, 0, 8),GenMidi.Operator(226, 33, 17, 1,192, 0, 0), -24),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Helicopter"),
1527 GenMidi.Patch(0x01,128, 65,[GenMidi.Voice(GenMidi.Operator(239, 83, 0, 2,128, 6, 14),GenMidi.Operator(239, 16, 2, 3,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Applause"),
1528 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 12,240,240, 2, 0, 0, 14),GenMidi.Operator( 4,246,230, 0, 0, 0, 0), -12),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Gun Shot"),
1529 GenMidi.Patch(0x01,128, 38,[GenMidi.Voice(GenMidi.Operator( 0,249, 87, 2, 0, 0, 0),GenMidi.Operator( 0,251, 70, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Acoustic Bass Drum"),
1530 GenMidi.Patch(0x01,128, 25,[GenMidi.Voice(GenMidi.Operator( 0,250, 71, 0, 0, 0, 6),GenMidi.Operator( 0,249, 6, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Acoustic Bass Drum"),
1531 GenMidi.Patch(0x01,128, 83,[GenMidi.Voice(GenMidi.Operator( 2,253,103, 0,128, 0, 6),GenMidi.Operator( 3,247,120, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Slide Stick"),
1532 GenMidi.Patch(0x01,128, 32,[GenMidi.Voice(GenMidi.Operator( 15,247, 20, 2, 0, 5, 14),GenMidi.Operator( 0,249, 71, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Acoustic Snare"),
1533 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator(225,136,251, 3, 0, 0, 15),GenMidi.Operator(255,166,168, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Hand Clap"),
1534 GenMidi.Patch(0x05,128, 36,[GenMidi.Voice(GenMidi.Operator( 6,170,255, 0, 0, 0, 14),GenMidi.Operator( 0,247,250, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 63, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 42),],"Electric Snare"),
1535 GenMidi.Patch(0x01,128, 15,[GenMidi.Voice(GenMidi.Operator( 2,245,108, 0, 0, 0, 7),GenMidi.Operator( 3,247, 56, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Floor Tom"),
1536 GenMidi.Patch(0x01,128, 88,[GenMidi.Voice(GenMidi.Operator( 12,152, 94, 2, 0, 0, 15),GenMidi.Operator( 15,251, 6, 3, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Closed High-Hat"),
1537 GenMidi.Patch(0x01,128, 19,[GenMidi.Voice(GenMidi.Operator( 2,245,120, 0, 0, 0, 7),GenMidi.Operator( 0,247, 55, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High Floor Tom"),
1538 GenMidi.Patch(0x01,128, 88,[GenMidi.Voice(GenMidi.Operator( 12,120, 94, 2, 0, 0, 15),GenMidi.Operator( 10,138, 43, 3,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Pedal High Hat"),
1539 GenMidi.Patch(0x01,128, 21,[GenMidi.Voice(GenMidi.Operator( 2,245, 55, 0, 0, 0, 3),GenMidi.Operator( 2,247, 55, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Tom"),
1540 GenMidi.Patch(0x01,128, 79,[GenMidi.Voice(GenMidi.Operator( 0,199, 1, 2, 64, 5, 14),GenMidi.Operator( 11,249, 51, 2, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Open High Hat"),
1541 GenMidi.Patch(0x01,128, 26,[GenMidi.Voice(GenMidi.Operator( 2,245, 55, 0, 0, 0, 3),GenMidi.Operator( 2,247, 55, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low-Mid Tom"),
1542 GenMidi.Patch(0x01,128, 28,[GenMidi.Voice(GenMidi.Operator( 2,245, 55, 0, 0, 0, 3),GenMidi.Operator( 2,247, 55, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High-Mid Tom"),
1543 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator( 4,194,230, 0, 0, 16, 14),GenMidi.Operator( 0,232, 67, 3, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Crash Cymbal 1"),
1544 GenMidi.Patch(0x01,128, 32,[GenMidi.Voice(GenMidi.Operator( 2,245, 55, 0, 0, 0, 3),GenMidi.Operator( 2,247, 55, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High Tom"),
1545 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator( 3,253, 18, 2,128, 0, 10),GenMidi.Operator( 2,253, 5, 2,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Ride Cymbal 1"),
1546 GenMidi.Patch(0x01,128, 96,[GenMidi.Voice(GenMidi.Operator( 0,228,133, 0,128, 0, 14),GenMidi.Operator(192,215, 52, 2,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Chinses Cymbal"),
1547 GenMidi.Patch(0x01,128, 72,[GenMidi.Voice(GenMidi.Operator( 4,226,230, 0,128, 16, 14),GenMidi.Operator( 1,184, 68, 1, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Ride Bell"),
1548 GenMidi.Patch(0x01,128, 79,[GenMidi.Voice(GenMidi.Operator( 2,118,119, 2,128, 7, 15),GenMidi.Operator( 1,152,103, 3, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Tambourine"),
1549 GenMidi.Patch(0x01,128, 69,[GenMidi.Voice(GenMidi.Operator( 4,246,112, 2,128, 1, 14),GenMidi.Operator( 7,198,163, 3, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Splash Cymbal"),
1550 GenMidi.Patch(0x01,128, 71,[GenMidi.Voice(GenMidi.Operator( 0,253,103, 0, 0, 0, 6),GenMidi.Operator( 1,246,152, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Cowbell"),
1551 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator( 4,194,230, 0, 0, 16, 14),GenMidi.Operator( 0,232, 67, 3, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Crash Cymbal 2"),
1552 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 1,249,181, 0, 0, 7, 11),GenMidi.Operator(191,212, 80, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Vibraslap"),
1553 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator( 3,253, 18, 2,128, 0, 10),GenMidi.Operator( 2,253, 5, 2,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Ride Cymbal 2"),
1554 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator( 0,251, 86, 2, 0, 0, 4),GenMidi.Operator( 0,250, 38, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High Bongo"),
1555 GenMidi.Patch(0x01,128, 54,[GenMidi.Voice(GenMidi.Operator( 0,251, 86, 2, 0, 0, 4),GenMidi.Operator( 0,250, 38, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Bango"),
1556 GenMidi.Patch(0x01,128, 72,[GenMidi.Voice(GenMidi.Operator( 0,251, 86, 2,128, 0, 0),GenMidi.Operator( 0,247, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Mute High Conga"),
1557 GenMidi.Patch(0x01,128, 67,[GenMidi.Voice(GenMidi.Operator( 0,251, 86, 2,128, 0, 0),GenMidi.Operator( 0,247, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Open High Conga"),
1558 GenMidi.Patch(0x01,128, 60,[GenMidi.Voice(GenMidi.Operator( 0,251, 86, 2,128, 0, 0),GenMidi.Operator( 0,247, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Conga"),
1559 GenMidi.Patch(0x01,128, 55,[GenMidi.Voice(GenMidi.Operator( 3,251, 86, 0,128, 1, 0),GenMidi.Operator( 0,247, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High Timbale"),
1560 GenMidi.Patch(0x01,128, 48,[GenMidi.Voice(GenMidi.Operator( 3,251, 86, 0,128, 1, 0),GenMidi.Operator( 0,247, 23, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Timbale"),
1561 GenMidi.Patch(0x01,128, 77,[GenMidi.Voice(GenMidi.Operator( 1,253,103, 3, 0, 0, 8),GenMidi.Operator( 1,246,152, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High Agogo"),
1562 GenMidi.Patch(0x01,128, 72,[GenMidi.Voice(GenMidi.Operator( 1,253,103, 3, 0, 0, 8),GenMidi.Operator( 1,246,152, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Agogo"),
1563 GenMidi.Patch(0x01,128, 88,[GenMidi.Voice(GenMidi.Operator( 12,120, 94, 2, 0, 0, 15),GenMidi.Operator( 10,138, 43, 3,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Cabasa"),
1564 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 0, 90,214, 2, 0, 14, 10),GenMidi.Operator(191,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Maracas"),
1565 GenMidi.Patch(0x01,128, 49,[GenMidi.Voice(GenMidi.Operator( 0,249,199, 1, 0, 7, 10),GenMidi.Operator(128,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Short Whistle"),
1566 GenMidi.Patch(0x01,128, 49,[GenMidi.Voice(GenMidi.Operator( 0,249,199, 1, 0, 7, 10),GenMidi.Operator(128,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Long Whistle"),
1567 GenMidi.Patch(0x01,128, 49,[GenMidi.Voice(GenMidi.Operator( 0,249,199, 1, 0, 7, 10),GenMidi.Operator(128,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Short Guiro"),
1568 GenMidi.Patch(0x01,128, 49,[GenMidi.Voice(GenMidi.Operator( 0,249,199, 1, 0, 7, 10),GenMidi.Operator(128,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Long Guiro"),
1569 GenMidi.Patch(0x01,128, 73,[GenMidi.Voice(GenMidi.Operator( 19,248,209, 1, 64, 4, 6),GenMidi.Operator( 18,245,120, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Claves"),
1570 GenMidi.Patch(0x01,128, 68,[GenMidi.Voice(GenMidi.Operator( 19,248,209, 1, 64, 4, 6),GenMidi.Operator( 18,245,120, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"High Wood Block"),
1571 GenMidi.Patch(0x01,128, 61,[GenMidi.Voice(GenMidi.Operator( 19,248,209, 1, 64, 4, 6),GenMidi.Operator( 18,245,120, 0, 0, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Low Wood Block"),
1572 GenMidi.Patch(0x00,128, 0,[GenMidi.Voice(GenMidi.Operator( 1, 94,220, 1, 0, 11, 10),GenMidi.Operator(191,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Mute Cuica"),
1573 GenMidi.Patch(0x01,128, 49,[GenMidi.Voice(GenMidi.Operator( 0,249,199, 1, 0, 7, 10),GenMidi.Operator(128,255,255, 0,192, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Open Cuica"),
1574 GenMidi.Patch(0x01,128, 90,[GenMidi.Voice(GenMidi.Operator(197,242, 96, 0, 64, 15, 8),GenMidi.Operator(212,244,122, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Mute Triangle"),
1575 GenMidi.Patch(0x01,128, 90,[GenMidi.Voice(GenMidi.Operator(133,242, 96, 1, 64, 15, 8),GenMidi.Operator(148,242,183, 0,128, 0, 0), 0),GenMidi.Voice(GenMidi.Operator( 0, 0,240, 0, 0, 0, 0),GenMidi.Operator( 0, 0,240, 0, 0, 0, 0), 0),],"Open Triangle"),
1579 private:
1580 static struct SynthMidiChannel {
1581 ubyte volume;
1582 ushort volume_t;
1583 ubyte pan;
1584 ubyte reg_pan;
1585 ubyte pitch;
1586 const(GenMidi.Patch)* patch;
1587 bool drum;
1590 static struct SynthVoice {
1591 ubyte bank;
1593 ubyte op_base;
1594 ubyte ch_base;
1596 uint freq;
1598 ubyte[2] tl;
1599 ubyte additive;
1601 bool voice_dual;
1602 const(GenMidi.Voice)* voice_data;
1603 const(GenMidi.Patch)* patch;
1605 SynthMidiChannel* chan;
1607 ubyte velocity;
1608 ubyte key;
1609 ubyte note;
1611 int finetune;
1613 ubyte pan;
1616 static align(1) struct MidiHeader {
1617 align(1):
1618 char[4] header;
1619 uint length;
1620 ushort format;
1621 ushort count;
1622 ushort time;
1623 ubyte[0] data;
1626 static align(1) struct MidiTrack {
1627 align(1):
1628 char[4] header;
1629 uint length;
1630 ubyte[0] data;
1633 static struct Track {
1634 const(ubyte)* data;
1635 const(ubyte)* pointer;
1636 uint length;
1637 uint time;
1638 ubyte lastevent;
1639 bool finish;
1640 uint num;
1643 static align(1) struct MusHeader {
1644 align(1):
1645 char[4] header;
1646 ushort length;
1647 ushort offset;
1650 private:
1651 // config
1652 uint mSampleRate;
1653 bool mOPL2Mode;
1654 bool mStereo;
1656 // genmidi lump
1657 version(genmidi_dumper) {
1658 GenMidi mGenMidi;
1659 bool mGenMidiLoaded;
1662 // OPL3 emulator
1663 OPL3Chip chip;
1665 SynthMidiChannel[16] mSynthMidiChannels;
1666 SynthVoice[18] mSynthVoices;
1667 uint mSynthVoiceNum;
1668 SynthVoice*[18] mSynthVoicesAllocated;
1669 uint mSynthVoicesAllocatedNum;
1670 SynthVoice*[18] mSynthVoicesFree;
1671 uint mSynthVoicesFreeNum;
1673 Track[] mMidiTracks;
1674 uint mMidiCount;
1675 uint mMidiTimebase;
1676 uint mMidiCallrate;
1677 uint mMidiTimer;
1678 uint mMidiTimechange;
1679 uint mMidiRate;
1680 uint mMidiFinished;
1681 ubyte[16] mMidiChannels;
1682 ubyte mMidiChannelcnt;
1684 const(ubyte)* mMusData;
1685 const(ubyte)* mMusPointer;
1686 ushort mMusLength;
1687 uint mMusTimer;
1688 uint mMusTimeend;
1689 ubyte[16] mMusChanVelo;
1691 uint mSongTempo;
1692 bool mPlayerActive;
1693 bool mPlayLooped;
1695 enum DataFormat {
1696 Unknown,
1697 Midi,
1698 Mus,
1700 DataFormat mDataFormat = DataFormat.Unknown;
1702 uint mOPLCounter;
1704 ubyte[] songdata;
1706 private:
1707 static ushort MISC_Read16LE (ushort n) pure nothrow @trusted @nogc {
1708 const(ubyte)* m = cast(const(ubyte)*)&n;
1709 return cast(ushort)(m[0]|(m[1]<<8));
1712 static ushort MISC_Read16BE (ushort n) pure nothrow @trusted @nogc {
1713 const(ubyte)* m = cast(const(ubyte)*)&n;
1714 return cast(ushort)(m[1]|(m[0]<<8));
1717 static uint MISC_Read32LE (uint n) pure nothrow @trusted @nogc {
1718 const(ubyte)* m = cast(const(ubyte)*)&n;
1719 return m[0]|(m[1]<<8)|(m[2]<<16)|(m[3]<<24);
1722 static uint MISC_Read32BE (uint n) pure nothrow @trusted @nogc {
1723 const(ubyte)* m = cast(const(ubyte)*)&n;
1724 return m[3]|(m[2]<<8)|(m[1]<<16)|(m[0]<<24);
1727 // ////////////////////////////////////////////////////////////////////// //
1728 // synth
1729 enum SynthCmd : ubyte {
1730 NoteOff,
1731 NoteOn,
1732 PitchBend,
1733 Patch,
1734 Control,
1737 enum SynthCtl : ubyte {
1738 Bank,
1739 Modulation,
1740 Volume,
1741 Pan,
1742 Expression,
1743 Reverb,
1744 Chorus,
1745 Sustain,
1746 Soft,
1747 AllNoteOff,
1748 MonoMode,
1749 PolyMode,
1750 Reset,
1753 void SynthResetVoice (ref SynthVoice voice) nothrow @trusted @nogc {
1754 voice.freq = 0;
1755 voice.voice_dual = false;
1756 voice.voice_data = null;
1757 voice.patch = null;
1758 voice.chan = null;
1759 voice.velocity = 0;
1760 voice.key = 0;
1761 voice.note = 0;
1762 voice.pan = 0x30;
1763 voice.finetune = 0;
1764 voice.tl.ptr[0] = 0x3f;
1765 voice.tl.ptr[1] = 0x3f;
1768 void SynthResetChip (ref OPL3Chip chip) nothrow @safe @nogc {
1769 for (ushort i = 0x40; i < 0x56; ++i) chip.writeReg(i, 0x3f);
1770 for (ushort i = 0x60; i < 0xf6; ++i) chip.writeReg(i, 0x00);
1771 for (ushort i = 0x01; i < 0x40; ++i) chip.writeReg(i, 0x00);
1773 chip.writeReg(0x01, 0x20);
1775 if (!mOPL2Mode) {
1776 chip.writeReg(0x105, 0x01);
1777 for (ushort i = 0x140; i < 0x156; ++i) chip.writeReg(i, 0x3f);
1778 for (ushort i = 0x160; i < 0x1f6; ++i) chip.writeReg(i, 0x00);
1779 for (ushort i = 0x101; i < 0x140; ++i) chip.writeReg(i, 0x00);
1780 chip.writeReg(0x105, 0x01);
1781 } else {
1782 chip.writeReg(0x105, 0x00);
1786 void SynthResetMidi (ref SynthMidiChannel channel) nothrow @trusted @nogc {
1787 channel.volume = 100;
1788 channel.volume_t = opl_voltable.ptr[channel.volume]+1;
1789 channel.pan = 64;
1790 channel.reg_pan = 0x30;
1791 channel.pitch = 64;
1792 channel.patch = &mGenMidi.patch.ptr[0];
1793 channel.drum = false;
1794 if (&channel is &mSynthMidiChannels.ptr[15]) channel.drum = true;
1797 void SynthInit () nothrow @trusted @nogc {
1798 static immutable ubyte[9] opl_slotoffset = [0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12];
1800 for (uint i = 0; i < 18; ++i) {
1801 mSynthVoices.ptr[i].bank = cast(ubyte)(i/9);
1802 mSynthVoices.ptr[i].op_base = opl_slotoffset.ptr[i%9];
1803 mSynthVoices.ptr[i].ch_base = i%9;
1804 SynthResetVoice(mSynthVoices.ptr[i]);
1807 for (uint i = 0; i < 16; ++i) SynthResetMidi(mSynthMidiChannels.ptr[i]);
1809 SynthResetChip(chip);
1811 mSynthVoiceNum = (mOPL2Mode ? 9 : 18);
1813 for (ubyte i = 0; i < mSynthVoiceNum; i++) mSynthVoicesFree.ptr[i] = &mSynthVoices.ptr[i];
1815 mSynthVoicesAllocatedNum = 0;
1816 mSynthVoicesFreeNum = mSynthVoiceNum;
1819 void SynthWriteReg (uint bank, ushort reg, ubyte data) nothrow @trusted @nogc {
1820 reg |= bank<<8;
1821 chip.writeReg(reg, data);
1824 void SynthVoiceOff (SynthVoice* voice) nothrow @trusted @nogc {
1825 SynthWriteReg(voice.bank, cast(ushort)(0xb0+voice.ch_base), cast(ubyte)(voice.freq>>8));
1826 voice.freq = 0;
1827 for (uint i = 0; i < mSynthVoicesAllocatedNum; ++i) {
1828 if (mSynthVoicesAllocated.ptr[i] is voice) {
1829 for (uint j = i; j < mSynthVoicesAllocatedNum-1; ++j) {
1830 mSynthVoicesAllocated.ptr[j] = mSynthVoicesAllocated.ptr[j+1];
1832 break;
1835 --mSynthVoicesAllocatedNum;
1836 mSynthVoicesFree.ptr[mSynthVoicesFreeNum++] = voice;
1839 void SynthVoiceFreq (SynthVoice* voice) nothrow @trusted @nogc {
1840 int freq = voice.chan.pitch+voice.finetune+32*voice.note;
1841 uint block = 0;
1843 if (freq < 0) {
1844 freq = 0;
1845 } else if (freq >= 284) {
1846 freq -= 284;
1847 block = freq/384;
1848 if (block > 7) block = 7;
1849 freq %= 384;
1850 freq += 284;
1853 freq = (block<<10)|opl_freqtable.ptr[freq];
1855 SynthWriteReg(voice.bank, 0xa0+voice.ch_base, freq&0xff);
1856 SynthWriteReg(voice.bank, cast(ushort)(0xb0+voice.ch_base), cast(ubyte)((freq>>8)|0x20));
1858 voice.freq = freq;
1861 void SynthVoiceVolume (SynthVoice* voice) nothrow @trusted @nogc {
1862 ubyte volume = cast(ubyte)(0x3f-(voice.chan.volume_t*opl_voltable.ptr[voice.velocity])/256);
1863 if ((voice.tl.ptr[0]&0x3f) != volume) {
1864 voice.tl.ptr[0] = (voice.tl.ptr[0]&0xc0)|volume;
1865 SynthWriteReg(voice.bank, 0x43+voice.op_base, voice.tl.ptr[0]);
1866 if (voice.additive) {
1867 ubyte volume2 = cast(ubyte)(0x3f-voice.additive);
1868 if (volume2 < volume) volume2 = volume;
1869 volume2 |= voice.tl.ptr[1]&0xc0;
1870 if (volume2 != voice.tl.ptr[1]) {
1871 voice.tl.ptr[1] = volume2;
1872 SynthWriteReg(voice.bank, 0x40+voice.op_base, voice.tl.ptr[1]);
1878 ubyte SynthOperatorSetup (uint bank, uint base, const(GenMidi.Operator)* op, bool volume) nothrow @trusted @nogc {
1879 ubyte tl = op.ksl;
1880 if (volume) tl |= 0x3f; else tl |= op.level;
1881 SynthWriteReg(bank, cast(ushort)(0x40+base), tl);
1882 SynthWriteReg(bank, cast(ushort)(0x20+base), op.mult);
1883 SynthWriteReg(bank, cast(ushort)(0x60+base), op.attack);
1884 SynthWriteReg(bank, cast(ushort)(0x80+base), op.sustain);
1885 SynthWriteReg(bank, cast(ushort)(0xE0+base), op.wave);
1886 return tl;
1889 void SynthVoiceOn (SynthMidiChannel* channel, const(GenMidi.Patch)* patch, bool dual, ubyte key, ubyte velocity) nothrow @trusted @nogc {
1890 SynthVoice* voice;
1891 const(GenMidi.Voice)* voice_data;
1892 uint bank;
1893 uint base;
1894 int note;
1896 if (mSynthVoicesFreeNum == 0) return;
1898 voice = mSynthVoicesFree.ptr[0];
1900 --mSynthVoicesFreeNum;
1902 for (uint i = 0; i < mSynthVoicesFreeNum; ++i) mSynthVoicesFree.ptr[i] = mSynthVoicesFree.ptr[i+1];
1904 mSynthVoicesAllocated.ptr[mSynthVoicesAllocatedNum++] = voice;
1906 voice.chan = channel;
1907 voice.key = key;
1908 voice.velocity = velocity;
1909 voice.patch = patch;
1910 voice.voice_dual = dual;
1912 if (dual) {
1913 voice_data = &patch.voice.ptr[1];
1914 voice.finetune = cast(int)(patch.finetune>>1)-64;
1915 } else {
1916 voice_data = &patch.voice.ptr[0];
1917 voice.finetune = 0;
1920 voice.pan = channel.reg_pan;
1922 if (voice.voice_data != voice_data) {
1923 voice.voice_data = voice_data;
1924 bank = voice.bank;
1925 base = voice.op_base;
1927 voice.tl.ptr[0] = SynthOperatorSetup(bank, base+3, &voice_data.car, true);
1929 if (voice_data.mod.feedback&1) {
1930 voice.additive = cast(ubyte)(0x3f-voice_data.mod.level);
1931 voice.tl.ptr[1] = SynthOperatorSetup(bank, base, &voice_data.mod, true);
1932 } else {
1933 voice.additive = 0;
1934 voice.tl.ptr[1] = SynthOperatorSetup(bank, base, &voice_data.mod, false);
1938 SynthWriteReg(voice.bank, 0xc0+voice.ch_base, voice_data.mod.feedback|voice.pan);
1940 if (MISC_Read16LE(patch.flags)&GenMidi.Patch.Flag.Fixed) {
1941 note = patch.note;
1942 } else {
1943 if (channel.drum) {
1944 note = 60;
1945 } else {
1946 note = key;
1947 note += cast(short)MISC_Read16LE(cast(ushort)voice_data.offset);
1948 while (note < 0) note += 12;
1949 while (note > 95) note -= 12;
1952 voice.note = cast(ubyte)note;
1954 SynthVoiceVolume(voice);
1955 SynthVoiceFreq(voice);
1958 void SynthKillVoice () nothrow @trusted @nogc {
1959 SynthVoice* voice;
1960 if (mSynthVoicesFreeNum > 0) return;
1961 voice = mSynthVoicesAllocated.ptr[0];
1962 for (uint i = 0; i < mSynthVoicesAllocatedNum; i++) {
1963 if (mSynthVoicesAllocated.ptr[i].voice_dual || mSynthVoicesAllocated.ptr[i].chan >= voice.chan) {
1964 voice = mSynthVoicesAllocated.ptr[i];
1967 SynthVoiceOff(voice);
1970 void SynthNoteOff (SynthMidiChannel* channel, ubyte note) nothrow @trusted @nogc {
1971 for (uint i = 0; i < mSynthVoicesAllocatedNum; ) {
1972 if (mSynthVoicesAllocated.ptr[i].chan is channel && mSynthVoicesAllocated.ptr[i].key == note) {
1973 SynthVoiceOff(mSynthVoicesAllocated.ptr[i]);
1974 } else {
1975 ++i;
1980 void SynthNoteOn (SynthMidiChannel* channel, ubyte note, ubyte velo) nothrow @trusted @nogc {
1981 const(GenMidi.Patch)* patch;
1983 if (velo == 0) {
1984 SynthNoteOff(channel, note);
1985 return;
1988 if (channel.drum) {
1989 if (note < 35 || note > 81) return;
1990 patch = &mGenMidi.patch.ptr[note-35+128];
1991 } else {
1992 patch = channel.patch;
1995 SynthKillVoice();
1997 SynthVoiceOn(channel, patch, false, note, velo);
1999 if (mSynthVoicesFreeNum > 0 && MISC_Read16LE(patch.flags)&GenMidi.Patch.Flag.DualVoice) {
2000 SynthVoiceOn(channel, patch, true, note, velo);
2004 void SynthPitchBend (SynthMidiChannel* channel, ubyte pitch) nothrow @trusted @nogc {
2005 SynthVoice*[18] mSynthChannelVoices;
2006 SynthVoice*[18] mSynthOtherVoices;
2008 uint cnt1 = 0;
2009 uint cnt2 = 0;
2011 channel.pitch = pitch;
2013 for (uint i = 0; i < mSynthVoicesAllocatedNum; ++i) {
2014 if (mSynthVoicesAllocated.ptr[i].chan is channel) {
2015 SynthVoiceFreq(mSynthVoicesAllocated.ptr[i]);
2016 mSynthChannelVoices.ptr[cnt1++] = mSynthVoicesAllocated.ptr[i];
2017 } else {
2018 mSynthOtherVoices.ptr[cnt2++] = mSynthVoicesAllocated.ptr[i];
2022 for (uint i = 0; i < cnt2; ++i) mSynthVoicesAllocated.ptr[i] = mSynthOtherVoices.ptr[i];
2023 for (uint i = 0; i < cnt1; ++i) mSynthVoicesAllocated.ptr[i+cnt2] = mSynthChannelVoices.ptr[i];
2026 void SynthUpdatePatch (SynthMidiChannel* channel, ubyte patch) nothrow @trusted @nogc {
2027 if (patch >= mGenMidi.patch.length) patch = 0;
2028 channel.patch = &mGenMidi.patch.ptr[patch];
2031 void SynthUpdatePan (SynthMidiChannel* channel, ubyte pan) nothrow @trusted @nogc {
2032 ubyte new_pan = 0x30;
2033 if (pan <= 48) new_pan = 0x20; else if (pan >= 96) new_pan = 0x10;
2034 channel.pan = pan;
2035 if (channel.reg_pan != new_pan) {
2036 channel.reg_pan = new_pan;
2037 for (uint i = 0; i < mSynthVoicesAllocatedNum; ++i) {
2038 if (mSynthVoicesAllocated.ptr[i].chan is channel) {
2039 mSynthVoicesAllocated.ptr[i].pan = new_pan;
2040 SynthWriteReg(mSynthVoicesAllocated.ptr[i].bank,
2041 0xc0+mSynthVoicesAllocated.ptr[i].ch_base,
2042 mSynthVoicesAllocated.ptr[i].voice_data.mod.feedback|new_pan);
2048 void SynthUpdateVolume (SynthMidiChannel* channel, ubyte volume) nothrow @trusted @nogc {
2049 if (volume&0x80) volume = 0x7f;
2050 if (channel.volume != volume) {
2051 channel.volume = volume;
2052 channel.volume_t = opl_voltable.ptr[channel.volume]+1;
2053 for (uint i = 0; i < mSynthVoicesAllocatedNum; ++i) {
2054 if (mSynthVoicesAllocated.ptr[i].chan is channel) {
2055 SynthVoiceVolume(mSynthVoicesAllocated.ptr[i]);
2061 void SynthNoteOffAll (SynthMidiChannel* channel) nothrow @trusted @nogc {
2062 for (uint i = 0; i < mSynthVoicesAllocatedNum; ) {
2063 if (mSynthVoicesAllocated.ptr[i].chan is channel) {
2064 SynthVoiceOff(mSynthVoicesAllocated.ptr[i]);
2065 } else {
2066 ++i;
2071 void SynthEventReset (SynthMidiChannel* channel) nothrow @trusted @nogc {
2072 SynthNoteOffAll(channel);
2073 channel.reg_pan = 0x30;
2074 channel.pan = 64;
2075 channel.pitch = 64;
2078 void SynthReset () nothrow @trusted @nogc {
2079 for (ubyte i = 0; i < 16; ++i) {
2080 SynthNoteOffAll(&mSynthMidiChannels.ptr[i]);
2081 SynthResetMidi(mSynthMidiChannels.ptr[i]);
2085 void SynthWrite (ubyte command, ubyte data1, ubyte data2) nothrow @trusted @nogc {
2086 SynthMidiChannel* channel = &mSynthMidiChannels.ptr[command&0x0f];
2087 command >>= 4;
2088 switch (command) {
2089 case SynthCmd.NoteOff: SynthNoteOff(channel, data1); break;
2090 case SynthCmd.NoteOn: SynthNoteOn(channel, data1, data2); break;
2091 case SynthCmd.PitchBend: SynthPitchBend(channel, data2); break;
2092 case SynthCmd.Patch: SynthUpdatePatch(channel, data1); break;
2093 case SynthCmd.Control:
2094 switch (data1) {
2095 case SynthCtl.Volume: SynthUpdateVolume(channel, data2); break;
2096 case SynthCtl.Pan: SynthUpdatePan(channel, data2); break;
2097 case SynthCtl.AllNoteOff: SynthNoteOffAll(channel); break;
2098 case SynthCtl.Reset: SynthEventReset(channel); break;
2099 default: break;
2101 break;
2102 default: break;
2106 // ////////////////////////////////////////////////////////////////////// //
2107 // MIDI
2108 uint MIDI_ReadDelay (const(ubyte)** data) nothrow @trusted @nogc {
2109 const(ubyte)* dn = *data;
2110 uint delay = 0;
2111 do {
2112 delay = (delay<<7)|((*dn)&0x7f);
2113 } while (*dn++&0x80);
2114 *data = dn;
2115 return delay;
2118 bool MIDI_LoadSong () nothrow @trusted {
2119 enum midh = "MThd";
2120 enum mtrkh = "MTrk";
2122 import core.stdc.string : memcmp;
2124 if (songdata.length <= MidiHeader.sizeof) return false;
2125 const(MidiHeader)* mid = cast(const(MidiHeader)*)songdata.ptr;
2127 if (memcmp(mid.header.ptr, midh.ptr, 4) != 0 || MISC_Read32BE(mid.length) != 6) return false;
2129 mMidiCount = MISC_Read16BE(mid.count);
2130 const(ubyte)[] midi_data = mid.data.ptr[0..songdata.length-MidiHeader.sizeof];
2131 mMidiTimebase = MISC_Read16BE(mid.time);
2133 if (mMidiTracks !is null) delete mMidiTracks;
2135 mMidiTracks = new Track[](mMidiCount);
2137 uint trknum = 0;
2138 while (trknum < mMidiCount) {
2139 if (midi_data.length < 8) { delete mMidiTracks; return false; } // out of data
2140 const(MidiTrack)* track = cast(const(MidiTrack)*)midi_data.ptr;
2141 uint datasize = MISC_Read32BE(track.length);
2142 if (midi_data.length-8 < datasize) { delete mMidiTracks; return false; } // out of data
2143 if (memcmp(track.header.ptr, mtrkh.ptr, 4) != 0) {
2144 // not a track, skip this chunk
2145 midi_data = midi_data[datasize+8..$];
2146 } else {
2147 // track
2148 mMidiTracks[trknum].length = datasize;
2149 mMidiTracks[trknum].data = track.data.ptr;
2150 mMidiTracks[trknum].num = trknum++;
2151 // move to next chunk
2152 midi_data = midi_data[datasize+8..$];
2155 // check if we have all tracks
2156 if (trknum != mMidiCount) { delete mMidiTracks; return false; } // out of tracks
2158 mDataFormat = DataFormat.Midi;
2160 return true;
2163 bool MIDI_StartSong () nothrow @trusted @nogc {
2164 if (mDataFormat != DataFormat.Midi || mPlayerActive) return false;
2166 for (uint i = 0; i < mMidiCount; ++i) {
2167 mMidiTracks[i].pointer = mMidiTracks[i].data;
2168 mMidiTracks[i].time = MIDI_ReadDelay(&mMidiTracks[i].pointer);
2169 mMidiTracks[i].lastevent = 0x80;
2170 mMidiTracks[i].finish = 0;
2173 for (uint i = 0; i < 16; ++i) mMidiChannels.ptr[i] = 0xff;
2175 mMidiChannelcnt = 0;
2177 mMidiRate = 1000000/(500000/mMidiTimebase);
2178 mMidiCallrate = mSongTempo;
2179 mMidiTimer = 0;
2180 mMidiTimechange = 0;
2181 mMidiFinished = 0;
2183 mPlayerActive = true;
2185 return true;
2188 void MIDI_StopSong () nothrow @trusted @nogc {
2189 if (mDataFormat != DataFormat.Midi || !mPlayerActive) return;
2190 mPlayerActive = false;
2191 for (uint i = 0; i < 16; ++i) {
2192 SynthWrite(cast(ubyte)((SynthCmd.Control<<4)|i), SynthCtl.AllNoteOff, 0);
2194 SynthReset();
2197 Track* MIDI_NextTrack () nothrow @trusted @nogc {
2198 Track* mintrack = &mMidiTracks[0];
2199 for (uint i = 1; i < mMidiCount; i++) {
2200 if ((mMidiTracks[i].time < mintrack.time && !mMidiTracks[i].finish) || mintrack.finish) {
2201 mintrack = &mMidiTracks[i];
2204 return mintrack;
2207 ubyte MIDI_GetChannel (ubyte chan) nothrow @trusted @nogc {
2208 if (chan == 9) return 15;
2209 if (mMidiChannels.ptr[chan] == 0xff) mMidiChannels.ptr[chan] = mMidiChannelcnt++;
2210 return mMidiChannels.ptr[chan];
2213 void MIDI_Command (const(ubyte)** datap, ubyte evnt) nothrow @trusted @nogc {
2214 ubyte chan;
2215 const(ubyte)* data;
2216 ubyte v1, v2;
2218 data = *datap;
2219 chan = MIDI_GetChannel(evnt&0x0f);
2220 switch (evnt&0xf0) {
2221 case 0x80:
2222 v1 = *data++;
2223 v2 = *data++;
2224 SynthWrite((SynthCmd.NoteOff<<4)|chan, v1, 0);
2225 break;
2226 case 0x90:
2227 v1 = *data++;
2228 v2 = *data++;
2229 SynthWrite((SynthCmd.NoteOn<<4)|chan, v1, v2);
2230 break;
2231 case 0xa0:
2232 data += 2;
2233 break;
2234 case 0xb0:
2235 v1 = *data++;
2236 v2 = *data++;
2237 switch (v1) {
2238 case 0x00: case 0x20: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Bank, v2); break;
2239 case 0x01: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Modulation, v2); break;
2240 case 0x07: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Volume, v2); break;
2241 case 0x0a: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Pan, v2); break;
2242 case 0x0b: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Expression, v2); break;
2243 case 0x40: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Sustain, v2); break;
2244 case 0x43: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Soft, v2); break;
2245 case 0x5b: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Reverb, v2); break;
2246 case 0x5d: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Chorus, v2); break;
2247 case 0x78: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.AllNoteOff, v2); break;
2248 case 0x79: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Reset, v2); break;
2249 case 0x7b: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.AllNoteOff, v2); break;
2250 case 0x7e: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.MonoMode, v2); break;
2251 case 0x7f: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.PolyMode, v2); break;
2252 default: break;
2254 break;
2255 case 0xc0:
2256 v1 = *data++;
2257 SynthWrite((SynthCmd.Patch<<4)|chan, v1, 0);
2258 break;
2259 case 0xd0:
2260 data += 1;
2261 break;
2262 case 0xe0:
2263 v1 = *data++;
2264 v2 = *data++;
2265 SynthWrite((SynthCmd.PitchBend<<4)|chan, v1, v2);
2266 break;
2267 default: break;
2269 *datap = data;
2272 void MIDI_FinishTrack (Track* trck) nothrow @trusted @nogc {
2273 if (trck.finish) return;
2274 trck.finish = true;
2275 ++mMidiFinished;
2278 void MIDI_AdvanceTrack (Track* trck) nothrow @trusted @nogc {
2279 ubyte evnt;
2280 ubyte meta;
2281 ubyte length;
2282 uint tempo;
2283 const(ubyte)* data;
2285 evnt = *trck.pointer++;
2287 if (!(evnt&0x80)) {
2288 evnt = trck.lastevent;
2289 --trck.pointer;
2292 switch (evnt) {
2293 case 0xf0:
2294 case 0xf7:
2295 length = cast(ubyte)MIDI_ReadDelay(&trck.pointer);
2296 trck.pointer += length;
2297 break;
2298 case 0xff:
2299 meta = *trck.pointer++;
2300 length = cast(ubyte)MIDI_ReadDelay(&trck.pointer);
2301 data = trck.pointer;
2302 trck.pointer += length;
2303 switch (meta) {
2304 case 0x2f:
2305 MIDI_FinishTrack(trck);
2306 break;
2307 case 0x51:
2308 if (length == 0x03) {
2309 tempo = (data[0]<<16)|(data[1]<<8)|data[2];
2310 mMidiTimechange += (mMidiTimer*mMidiRate)/mMidiCallrate;
2311 mMidiTimer = 0;
2312 mMidiRate = 1000000/(tempo/mMidiTimebase);
2314 break;
2315 default: break;
2317 break;
2318 default:
2319 MIDI_Command(&trck.pointer,evnt);
2320 break;
2323 trck.lastevent = evnt;
2324 if (trck.pointer >= trck.data+trck.length) MIDI_FinishTrack(trck);
2327 void MIDI_Callback () nothrow @trusted @nogc {
2328 Track* trck;
2330 if (mDataFormat != DataFormat.Midi || !mPlayerActive) return;
2332 for (;;) {
2333 trck = MIDI_NextTrack();
2334 if (trck.finish || trck.time > mMidiTimechange+(mMidiTimer*mMidiRate)/mMidiCallrate) break;
2335 MIDI_AdvanceTrack(trck);
2336 if (!trck.finish) trck.time += MIDI_ReadDelay(&trck.pointer);
2339 ++mMidiTimer;
2341 if (mMidiFinished == mMidiCount) {
2342 if (!mPlayLooped) MIDI_StopSong();
2343 for (uint i = 0; i < mMidiCount; i++) {
2344 mMidiTracks[i].pointer = mMidiTracks[i].data;
2345 mMidiTracks[i].time = MIDI_ReadDelay(&mMidiTracks[i].pointer);
2346 mMidiTracks[i].lastevent = 0x80;
2347 mMidiTracks[i].finish = 0;
2350 for (uint i = 0; i < 16; i++) mMidiChannels.ptr[i] = 0xff;
2352 mMidiChannelcnt = 0;
2354 mMidiRate = 1000000/(500000/mMidiTimebase);
2355 mMidiTimer = 0;
2356 mMidiTimechange = 0;
2357 mMidiFinished = 0;
2359 SynthReset();
2363 // ////////////////////////////////////////////////////////////////////// //
2364 // MUS
2365 void MUS_Callback () nothrow @trusted @nogc {
2366 if (mDataFormat != DataFormat.Mus || !mPlayerActive) return;
2367 while (mMusTimer == mMusTimeend) {
2368 ubyte cmd;
2369 ubyte evnt;
2370 ubyte chan;
2371 ubyte data1;
2372 ubyte data2;
2374 cmd = *mMusPointer++;
2375 chan = cmd&0x0f;
2376 evnt = (cmd>>4)&7;
2378 switch (evnt) {
2379 case 0x00:
2380 data1 = *mMusPointer++;
2381 SynthWrite((SynthCmd.NoteOff<<4)|chan, data1, 0);
2382 break;
2383 case 0x01:
2384 data1 = *mMusPointer++;
2385 if (data1&0x80) {
2386 data1 &= 0x7f;
2387 mMusChanVelo.ptr[chan] = *mMusPointer++;
2389 SynthWrite((SynthCmd.NoteOn<<4)|chan, data1, mMusChanVelo.ptr[chan]);
2390 break;
2391 case 0x02:
2392 data1 = *mMusPointer++;
2393 SynthWrite((SynthCmd.PitchBend<<4)|chan, (data1&1)<<6, data1>>1);
2394 break;
2395 case 0x03:
2396 case 0x04:
2397 data1 = *mMusPointer++;
2398 data2 = 0;
2399 if (evnt == 0x04) data2 = *mMusPointer++;
2400 switch (data1) {
2401 case 0x00: SynthWrite((SynthCmd.Patch<<4)|chan, data2, 0); break;
2402 case 0x01: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Bank, data2); break;
2403 case 0x02: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Modulation, data2); break;
2404 case 0x03: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Volume, data2); break;
2405 case 0x04: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Pan, data2); break;
2406 case 0x05: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Expression, data2); break;
2407 case 0x06: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Reverb, data2); break;
2408 case 0x07: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Chorus, data2); break;
2409 case 0x08: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Sustain, data2); break;
2410 case 0x09: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Soft, data2); break;
2411 case 0x0a: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.AllNoteOff, data2); break;
2412 case 0x0b: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.AllNoteOff, data2); break;
2413 case 0x0c: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.MonoMode, data2); break;
2414 case 0x0d: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.PolyMode, data2); break;
2415 case 0x0e: SynthWrite((SynthCmd.Control<<4)|chan, SynthCtl.Reset, data2); break;
2416 case 0x0f: break;
2417 default: break;
2419 break;
2420 case 0x05:
2421 break;
2422 case 0x06:
2423 if (!mPlayLooped) {
2424 MUS_StopSong();
2425 return;
2427 mMusPointer = mMusData;
2428 cmd = 0;
2429 SynthReset();
2430 break;
2431 case 0x07:
2432 ++mMusPointer;
2433 break;
2434 default: break;
2437 if (cmd&0x80) {
2438 mMusTimeend += MIDI_ReadDelay(&mMusPointer);
2439 break;
2442 ++mMusTimer;
2445 bool MUS_LoadSong () nothrow @trusted @nogc {
2446 enum mush = "MUS\x1a";
2447 import core.stdc.string : memcmp;
2448 if (songdata.length <= MusHeader.sizeof) return false;
2449 const(MusHeader)* mus = cast(const(MusHeader)*)songdata.ptr;
2450 if (memcmp(mus.header.ptr, mush.ptr, 4) != 0) return false;
2451 mMusLength = MISC_Read16LE(mus.length);
2452 uint musofs = MISC_Read16LE(mus.offset);
2453 if (musofs >= songdata.length) return false;
2454 if (songdata.length-musofs < mMusLength) return false;
2455 mMusData = &(cast(const(ubyte)*)songdata.ptr)[musofs];
2456 mDataFormat = DataFormat.Mus;
2457 return true;
2460 bool MUS_StartSong () nothrow @trusted @nogc {
2461 if (mDataFormat != DataFormat.Mus || mPlayerActive) return true;
2462 mMusPointer = mMusData;
2463 mMusTimer = 0;
2464 mMusTimeend = 0;
2465 mPlayerActive = true;
2466 return false;
2469 void MUS_StopSong () nothrow @trusted @nogc {
2470 if (mDataFormat != DataFormat.Mus || !mPlayerActive) return;
2471 mPlayerActive = false;
2472 for (uint i = 0; i < 16; i++) {
2473 SynthWrite(cast(ubyte)((SynthCmd.Control<<4)|i), SynthCtl.AllNoteOff, 0);
2475 SynthReset();
2478 void PlayerInit () nothrow @trusted @nogc {
2479 mSongTempo = DefaultTempo;
2480 mPlayerActive = false;
2481 mDataFormat = DataFormat.Unknown;
2482 mPlayLooped = false;
2483 mMidiTracks = null;
2486 version(genmidi_dumper) static immutable string genmidiData = import("GENMIDI.lmp");
2488 version(genmidi_dumper) bool loadGenMIDI (const(void)* data) nothrow @trusted @nogc {
2489 import core.stdc.string : memcmp, memcpy;
2490 static immutable string genmidi_head = "#OPL_II#";
2491 if (memcmp(data, data, 8) != 0) return false;
2492 memcpy(&mGenMidi, (cast(const(ubyte)*)data)+8, GenMidi.sizeof);
2493 mGenMidiLoaded = true;
2494 return true;
2497 version(genmidi_dumper) public void dumpGenMidi (VFile fo) { mGenMidi.dump(fo); }
2499 public:
2500 enum DefaultTempo = 140;
2502 public:
2503 this (int asamplerate=48000, bool aopl3mode=true, bool astereo=true) nothrow @trusted @nogc {
2504 version(genmidi_dumper) mGenMidiLoaded = false;
2505 songdata = null;
2506 sendConfig(asamplerate, aopl3mode, astereo);
2507 SynthInit();
2508 PlayerInit();
2509 mOPLCounter = 0;
2510 version(genmidi_dumper) loadGenMIDI(genmidiData.ptr);
2513 private void sendConfig (int asamplerate, bool aopl3mode, bool astereo) nothrow @safe @nogc {
2514 if (asamplerate < 4096) asamplerate = 4096;
2515 if (asamplerate > 96000) asamplerate = 96000;
2516 mSampleRate = asamplerate;
2517 chip.reset(mSampleRate);
2518 mOPL2Mode = !aopl3mode;
2519 mStereo = astereo;
2520 SynthInit();
2523 bool load (const(void)[] data) {
2524 import core.stdc.string : memcpy;
2525 stop(); // just in case
2526 mDataFormat = DataFormat.Unknown;
2527 delete songdata;
2528 version(genmidi_dumper) if (!mGenMidiLoaded) return false;
2529 // just in case
2530 scope(failure) {
2531 mDataFormat = DataFormat.Unknown;
2532 delete songdata;
2534 if (data.length == 0) return false;
2535 songdata.length = data.length;
2536 memcpy(songdata.ptr, data.ptr, data.length);
2537 if (MUS_LoadSong() || MIDI_LoadSong()) return true;
2538 mDataFormat = DataFormat.Unknown;
2539 delete songdata;
2540 return false;
2543 @property void tempo (uint atempo) pure nothrow @safe @nogc {
2544 if (atempo < 1) atempo = 1; else if (atempo > 255) atempo = 255;
2545 mSongTempo = atempo;
2548 @property uint tempo () const pure nothrow @safe @nogc { return mSongTempo; }
2550 @property void looped (bool loop) pure nothrow @safe @nogc { mPlayLooped = loop; }
2551 @property bool looped () const pure nothrow @safe @nogc { return mPlayLooped; }
2553 @property bool loaded () const pure nothrow @safe @nogc { return (mDataFormat != DataFormat.Unknown); }
2555 @property bool playing () const pure nothrow @safe @nogc { return mPlayerActive; }
2557 @property void stereo (bool v) pure nothrow @safe @nogc { mStereo = v; }
2558 @property bool stereo () const pure nothrow @safe @nogc { return mStereo; }
2560 // returns `false` if song cannot be started (or if it is already playing)
2561 bool play () nothrow @safe @nogc {
2562 bool res = false;
2563 final switch (mDataFormat) {
2564 case DataFormat.Unknown: break;
2565 case DataFormat.Midi: res = MIDI_StartSong(); break;
2566 case DataFormat.Mus: res = MUS_StartSong(); break;
2568 return res;
2571 void stop () nothrow @safe @nogc {
2572 final switch (mDataFormat) {
2573 case DataFormat.Unknown: break;
2574 case DataFormat.Midi: MIDI_StopSong(); break;
2575 case DataFormat.Mus: MUS_StopSong(); break;
2579 // return number of generated *frames*
2580 // returns 0 if song is complete (and player is not looped)
2581 uint generate (short[] buffer) nothrow @trusted @nogc {
2582 if (mDataFormat == DataFormat.Unknown) return 0;
2583 if (buffer.length > uint.max/64) buffer = buffer[0..uint.max/64];
2584 uint length = cast(uint)buffer.length;
2585 if (mStereo) length /= 2;
2586 if (length < 1) return 0; // oops
2587 short[2] accm = void;
2588 uint i = 0;
2589 while (i < length) {
2590 if (!mPlayerActive) break;
2591 while (mOPLCounter >= mSampleRate) {
2592 if (mPlayerActive) {
2593 final switch (mDataFormat) {
2594 case DataFormat.Unknown: assert(0, "the thing that should not be");
2595 case DataFormat.Midi: MIDI_Callback(); break;
2596 case DataFormat.Mus: MUS_Callback(); break;
2599 mOPLCounter -= mSampleRate;
2601 mOPLCounter += mSongTempo;
2602 chip.generateResampled(accm.ptr);
2603 if (mStereo) {
2604 buffer.ptr[i*2] = accm.ptr[0];
2605 buffer.ptr[i*2+1] = accm.ptr[1];
2606 } else {
2607 buffer.ptr[i] = (accm.ptr[0]+accm.ptr[1])/2;
2609 ++i;
2611 return i;