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