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