lowercasing filenames, part3
[picodrive.git] / pico / sound / ym2612.c
diff --git a/pico/sound/ym2612.c b/pico/sound/ym2612.c
new file mode 100644 (file)
index 0000000..4b64fb4
--- /dev/null
@@ -0,0 +1,2057 @@
+/*\r
+** This is a bunch of remains of original fm.c from MAME project. All stuff\r
+** unrelated to ym2612 was removed, multiple chip support was removed,\r
+** some parts of code were slightly rewritten and tied to the emulator.\r
+**\r
+** SSG-EG was also removed, because it's rarely used, Sega2.doc even does not\r
+** document it ("proprietary") and tells to write 0 to SSG-EG control register.\r
+*/\r
+\r
+/*\r
+**\r
+** File: fm.c -- software implementation of Yamaha FM sound generator\r
+**\r
+** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net)\r
+** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development\r
+**\r
+** Version 1.4 (final beta)\r
+**\r
+*/\r
+\r
+/*\r
+** History:\r
+**\r
+** 03-08-2003 Jarek Burczynski:\r
+**  - fixed YM2608 initial values (after the reset)\r
+**  - fixed flag and irqmask handling (YM2608)\r
+**  - fixed BUFRDY flag handling (YM2608)\r
+**\r
+** 14-06-2003 Jarek Burczynski:\r
+**  - implemented all of the YM2608 status register flags\r
+**  - implemented support for external memory read/write via YM2608\r
+**  - implemented support for deltat memory limit register in YM2608 emulation\r
+**\r
+** 22-05-2003 Jarek Burczynski:\r
+**  - fixed LFO PM calculations (copy&paste bugfix)\r
+**\r
+** 08-05-2003 Jarek Burczynski:\r
+**  - fixed SSG support\r
+**\r
+** 22-04-2003 Jarek Burczynski:\r
+**  - implemented 100% correct LFO generator (verified on real YM2610 and YM2608)\r
+**\r
+** 15-04-2003 Jarek Burczynski:\r
+**  - added support for YM2608's register 0x110 - status mask\r
+**\r
+** 01-12-2002 Jarek Burczynski:\r
+**  - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608)\r
+**    The addressing patch used for early Neo-Geo games can be removed now.\r
+**\r
+** 26-11-2002 Jarek Burczynski, Nicola Salmoria:\r
+**  - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to:\r
+**  - added emulation of YM2608 drums.\r
+**  - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608)\r
+**\r
+** 16-08-2002 Jarek Burczynski:\r
+**  - binary exact Envelope Generator (verified on real YM2203);\r
+**    identical to YM2151\r
+**  - corrected 'off by one' error in feedback calculations (when feedback is off)\r
+**  - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610)\r
+**\r
+** 18-12-2001 Jarek Burczynski:\r
+**  - added SSG-EG support (verified on real YM2203)\r
+**\r
+** 12-08-2001 Jarek Burczynski:\r
+**  - corrected ym_sin_tab and ym_tl_tab data (verified on real chip)\r
+**  - corrected feedback calculations (verified on real chip)\r
+**  - corrected phase generator calculations (verified on real chip)\r
+**  - corrected envelope generator calculations (verified on real chip)\r
+**  - corrected FM volume level (YM2610 and YM2610B).\r
+**  - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) :\r
+**    this was needed to calculate YM2610 FM channels output correctly.\r
+**    (Each FM channel is calculated as in other chips, but the output of the channel\r
+**    gets shifted right by one *before* sending to accumulator. That was impossible to do\r
+**    with previous implementation).\r
+**\r
+** 23-07-2001 Jarek Burczynski, Nicola Salmoria:\r
+**  - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip)\r
+**\r
+** 11-06-2001 Jarek Burczynski:\r
+**  - corrected end of sample bug in ADPCMA_calc_cha().\r
+**    Real YM2610 checks for equality between current and end addresses (only 20 LSB bits).\r
+**\r
+** 08-12-98 hiro-shi:\r
+** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA\r
+** move ROM limit check.(CALC_CH? -> 2610Write1/2)\r
+** test program (ADPCMB_TEST)\r
+** move ADPCM A/B end check.\r
+** ADPCMB repeat flag(no check)\r
+** change ADPCM volume rate (8->16) (32->48).\r
+**\r
+** 09-12-98 hiro-shi:\r
+** change ADPCM volume. (8->16, 48->64)\r
+** replace ym2610 ch0/3 (YM-2610B)\r
+** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff.\r
+** add ADPCM_SHIFT_MASK\r
+** change ADPCMA_DECODE_MIN/MAX.\r
+*/\r
+\r
+\r
+\r
+\r
+/************************************************************************/\r
+/*    comment of hiro-shi(Hiromitsu Shioya)                             */\r
+/*    YM2610(B) = OPN-B                                                 */\r
+/*    YM2610  : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch      */\r
+/*    YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch      */\r
+/************************************************************************/\r
+\r
+//#include <stdio.h>\r
+\r
+#include <string.h>\r
+#include <math.h>\r
+\r
+#include "ym2612.h"\r
+\r
+#ifndef EXTERNAL_YM2612\r
+#include <stdlib.h>\r
+// let it be 1 global to simplify things\r
+YM2612 ym2612;\r
+\r
+#else\r
+extern YM2612 *ym2612_940;\r
+#define ym2612 (*ym2612_940)\r
+\r
+#endif\r
+\r
+void memset32(int *dest, int c, int count);\r
+\r
+\r
+#ifndef __GNUC__\r
+#pragma warning (disable:4100) // unreferenced formal parameter\r
+#pragma warning (disable:4244)\r
+#pragma warning (disable:4245) // signed/unsigned in conversion\r
+#pragma warning (disable:4710)\r
+#pragma warning (disable:4018) // signed/unsigned\r
+#endif\r
+\r
+#ifndef INLINE\r
+#define INLINE static __inline\r
+#endif\r
+\r
+#ifndef M_PI\r
+#define M_PI    3.14159265358979323846\r
+#endif\r
+\r
+\r
+/* globals */\r
+\r
+#define FREQ_SH                        16  /* 16.16 fixed point (frequency calculations) */\r
+#define EG_SH                  16  /* 16.16 fixed point (envelope generator timing) */\r
+#define LFO_SH                 25  /*  7.25 fixed point (LFO calculations)       */\r
+#define TIMER_SH               16  /* 16.16 fixed point (timers calculations)    */\r
+\r
+#define ENV_BITS               10\r
+#define ENV_LEN                        (1<<ENV_BITS)\r
+#define ENV_STEP               (128.0/ENV_LEN)\r
+\r
+#define MAX_ATT_INDEX  (ENV_LEN-1) /* 1023 */\r
+#define MIN_ATT_INDEX  (0)                     /* 0 */\r
+\r
+#define EG_ATT                 4\r
+#define EG_DEC                 3\r
+#define EG_SUS                 2\r
+#define EG_REL                 1\r
+#define EG_OFF                 0\r
+\r
+#define SIN_BITS               10\r
+#define SIN_LEN                        (1<<SIN_BITS)\r
+#define SIN_MASK               (SIN_LEN-1)\r
+\r
+#define TL_RES_LEN             (256) /* 8 bits addressing (real chip) */\r
+\r
+#define EG_TIMER_OVERFLOW (3*(1<<EG_SH)) /* envelope generator timer overflows every 3 samples (on real chip) */\r
+\r
+#define MAXOUT         (+32767)\r
+#define MINOUT         (-32768)\r
+\r
+/* limitter */\r
+#define Limit(val, max,min) { \\r
+       if ( val > max )      val = max; \\r
+       else if ( val < min ) val = min; \\r
+}\r
+\r
+\r
+/*  TL_TAB_LEN is calculated as:\r
+*   13 - sinus amplitude bits     (Y axis)\r
+*   2  - sinus sign bit           (Y axis)\r
+*   TL_RES_LEN - sinus resolution (X axis)\r
+*/\r
+//#define TL_TAB_LEN (13*2*TL_RES_LEN)\r
+#define TL_TAB_LEN (13*TL_RES_LEN*256/8) // 106496*2\r
+UINT16 ym_tl_tab[TL_TAB_LEN];\r
+\r
+/* ~3K wasted but oh well */\r
+UINT16 ym_tl_tab2[13*TL_RES_LEN];\r
+\r
+#define ENV_QUIET              (2*13*TL_RES_LEN/8)\r
+\r
+/* sin waveform table in 'decibel' scale (use only period/4 values) */\r
+static UINT16 ym_sin_tab[256];\r
+\r
+/* sustain level table (3dB per step) */\r
+/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */\r
+/* 1,    2,    4,    8,    16,   32,   64   (value)*/\r
+/* 0.75, 1.5,  3,    6,    12,   24,   48   (dB)*/\r
+\r
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/\r
+#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) )\r
+static const UINT32 sl_table[16]={\r
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),\r
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)\r
+};\r
+#undef SC\r
+\r
+\r
+#if 0\r
+#define RATE_STEPS (8)\r
+static const UINT8 eg_inc[19*RATE_STEPS]={\r
+\r
+/*cycle:0 1  2 3  4 5  6 7*/\r
+\r
+/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */\r
+/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */\r
+/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */\r
+/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */\r
+\r
+/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */\r
+/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */\r
+/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */\r
+/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */\r
+\r
+/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */\r
+/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */\r
+/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */\r
+/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */\r
+\r
+/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */\r
+/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */\r
+/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */\r
+/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */\r
+\r
+/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */\r
+/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */\r
+/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */\r
+};\r
+#endif\r
+\r
+\r
+#define PACK(a0,a1,a2,a3,a4,a5,a6,a7) ((a7<<21)|(a6<<18)|(a5<<15)|(a4<<12)|(a3<<9)|(a2<<6)|(a1<<3)|(a0<<0))\r
+static const UINT32 eg_inc_pack[19] =\r
+{\r
+/* 0 */ PACK(0,1,0,1,0,1,0,1), /* rates 00..11 0 (increment by 0 or 1) */\r
+/* 1 */ PACK(0,1,0,1,1,1,0,1), /* rates 00..11 1 */\r
+/* 2 */ PACK(0,1,1,1,0,1,1,1), /* rates 00..11 2 */\r
+/* 3 */ PACK(0,1,1,1,1,1,1,1), /* rates 00..11 3 */\r
+\r
+/* 4 */ PACK(1,1,1,1,1,1,1,1), /* rate 12 0 (increment by 1) */\r
+/* 5 */ PACK(1,1,1,2,1,1,1,2), /* rate 12 1 */\r
+/* 6 */ PACK(1,2,1,2,1,2,1,2), /* rate 12 2 */\r
+/* 7 */ PACK(1,2,2,2,1,2,2,2), /* rate 12 3 */\r
+\r
+/* 8 */ PACK(2,2,2,2,2,2,2,2), /* rate 13 0 (increment by 2) */\r
+/* 9 */ PACK(2,2,2,3,2,2,2,3), /* rate 13 1 */\r
+/*10 */ PACK(2,3,2,3,2,3,2,3), /* rate 13 2 */\r
+/*11 */ PACK(2,3,3,3,2,3,3,3), /* rate 13 3 */\r
+\r
+/*12 */ PACK(3,3,3,3,3,3,3,3), /* rate 14 0 (increment by 4) */\r
+/*13 */ PACK(3,3,3,4,3,3,3,4), /* rate 14 1 */\r
+/*14 */ PACK(3,4,3,4,3,4,3,4), /* rate 14 2 */\r
+/*15 */ PACK(3,4,4,4,3,4,4,4), /* rate 14 3 */\r
+\r
+/*16 */ PACK(4,4,4,4,4,4,4,4), /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */\r
+/*17 */ PACK(5,5,5,5,5,5,5,5), /* rates 15 2, 15 3 for attack */\r
+/*18 */ PACK(0,0,0,0,0,0,0,0), /* infinity rates for attack and decay(s) */\r
+};\r
+\r
+\r
+//#define O(a) (a*RATE_STEPS)\r
+#define O(a) a\r
+\r
+/*note that there is no O(17) in this table - it's directly in the code */\r
+static const UINT8 eg_rate_select[32+64+32]={  /* Envelope Generator rates (32 + 64 rates + 32 RKS) */\r
+/* 32 infinite time rates */\r
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),\r
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),\r
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),\r
+O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),\r
+\r
+/* rates 00-11 */\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+O( 0),O( 1),O( 2),O( 3),\r
+\r
+/* rate 12 */\r
+O( 4),O( 5),O( 6),O( 7),\r
+\r
+/* rate 13 */\r
+O( 8),O( 9),O(10),O(11),\r
+\r
+/* rate 14 */\r
+O(12),O(13),O(14),O(15),\r
+\r
+/* rate 15 */\r
+O(16),O(16),O(16),O(16),\r
+\r
+/* 32 dummy rates (same as 15 3) */\r
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),\r
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),\r
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),\r
+O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16)\r
+\r
+};\r
+#undef O\r
+\r
+/*rate  0,    1,    2,   3,   4,   5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15*/\r
+/*shift 11,   10,   9,   8,   7,   6,  5,  4,  3,  2, 1,  0,  0,  0,  0,  0 */\r
+/*mask  2047, 1023, 511, 255, 127, 63, 31, 15, 7,  3, 1,  0,  0,  0,  0,  0 */\r
+\r
+#define O(a) (a*1)\r
+static const UINT8 eg_rate_shift[32+64+32]={   /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */\r
+/* 32 infinite time rates */\r
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),\r
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),\r
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),\r
+O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),\r
+\r
+/* rates 00-11 */\r
+O(11),O(11),O(11),O(11),\r
+O(10),O(10),O(10),O(10),\r
+O( 9),O( 9),O( 9),O( 9),\r
+O( 8),O( 8),O( 8),O( 8),\r
+O( 7),O( 7),O( 7),O( 7),\r
+O( 6),O( 6),O( 6),O( 6),\r
+O( 5),O( 5),O( 5),O( 5),\r
+O( 4),O( 4),O( 4),O( 4),\r
+O( 3),O( 3),O( 3),O( 3),\r
+O( 2),O( 2),O( 2),O( 2),\r
+O( 1),O( 1),O( 1),O( 1),\r
+O( 0),O( 0),O( 0),O( 0),\r
+\r
+/* rate 12 */\r
+O( 0),O( 0),O( 0),O( 0),\r
+\r
+/* rate 13 */\r
+O( 0),O( 0),O( 0),O( 0),\r
+\r
+/* rate 14 */\r
+O( 0),O( 0),O( 0),O( 0),\r
+\r
+/* rate 15 */\r
+O( 0),O( 0),O( 0),O( 0),\r
+\r
+/* 32 dummy rates (same as 15 3) */\r
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),\r
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),\r
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),\r
+O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0)\r
+\r
+};\r
+#undef O\r
+\r
+static const UINT8 dt_tab[4 * 32]={\r
+/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/\r
+/* FD=0 */\r
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/* FD=1 */\r
+       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,\r
+       2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,\r
+/* FD=2 */\r
+       1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,\r
+       5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,\r
+/* FD=3 */\r
+       2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,\r
+       8 ,8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22\r
+};\r
+\r
+\r
+/* OPN key frequency number -> key code follow table */\r
+/* fnum higher 4bit -> keycode lower 2bit */\r
+static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};\r
+\r
+\r
+/* 8 LFO speed parameters */\r
+/* each value represents number of samples that one LFO level will last for */\r
+static const UINT32 lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5};\r
+\r
+\r
+\r
+/*There are 4 different LFO AM depths available, they are:\r
+  0 dB, 1.4 dB, 5.9 dB, 11.8 dB\r
+  Here is how it is generated (in EG steps):\r
+\r
+  11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0\r
+   5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0\r
+   1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0\r
+\r
+  (1.4 dB is loosing precision as you can see)\r
+\r
+  It's implemented as generator from 0..126 with step 2 then a shift\r
+  right N times, where N is:\r
+    8 for 0 dB\r
+    3 for 1.4 dB\r
+    1 for 5.9 dB\r
+    0 for 11.8 dB\r
+*/\r
+static const UINT8 lfo_ams_depth_shift[4] = {8, 3, 1, 0};\r
+\r
+\r
+\r
+/*There are 8 different LFO PM depths available, they are:\r
+  0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents)\r
+\r
+  Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10\r
+  (bits 8,9,10 = FNUM MSB from OCT/FNUM register)\r
+\r
+  Here we store only first quarter (positive one) of full waveform.\r
+  Full table (lfo_pm_table) containing all 128 waveforms is build\r
+  at run (init) time.\r
+\r
+  One value in table below represents 4 (four) basic LFO steps\r
+  (1 PM step = 4 AM steps).\r
+\r
+  For example:\r
+   at LFO SPEED=0 (which is 108 samples per basic LFO step)\r
+   one value from "lfo_pm_output" table lasts for 432 consecutive\r
+   samples (4*108=432) and one full LFO waveform cycle lasts for 13824\r
+   samples (32*432=13824; 32 because we store only a quarter of whole\r
+            waveform in the table below)\r
+*/\r
+static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */\r
+/* FNUM BIT 4: 000 0001xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 2 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 3 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 4 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 5 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 6 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 7 */ {0,   0,   0,   0,   1,   1,   1,   1},\r
+\r
+/* FNUM BIT 5: 000 0010xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 2 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 3 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 4 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 5 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 6 */ {0,   0,   0,   0,   1,   1,   1,   1},\r
+/* DEPTH 7 */ {0,   0,   1,   1,   2,   2,   2,   3},\r
+\r
+/* FNUM BIT 6: 000 0100xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 2 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 3 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 4 */ {0,   0,   0,   0,   0,   0,   0,   1},\r
+/* DEPTH 5 */ {0,   0,   0,   0,   1,   1,   1,   1},\r
+/* DEPTH 6 */ {0,   0,   1,   1,   2,   2,   2,   3},\r
+/* DEPTH 7 */ {0,   0,   2,   3,   4,   4,   5,   6},\r
+\r
+/* FNUM BIT 7: 000 1000xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 2 */ {0,   0,   0,   0,   0,   0,   1,   1},\r
+/* DEPTH 3 */ {0,   0,   0,   0,   1,   1,   1,   1},\r
+/* DEPTH 4 */ {0,   0,   0,   1,   1,   1,   1,   2},\r
+/* DEPTH 5 */ {0,   0,   1,   1,   2,   2,   2,   3},\r
+/* DEPTH 6 */ {0,   0,   2,   3,   4,   4,   5,   6},\r
+/* DEPTH 7 */ {0,   0,   4,   6,   8,   8, 0xa, 0xc},\r
+\r
+/* FNUM BIT 8: 001 0000xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   1,   1,   1,   1},\r
+/* DEPTH 2 */ {0,   0,   0,   1,   1,   1,   2,   2},\r
+/* DEPTH 3 */ {0,   0,   1,   1,   2,   2,   3,   3},\r
+/* DEPTH 4 */ {0,   0,   1,   2,   2,   2,   3,   4},\r
+/* DEPTH 5 */ {0,   0,   2,   3,   4,   4,   5,   6},\r
+/* DEPTH 6 */ {0,   0,   4,   6,   8,   8, 0xa, 0xc},\r
+/* DEPTH 7 */ {0,   0,   8, 0xc,0x10,0x10,0x14,0x18},\r
+\r
+/* FNUM BIT 9: 010 0000xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   2,   2,   2,   2},\r
+/* DEPTH 2 */ {0,   0,   0,   2,   2,   2,   4,   4},\r
+/* DEPTH 3 */ {0,   0,   2,   2,   4,   4,   6,   6},\r
+/* DEPTH 4 */ {0,   0,   2,   4,   4,   4,   6,   8},\r
+/* DEPTH 5 */ {0,   0,   4,   6,   8,   8, 0xa, 0xc},\r
+/* DEPTH 6 */ {0,   0,   8, 0xc,0x10,0x10,0x14,0x18},\r
+/* DEPTH 7 */ {0,   0,0x10,0x18,0x20,0x20,0x28,0x30},\r
+\r
+/* FNUM BIT10: 100 0000xxxx */\r
+/* DEPTH 0 */ {0,   0,   0,   0,   0,   0,   0,   0},\r
+/* DEPTH 1 */ {0,   0,   0,   0,   4,   4,   4,   4},\r
+/* DEPTH 2 */ {0,   0,   0,   4,   4,   4,   8,   8},\r
+/* DEPTH 3 */ {0,   0,   4,   4,   8,   8, 0xc, 0xc},\r
+/* DEPTH 4 */ {0,   0,   4,   8,   8,   8, 0xc,0x10},\r
+/* DEPTH 5 */ {0,   0,   8, 0xc,0x10,0x10,0x14,0x18},\r
+/* DEPTH 6 */ {0,   0,0x10,0x18,0x20,0x20,0x28,0x30},\r
+/* DEPTH 7 */ {0,   0,0x20,0x30,0x40,0x40,0x50,0x60},\r
+\r
+};\r
+\r
+/* all 128 LFO PM waveforms */\r
+static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */\r
+\r
+/* there are 2048 FNUMs that can be generated using FNUM/BLK registers\r
+       but LFO works with one more bit of a precision so we really need 4096 elements */\r
+static UINT32 fn_table[4096];  /* fnumber->increment counter */\r
+\r
+static int g_lfo_ampm = 0;\r
+\r
+/* register number to channel number , slot offset */\r
+#define OPN_CHAN(N) (N&3)\r
+#define OPN_SLOT(N) ((N>>2)&3)\r
+\r
+/* slot number */\r
+#define SLOT1 0\r
+#define SLOT2 2\r
+#define SLOT3 1\r
+#define SLOT4 3\r
+\r
+\r
+/* OPN Mode Register Write */\r
+INLINE void set_timers( int v )\r
+{\r
+       /* b7 = CSM MODE */\r
+       /* b6 = 3 slot mode */\r
+       /* b5 = reset b */\r
+       /* b4 = reset a */\r
+       /* b3 = timer enable b */\r
+       /* b2 = timer enable a */\r
+       /* b1 = load b */\r
+       /* b0 = load a */\r
+       ym2612.OPN.ST.mode = v;\r
+\r
+       /* reset Timer b flag */\r
+       if( v & 0x20 )\r
+               ym2612.OPN.ST.status &= ~2;\r
+\r
+       /* reset Timer a flag */\r
+       if( v & 0x10 )\r
+               ym2612.OPN.ST.status &= ~1;\r
+}\r
+\r
+\r
+INLINE void FM_KEYON(int c , int s )\r
+{\r
+       FM_SLOT *SLOT = &ym2612.CH[c].SLOT[s];\r
+       if( !SLOT->key )\r
+       {\r
+               SLOT->key = 1;\r
+               SLOT->phase = 0;                /* restart Phase Generator */\r
+               SLOT->state = EG_ATT;   /* phase -> Attack */\r
+               SLOT->volume = MAX_ATT_INDEX;    /* fix Ecco 2 splash sound */\r
+               ym2612.slot_mask |= (1<<s) << (c*4);\r
+       }\r
+}\r
+\r
+INLINE void FM_KEYOFF(int c , int s )\r
+{\r
+       FM_SLOT *SLOT = &ym2612.CH[c].SLOT[s];\r
+       if( SLOT->key )\r
+       {\r
+               SLOT->key = 0;\r
+               if (SLOT->state>EG_REL)\r
+                       SLOT->state = EG_REL;/* phase -> Release */\r
+       }\r
+}\r
+\r
+\r
+/* set detune & multiple */\r
+INLINE void set_det_mul(FM_CH *CH, FM_SLOT *SLOT, int v)\r
+{\r
+       SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1;\r
+       SLOT->DT  = ym2612.OPN.ST.dt_tab[(v>>4)&7];\r
+       CH->SLOT[SLOT1].Incr=-1;\r
+}\r
+\r
+/* set total level */\r
+INLINE void set_tl(FM_SLOT *SLOT, int v)\r
+{\r
+       SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */\r
+}\r
+\r
+/* set attack rate & key scale  */\r
+INLINE void set_ar_ksr(FM_CH *CH, FM_SLOT *SLOT, int v)\r
+{\r
+       UINT8 old_KSR = SLOT->KSR;\r
+\r
+       SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;\r
+\r
+       SLOT->KSR = 3-(v>>6);\r
+       if (SLOT->KSR != old_KSR)\r
+       {\r
+               CH->SLOT[SLOT1].Incr=-1;\r
+       }\r
+       else\r
+       {\r
+               int eg_sh_ar, eg_sel_ar;\r
+\r
+               /* refresh Attack rate */\r
+               if ((SLOT->ar + SLOT->ksr) < 32+62)\r
+               {\r
+                       eg_sh_ar  = eg_rate_shift [SLOT->ar  + SLOT->ksr ];\r
+                       eg_sel_ar = eg_rate_select[SLOT->ar  + SLOT->ksr ];\r
+               }\r
+               else\r
+               {\r
+                       eg_sh_ar  = 0;\r
+                       eg_sel_ar = 17;\r
+               }\r
+\r
+               SLOT->eg_pack_ar = eg_inc_pack[eg_sel_ar] | (eg_sh_ar<<24);\r
+       }\r
+}\r
+\r
+/* set decay rate */\r
+INLINE void set_dr(FM_SLOT *SLOT, int v)\r
+{\r
+       int eg_sh_d1r, eg_sel_d1r;\r
+\r
+       SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;\r
+\r
+       eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr];\r
+       eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr];\r
+\r
+       SLOT->eg_pack_d1r = eg_inc_pack[eg_sel_d1r] | (eg_sh_d1r<<24);\r
+}\r
+\r
+/* set sustain rate */\r
+INLINE void set_sr(FM_SLOT *SLOT, int v)\r
+{\r
+       int eg_sh_d2r, eg_sel_d2r;\r
+\r
+       SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;\r
+\r
+       eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr];\r
+       eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr];\r
+\r
+       SLOT->eg_pack_d2r = eg_inc_pack[eg_sel_d2r] | (eg_sh_d2r<<24);\r
+}\r
+\r
+/* set release rate */\r
+INLINE void set_sl_rr(FM_SLOT *SLOT, int v)\r
+{\r
+       int eg_sh_rr, eg_sel_rr;\r
+\r
+       SLOT->sl = sl_table[ v>>4 ];\r
+\r
+       SLOT->rr  = 34 + ((v&0x0f)<<2);\r
+\r
+       eg_sh_rr  = eg_rate_shift [SLOT->rr  + SLOT->ksr];\r
+       eg_sel_rr = eg_rate_select[SLOT->rr  + SLOT->ksr];\r
+\r
+       SLOT->eg_pack_rr = eg_inc_pack[eg_sel_rr] | (eg_sh_rr<<24);\r
+}\r
+\r
+\r
+\r
+INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm)\r
+{\r
+       int ret, sin = (phase>>16) + (pm>>1);\r
+       int neg = sin & 0x200;\r
+       if (sin & 0x100) sin ^= 0xff;\r
+       sin&=0xff;\r
+       env&=~1;\r
+\r
+       // this was already checked\r
+       // if (env >= ENV_QUIET) // 384\r
+       //      return 0;\r
+\r
+       ret = ym_tl_tab[sin | (env<<7)];\r
+\r
+       return neg ? -ret : ret;\r
+}\r
+\r
+INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm)\r
+{\r
+       int ret, sin = (phase+pm)>>16;\r
+       int neg = sin & 0x200;\r
+       if (sin & 0x100) sin ^= 0xff;\r
+       sin&=0xff;\r
+       env&=~1;\r
+\r
+       // if (env >= ENV_QUIET) // 384\r
+       //      return 0;\r
+\r
+       ret = ym_tl_tab[sin | (env<<7)];\r
+\r
+       return neg ? -ret : ret;\r
+}\r
+\r
+#if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612)\r
+/* advance LFO to next sample */\r
+INLINE int advance_lfo(int lfo_ampm, UINT32 lfo_cnt_old, UINT32 lfo_cnt)\r
+{\r
+       UINT8 pos;\r
+       UINT8 prev_pos;\r
+\r
+       prev_pos = (lfo_cnt_old >> LFO_SH) & 127;\r
+\r
+       pos = (lfo_cnt >> LFO_SH) & 127;\r
+\r
+       /* update AM when LFO output changes */\r
+\r
+       if (prev_pos != pos)\r
+       {\r
+               lfo_ampm &= 0xff;\r
+               /* triangle */\r
+               /* AM: 0 to 126 step +2, 126 to 0 step -2 */\r
+               if (pos<64)\r
+                       lfo_ampm |= ((pos&63) * 2) << 8;           /* 0 - 126 */\r
+               else\r
+                       lfo_ampm |= (126 - (pos&63)*2) << 8;\r
+       }\r
+       else\r
+       {\r
+               return lfo_ampm;\r
+       }\r
+\r
+       /* PM works with 4 times slower clock */\r
+       prev_pos >>= 2;\r
+       pos >>= 2;\r
+       /* update PM when LFO output changes */\r
+       if (prev_pos != pos)\r
+       {\r
+               lfo_ampm &= ~0xff;\r
+               lfo_ampm |= pos; /* 0 - 32 */\r
+       }\r
+       return lfo_ampm;\r
+}\r
+\r
+#define EG_INC_VAL() \\r
+       ((1 << ((pack >> ((eg_cnt>>shift)&7)*3)&7)) >> 1)\r
+\r
+INLINE UINT32 update_eg_phase(FM_SLOT *SLOT, UINT32 eg_cnt)\r
+{\r
+       INT32 volume = SLOT->volume;\r
+\r
+       switch(SLOT->state)\r
+       {\r
+               case EG_ATT:            /* attack phase */\r
+               {\r
+                       UINT32 pack = SLOT->eg_pack_ar;\r
+                       UINT32 shift = pack>>24;\r
+                       if ( !(eg_cnt & ((1<<shift)-1) ) )\r
+                       {\r
+                               volume += ( ~volume * EG_INC_VAL() ) >>4;\r
+\r
+                               if (volume <= MIN_ATT_INDEX)\r
+                               {\r
+                                       volume = MIN_ATT_INDEX;\r
+                                       SLOT->state = EG_DEC;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+\r
+               case EG_DEC:    /* decay phase */\r
+               {\r
+                       UINT32 pack = SLOT->eg_pack_d1r;\r
+                       UINT32 shift = pack>>24;\r
+                       if ( !(eg_cnt & ((1<<shift)-1) ) )\r
+                       {\r
+                               volume += EG_INC_VAL();\r
+\r
+                               if ( volume >= (INT32) SLOT->sl )\r
+                                       SLOT->state = EG_SUS;\r
+                       }\r
+                       break;\r
+               }\r
+\r
+               case EG_SUS:    /* sustain phase */\r
+               {\r
+                       UINT32 pack = SLOT->eg_pack_d2r;\r
+                       UINT32 shift = pack>>24;\r
+                       if ( !(eg_cnt & ((1<<shift)-1) ) )\r
+                       {\r
+                               volume += EG_INC_VAL();\r
+\r
+                               if ( volume >= MAX_ATT_INDEX )\r
+                               {\r
+                                       volume = MAX_ATT_INDEX;\r
+                                       /* do not change SLOT->state (verified on real chip) */\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+\r
+               case EG_REL:    /* release phase */\r
+               {\r
+                       UINT32 pack = SLOT->eg_pack_rr;\r
+                       UINT32 shift = pack>>24;\r
+                       if ( !(eg_cnt & ((1<<shift)-1) ) )\r
+                       {\r
+                               volume += EG_INC_VAL();\r
+\r
+                               if ( volume >= MAX_ATT_INDEX )\r
+                               {\r
+                                       volume = MAX_ATT_INDEX;\r
+                                       SLOT->state = EG_OFF;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+\r
+       SLOT->volume = volume;\r
+       return SLOT->tl + ((UINT32)volume); /* tl is 7bit<<3, volume 0-1023 (0-2039 total) */\r
+}\r
+#endif\r
+\r
+\r
+typedef struct\r
+{\r
+       UINT16 vol_out1; /* 00: current output from EG circuit (without AM from LFO) */\r
+       UINT16 vol_out2;\r
+       UINT16 vol_out3;\r
+       UINT16 vol_out4;\r
+       UINT32 pad[2];\r
+       UINT32 phase1;   /* 10 */\r
+       UINT32 phase2;\r
+       UINT32 phase3;\r
+       UINT32 phase4;\r
+       UINT32 incr1;    /* 20: phase step */\r
+       UINT32 incr2;\r
+       UINT32 incr3;\r
+       UINT32 incr4;\r
+       UINT32 lfo_cnt;  /* 30 */\r
+       UINT32 lfo_inc;\r
+       INT32  mem;      /* one sample delay memory */\r
+       UINT32 eg_cnt;   /* envelope generator counter */\r
+       FM_CH  *CH;      /* 40: envelope generator counter */\r
+       UINT32 eg_timer;\r
+       UINT32 eg_timer_add;\r
+       UINT32 pack;     // 4c: stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]\r
+       UINT32 algo;     /* 50: algo[3], was_update */\r
+       INT32  op1_out;\r
+#ifdef _MIPS_ARCH_ALLEGREX\r
+       UINT32 pad1[3+8];\r
+#endif\r
+} chan_rend_context;\r
+\r
+\r
+#if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612)\r
+static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)\r
+{\r
+       int scounter;                                   /* sample counter */\r
+\r
+       /* sample generating loop */\r
+       for (scounter = 0; scounter < length; scounter++)\r
+       {\r
+               int smp = 0;            /* produced sample */\r
+               unsigned int eg_out, eg_out2, eg_out4;\r
+\r
+               if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */\r
+                       ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16);\r
+                       ct->lfo_cnt += ct->lfo_inc;\r
+               }\r
+\r
+               ct->eg_timer += ct->eg_timer_add;\r
+               while (ct->eg_timer >= EG_TIMER_OVERFLOW)\r
+               {\r
+                       ct->eg_timer -= EG_TIMER_OVERFLOW;\r
+                       ct->eg_cnt++;\r
+\r
+                       if (ct->CH->SLOT[SLOT1].state != EG_OFF) ct->vol_out1 = update_eg_phase(&ct->CH->SLOT[SLOT1], ct->eg_cnt);\r
+                       if (ct->CH->SLOT[SLOT2].state != EG_OFF) ct->vol_out2 = update_eg_phase(&ct->CH->SLOT[SLOT2], ct->eg_cnt);\r
+                       if (ct->CH->SLOT[SLOT3].state != EG_OFF) ct->vol_out3 = update_eg_phase(&ct->CH->SLOT[SLOT3], ct->eg_cnt);\r
+                       if (ct->CH->SLOT[SLOT4].state != EG_OFF) ct->vol_out4 = update_eg_phase(&ct->CH->SLOT[SLOT4], ct->eg_cnt);\r
+               }\r
+\r
+               if (ct->pack & 4) continue; /* output disabled */\r
+\r
+               /* calculate channel sample */\r
+               eg_out = ct->vol_out1;\r
+               if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) ) eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
+\r
+               if( eg_out < ENV_QUIET )        /* SLOT 1 */\r
+               {\r
+                       int out = 0;\r
+\r
+                       if (ct->pack&0xf000) out = ((ct->op1_out>>16) + ((ct->op1_out<<16)>>16)) << ((ct->pack&0xf000)>>12); /* op1_out0 + op1_out1 */\r
+                       ct->op1_out <<= 16;\r
+                       ct->op1_out |= (unsigned short)op_calc1(ct->phase1, eg_out, out);\r
+               } else {\r
+                       ct->op1_out <<= 16; /* op1_out0 = op1_out1; op1_out1 = 0; */\r
+               }\r
+\r
+               eg_out  = ct->vol_out3; // volume_calc(&CH->SLOT[SLOT3]);\r
+               eg_out2 = ct->vol_out2; // volume_calc(&CH->SLOT[SLOT2]);\r
+               eg_out4 = ct->vol_out4; // volume_calc(&CH->SLOT[SLOT4]);\r
+\r
+               if (ct->pack & 8) {\r
+                       unsigned int add = ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
+                       if (ct->pack & (1<<(SLOT3+8))) eg_out  += add;\r
+                       if (ct->pack & (1<<(SLOT2+8))) eg_out2 += add;\r
+                       if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add;\r
+               }\r
+\r
+               switch( ct->CH->ALGO )\r
+               {\r
+                       case 0:\r
+                       {\r
+                               /* M1---C1---MEM---M2---C2---OUT */\r
+                               int m2,c1,c2=0; /* Phase Modulation input for operators 2,3,4 */\r
+                               m2 = ct->mem;\r
+                               c1 = ct->op1_out>>16;\r
+                               if( eg_out  < ENV_QUIET ) {             /* SLOT 3 */\r
+                                       c2  = op_calc(ct->phase3, eg_out,  m2);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       ct->mem = op_calc(ct->phase2, eg_out2, c1);\r
+                               }\r
+                               else ct->mem = 0;\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp = op_calc(ct->phase4, eg_out4, c2);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 1:\r
+                       {\r
+                               /* M1------+-MEM---M2---C2---OUT */\r
+                               /*      C1-+                     */\r
+                               int m2,c2=0;\r
+                               m2 = ct->mem;\r
+                               ct->mem = ct->op1_out>>16;\r
+                               if( eg_out  < ENV_QUIET ) {             /* SLOT 3 */\r
+                                       c2  = op_calc(ct->phase3, eg_out,  m2);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       ct->mem+= op_calc(ct->phase2, eg_out2, 0);\r
+                               }\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp = op_calc(ct->phase4, eg_out4, c2);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 2:\r
+                       {\r
+                               /* M1-----------------+-C2---OUT */\r
+                               /*      C1---MEM---M2-+          */\r
+                               int m2,c2;\r
+                               m2 = ct->mem;\r
+                               c2 = ct->op1_out>>16;\r
+                               if( eg_out  < ENV_QUIET ) {             /* SLOT 3 */\r
+                                       c2 += op_calc(ct->phase3, eg_out,  m2);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       ct->mem = op_calc(ct->phase2, eg_out2, 0);\r
+                               }\r
+                               else ct->mem = 0;\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp = op_calc(ct->phase4, eg_out4, c2);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 3:\r
+                       {\r
+                               /* M1---C1---MEM------+-C2---OUT */\r
+                               /*                 M2-+          */\r
+                               int c1,c2;\r
+                               c2 = ct->mem;\r
+                               c1 = ct->op1_out>>16;\r
+                               if( eg_out  < ENV_QUIET ) {             /* SLOT 3 */\r
+                                       c2 += op_calc(ct->phase3, eg_out,  0);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       ct->mem = op_calc(ct->phase2, eg_out2, c1);\r
+                               }\r
+                               else ct->mem = 0;\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp = op_calc(ct->phase4, eg_out4, c2);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 4:\r
+                       {\r
+                               /* M1---C1-+-OUT */\r
+                               /* M2---C2-+     */\r
+                               /* MEM: not used */\r
+                               int c1,c2=0;\r
+                               c1 = ct->op1_out>>16;\r
+                               if( eg_out  < ENV_QUIET ) {             /* SLOT 3 */\r
+                                       c2  = op_calc(ct->phase3, eg_out,  0);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       smp = op_calc(ct->phase2, eg_out2, c1);\r
+                               }\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp+= op_calc(ct->phase4, eg_out4, c2);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 5:\r
+                       {\r
+                               /*    +----C1----+     */\r
+                               /* M1-+-MEM---M2-+-OUT */\r
+                               /*    +----C2----+     */\r
+                               int m2,c1,c2;\r
+                               m2 = ct->mem;\r
+                               ct->mem = c1 = c2 = ct->op1_out>>16;\r
+                               if( eg_out < ENV_QUIET ) {              /* SLOT 3 */\r
+                                       smp = op_calc(ct->phase3, eg_out, m2);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       smp+= op_calc(ct->phase2, eg_out2, c1);\r
+                               }\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp+= op_calc(ct->phase4, eg_out4, c2);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 6:\r
+                       {\r
+                               /* M1---C1-+     */\r
+                               /*      M2-+-OUT */\r
+                               /*      C2-+     */\r
+                               /* MEM: not used */\r
+                               int c1;\r
+                               c1 = ct->op1_out>>16;\r
+                               if( eg_out < ENV_QUIET ) {              /* SLOT 3 */\r
+                                       smp = op_calc(ct->phase3, eg_out,  0);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       smp+= op_calc(ct->phase2, eg_out2, c1);\r
+                               }\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp+= op_calc(ct->phase4, eg_out4, 0);\r
+                               }\r
+                               break;\r
+                       }\r
+                       case 7:\r
+                       {\r
+                               /* M1-+     */\r
+                               /* C1-+-OUT */\r
+                               /* M2-+     */\r
+                               /* C2-+     */\r
+                               /* MEM: not used*/\r
+                               smp = ct->op1_out>>16;\r
+                               if( eg_out < ENV_QUIET ) {              /* SLOT 3 */\r
+                                       smp += op_calc(ct->phase3, eg_out,  0);\r
+                               }\r
+                               if( eg_out2 < ENV_QUIET ) {             /* SLOT 2 */\r
+                                       smp += op_calc(ct->phase2, eg_out2, 0);\r
+                               }\r
+                               if( eg_out4 < ENV_QUIET ) {             /* SLOT 4 */\r
+                                       smp += op_calc(ct->phase4, eg_out4, 0);\r
+                               }\r
+                               break;\r
+                       }\r
+               }\r
+               /* done calculating channel sample */\r
+\r
+               /* mix sample to output buffer */\r
+               if (smp) {\r
+                       if (ct->pack & 1) { /* stereo */\r
+                               if (ct->pack & 0x20) /* L */ /* TODO: check correctness */\r
+                                       buffer[scounter*2] += smp;\r
+                               if (ct->pack & 0x10) /* R */\r
+                                       buffer[scounter*2+1] += smp;\r
+                       } else {\r
+                               buffer[scounter] += smp;\r
+                       }\r
+                       ct->algo = 8; // algo is only used in asm, here only bit3 is used\r
+               }\r
+\r
+               /* update phase counters AFTER output calculations */\r
+               ct->phase1 += ct->incr1;\r
+               ct->phase2 += ct->incr2;\r
+               ct->phase3 += ct->incr3;\r
+               ct->phase4 += ct->incr4;\r
+       }\r
+}\r
+#else\r
+void chan_render_loop(chan_rend_context *ct, int *buffer, unsigned short length);\r
+#endif\r
+\r
+static chan_rend_context crct;\r
+\r
+static void chan_render_prep(void)\r
+{\r
+       crct.eg_timer_add = ym2612.OPN.eg_timer_add;\r
+       crct.lfo_inc = ym2612.OPN.lfo_inc;\r
+}\r
+\r
+static void chan_render_finish(void)\r
+{\r
+       ym2612.OPN.eg_cnt = crct.eg_cnt;\r
+       ym2612.OPN.eg_timer = crct.eg_timer;\r
+       g_lfo_ampm = crct.pack >> 16; // need_save\r
+       ym2612.OPN.lfo_cnt = crct.lfo_cnt;\r
+}\r
+\r
+static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: stereo, ?, disabled, ?, pan_r, pan_l\r
+{\r
+       crct.CH = &ym2612.CH[c];\r
+       crct.mem = crct.CH->mem_value;          /* one sample delay memory */\r
+       crct.lfo_cnt = ym2612.OPN.lfo_cnt;\r
+\r
+       flags &= 0x35;\r
+\r
+       if (crct.lfo_inc) {\r
+               flags |= 8;\r
+               flags |= g_lfo_ampm << 16;\r
+               flags |= crct.CH->AMmasks << 8;\r
+               if (crct.CH->ams == 8) // no ams\r
+                    flags &= ~0xf00;\r
+               else flags |= (crct.CH->ams&3)<<6;\r
+       }\r
+       flags |= (crct.CH->FB&0xf)<<12;                         /* feedback shift */\r
+       crct.pack = flags;\r
+\r
+       crct.eg_cnt = ym2612.OPN.eg_cnt;                        /* envelope generator counter */\r
+       crct.eg_timer = ym2612.OPN.eg_timer;\r
+\r
+       /* precalculate phase modulation incr */\r
+       crct.phase1 = crct.CH->SLOT[SLOT1].phase;\r
+       crct.phase2 = crct.CH->SLOT[SLOT2].phase;\r
+       crct.phase3 = crct.CH->SLOT[SLOT3].phase;\r
+       crct.phase4 = crct.CH->SLOT[SLOT4].phase;\r
+\r
+       /* current output from EG circuit (without AM from LFO) */\r
+       crct.vol_out1 = crct.CH->SLOT[SLOT1].tl + ((UINT32)crct.CH->SLOT[SLOT1].volume);\r
+       crct.vol_out2 = crct.CH->SLOT[SLOT2].tl + ((UINT32)crct.CH->SLOT[SLOT2].volume);\r
+       crct.vol_out3 = crct.CH->SLOT[SLOT3].tl + ((UINT32)crct.CH->SLOT[SLOT3].volume);\r
+       crct.vol_out4 = crct.CH->SLOT[SLOT4].tl + ((UINT32)crct.CH->SLOT[SLOT4].volume);\r
+\r
+       crct.op1_out = crct.CH->op1_out;\r
+       crct.algo = crct.CH->ALGO & 7;\r
+\r
+       if(crct.CH->pms)\r
+       {\r
+               /* add support for 3 slot mode */\r
+               UINT32 block_fnum = crct.CH->block_fnum;\r
+\r
+               UINT32 fnum_lfo   = ((block_fnum & 0x7f0) >> 4) * 32 * 8;\r
+               INT32  lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + crct.CH->pms + ((crct.pack>>16)&0xff) ];\r
+\r
+               if (lfo_fn_table_index_offset)  /* LFO phase modulation active */\r
+               {\r
+                       UINT8  blk;\r
+                       UINT32 fn;\r
+                       int kc,fc;\r
+\r
+                       blk = block_fnum >> 11;\r
+                       block_fnum = block_fnum*2 + lfo_fn_table_index_offset;\r
+\r
+                       fn  = block_fnum & 0xfff;\r
+\r
+                       /* keyscale code */\r
+                       kc = (blk<<2) | opn_fktable[fn >> 8];\r
+                       /* phase increment counter */\r
+                       fc = fn_table[fn]>>(7-blk);\r
+\r
+                       crct.incr1 = ((fc+crct.CH->SLOT[SLOT1].DT[kc])*crct.CH->SLOT[SLOT1].mul) >> 1;\r
+                       crct.incr2 = ((fc+crct.CH->SLOT[SLOT2].DT[kc])*crct.CH->SLOT[SLOT2].mul) >> 1;\r
+                       crct.incr3 = ((fc+crct.CH->SLOT[SLOT3].DT[kc])*crct.CH->SLOT[SLOT3].mul) >> 1;\r
+                       crct.incr4 = ((fc+crct.CH->SLOT[SLOT4].DT[kc])*crct.CH->SLOT[SLOT4].mul) >> 1;\r
+               }\r
+               else    /* LFO phase modulation  = zero */\r
+               {\r
+                       crct.incr1 = crct.CH->SLOT[SLOT1].Incr;\r
+                       crct.incr2 = crct.CH->SLOT[SLOT2].Incr;\r
+                       crct.incr3 = crct.CH->SLOT[SLOT3].Incr;\r
+                       crct.incr4 = crct.CH->SLOT[SLOT4].Incr;\r
+               }\r
+       }\r
+       else    /* no LFO phase modulation */\r
+       {\r
+               crct.incr1 = crct.CH->SLOT[SLOT1].Incr;\r
+               crct.incr2 = crct.CH->SLOT[SLOT2].Incr;\r
+               crct.incr3 = crct.CH->SLOT[SLOT3].Incr;\r
+               crct.incr4 = crct.CH->SLOT[SLOT4].Incr;\r
+       }\r
+\r
+       chan_render_loop(&crct, buffer, length);\r
+\r
+       crct.CH->op1_out = crct.op1_out;\r
+       crct.CH->mem_value = crct.mem;\r
+       if (crct.CH->SLOT[SLOT1].state | crct.CH->SLOT[SLOT2].state | crct.CH->SLOT[SLOT3].state | crct.CH->SLOT[SLOT4].state)\r
+       {\r
+               crct.CH->SLOT[SLOT1].phase = crct.phase1;\r
+               crct.CH->SLOT[SLOT2].phase = crct.phase2;\r
+               crct.CH->SLOT[SLOT3].phase = crct.phase3;\r
+               crct.CH->SLOT[SLOT4].phase = crct.phase4;\r
+       }\r
+       else\r
+               ym2612.slot_mask &= ~(0xf << (c*4));\r
+\r
+       return (crct.algo & 8) >> 3; // had output\r
+}\r
+\r
+/* update phase increment and envelope generator */\r
+INLINE void refresh_fc_eg_slot(FM_SLOT *SLOT, int fc, int kc)\r
+{\r
+       int ksr, fdt;\r
+\r
+       /* (frequency) phase increment counter */\r
+       fdt = fc+SLOT->DT[kc];\r
+       /* detect overflow */\r
+//     if (fdt < 0) fdt += fn_table[0x7ff*2] >> (7-blk-1);\r
+       if (fdt < 0) fdt += fn_table[0x7ff*2] >> 2;\r
+       SLOT->Incr = fdt*SLOT->mul >> 1;\r
+\r
+       ksr = kc >> SLOT->KSR;\r
+       if( SLOT->ksr != ksr )\r
+       {\r
+               int eg_sh, eg_sel;\r
+               SLOT->ksr = ksr;\r
+\r
+               /* calculate envelope generator rates */\r
+               if ((SLOT->ar + ksr) < 32+62)\r
+               {\r
+                       eg_sh  = eg_rate_shift [SLOT->ar  + ksr ];\r
+                       eg_sel = eg_rate_select[SLOT->ar  + ksr ];\r
+               }\r
+               else\r
+               {\r
+                       eg_sh  = 0;\r
+                       eg_sel = 17;\r
+               }\r
+\r
+               SLOT->eg_pack_ar = eg_inc_pack[eg_sel] | (eg_sh<<24);\r
+\r
+               eg_sh  = eg_rate_shift [SLOT->d1r + ksr];\r
+               eg_sel = eg_rate_select[SLOT->d1r + ksr];\r
+\r
+               SLOT->eg_pack_d1r = eg_inc_pack[eg_sel] | (eg_sh<<24);\r
+\r
+               eg_sh  = eg_rate_shift [SLOT->d2r + ksr];\r
+               eg_sel = eg_rate_select[SLOT->d2r + ksr];\r
+\r
+               SLOT->eg_pack_d2r = eg_inc_pack[eg_sel] | (eg_sh<<24);\r
+\r
+               eg_sh  = eg_rate_shift [SLOT->rr  + ksr];\r
+               eg_sel = eg_rate_select[SLOT->rr  + ksr];\r
+\r
+               SLOT->eg_pack_rr = eg_inc_pack[eg_sel] | (eg_sh<<24);\r
+       }\r
+}\r
+\r
+/* update phase increment counters */\r
+INLINE void refresh_fc_eg_chan(FM_CH *CH)\r
+{\r
+       if( CH->SLOT[SLOT1].Incr==-1){\r
+               int fc = CH->fc;\r
+               int kc = CH->kcode;\r
+               refresh_fc_eg_slot(&CH->SLOT[SLOT1] , fc , kc );\r
+               refresh_fc_eg_slot(&CH->SLOT[SLOT2] , fc , kc );\r
+               refresh_fc_eg_slot(&CH->SLOT[SLOT3] , fc , kc );\r
+               refresh_fc_eg_slot(&CH->SLOT[SLOT4] , fc , kc );\r
+       }\r
+}\r
+\r
+INLINE void refresh_fc_eg_chan_sl3(void)\r
+{\r
+       if( ym2612.CH[2].SLOT[SLOT1].Incr==-1)\r
+       {\r
+               refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT1], ym2612.OPN.SL3.fc[1], ym2612.OPN.SL3.kcode[1] );\r
+               refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT2], ym2612.OPN.SL3.fc[2], ym2612.OPN.SL3.kcode[2] );\r
+               refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT3], ym2612.OPN.SL3.fc[0], ym2612.OPN.SL3.kcode[0] );\r
+               refresh_fc_eg_slot(&ym2612.CH[2].SLOT[SLOT4], ym2612.CH[2].fc , ym2612.CH[2].kcode );\r
+       }\r
+}\r
+\r
+/* initialize time tables */\r
+static void init_timetables(const UINT8 *dttable)\r
+{\r
+       int i,d;\r
+       double rate;\r
+\r
+       /* DeTune table */\r
+       for (d = 0;d <= 3;d++){\r
+               for (i = 0;i <= 31;i++){\r
+                       rate = ((double)dttable[d*32 + i]) * SIN_LEN  * ym2612.OPN.ST.freqbase  * (1<<FREQ_SH) / ((double)(1<<20));\r
+                       ym2612.OPN.ST.dt_tab[d][i]   = (INT32) rate;\r
+                       ym2612.OPN.ST.dt_tab[d+4][i] = -ym2612.OPN.ST.dt_tab[d][i];\r
+               }\r
+       }\r
+}\r
+\r
+\r
+static void reset_channels(FM_CH *CH)\r
+{\r
+       int c,s;\r
+\r
+       ym2612.OPN.ST.mode   = 0;       /* normal mode */\r
+       ym2612.OPN.ST.TA     = 0;\r
+       ym2612.OPN.ST.TAC    = 0;\r
+       ym2612.OPN.ST.TB     = 0;\r
+       ym2612.OPN.ST.TBC    = 0;\r
+\r
+       for( c = 0 ; c < 6 ; c++ )\r
+       {\r
+               CH[c].fc = 0;\r
+               for(s = 0 ; s < 4 ; s++ )\r
+               {\r
+                       CH[c].SLOT[s].state= EG_OFF;\r
+                       CH[c].SLOT[s].volume = MAX_ATT_INDEX;\r
+               }\r
+               CH[c].mem_value = CH[c].op1_out = 0;\r
+       }\r
+       ym2612.slot_mask = 0;\r
+}\r
+\r
+/* initialize generic tables */\r
+static void init_tables(void)\r
+{\r
+       signed int i,x,y,p;\r
+       signed int n;\r
+       double o,m;\r
+\r
+       for (i=0; i < 256; i++)\r
+       {\r
+               /* non-standard sinus */\r
+               m = sin( ((i*2)+1) * M_PI / SIN_LEN ); /* checked against the real chip */\r
+\r
+               /* we never reach zero here due to ((i*2)+1) */\r
+\r
+               if (m>0.0)\r
+                       o = 8*log(1.0/m)/log(2);        /* convert to 'decibels' */\r
+               else\r
+                       o = 8*log(-1.0/m)/log(2);       /* convert to 'decibels' */\r
+\r
+               o = o / (ENV_STEP/4);\r
+\r
+               n = (int)(2.0*o);\r
+               if (n&1)                                                /* round to nearest */\r
+                       n = (n>>1)+1;\r
+               else\r
+                       n = n>>1;\r
+\r
+               ym_sin_tab[ i ] = n;\r
+               //dprintf("FM.C: sin [%4i]= %4i", i, ym_sin_tab[i]);\r
+       }\r
+\r
+       //dprintf("FM.C: ENV_QUIET= %08x", ENV_QUIET );\r
+\r
+\r
+       for (x=0; x < TL_RES_LEN; x++)\r
+       {\r
+               m = (1<<16) / pow(2, (x+1) * (ENV_STEP/4.0) / 8.0);\r
+               m = floor(m);\r
+\r
+               /* we never reach (1<<16) here due to the (x+1) */\r
+               /* result fits within 16 bits at maximum */\r
+\r
+               n = (int)m;             /* 16 bits here */\r
+               n >>= 4;                /* 12 bits here */\r
+               if (n&1)                /* round to nearest */\r
+                       n = (n>>1)+1;\r
+               else\r
+                       n = n>>1;\r
+                                               /* 11 bits here (rounded) */\r
+               n <<= 2;                /* 13 bits here (as in real chip) */\r
+               ym_tl_tab2[ x ] = n;\r
+\r
+               for (i=1; i < 13; i++)\r
+               {\r
+                       ym_tl_tab2[ x + i*TL_RES_LEN ] = n >> i;\r
+               }\r
+       }\r
+\r
+       for (x=0; x < 256; x++)\r
+       {\r
+               int sin = ym_sin_tab[ x ];\r
+\r
+               for (y=0; y < 2*13*TL_RES_LEN/8; y+=2)\r
+               {\r
+                       p = (y<<2) + sin;\r
+                       if (p >= 13*TL_RES_LEN)\r
+                                ym_tl_tab[(y<<7) | x] = 0;\r
+                       else ym_tl_tab[(y<<7) | x] = ym_tl_tab2[p];\r
+               }\r
+       }\r
+\r
+\r
+       /* build LFO PM modulation table */\r
+       for(i = 0; i < 8; i++) /* 8 PM depths */\r
+       {\r
+               UINT8 fnum;\r
+               for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */\r
+               {\r
+                       UINT8 value;\r
+                       UINT8 step;\r
+                       UINT32 offset_depth = i;\r
+                       UINT32 offset_fnum_bit;\r
+                       UINT32 bit_tmp;\r
+\r
+                       for (step=0; step<8; step++)\r
+                       {\r
+                               value = 0;\r
+                               for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */\r
+                               {\r
+                                       if (fnum & (1<<bit_tmp)) /* only if bit "bit_tmp" is set */\r
+                                       {\r
+                                               offset_fnum_bit = bit_tmp * 8;\r
+                                               value += lfo_pm_output[offset_fnum_bit + offset_depth][step];\r
+                                       }\r
+                               }\r
+                               lfo_pm_table[(fnum*32*8) + (i*32) + step   + 0] = value;\r
+                               lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+ 8] = value;\r
+                               lfo_pm_table[(fnum*32*8) + (i*32) + step   +16] = -value;\r
+                               lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+24] = -value;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/* CSM Key Controll */\r
+#if 0\r
+INLINE void CSMKeyControll(FM_CH *CH)\r
+{\r
+       /* this is wrong, atm */\r
+\r
+       /* all key on */\r
+       FM_KEYON(CH,SLOT1);\r
+       FM_KEYON(CH,SLOT2);\r
+       FM_KEYON(CH,SLOT3);\r
+       FM_KEYON(CH,SLOT4);\r
+}\r
+#endif\r
+\r
+\r
+/* prescaler set (and make time tables) */\r
+static void OPNSetPres(int pres)\r
+{\r
+       int i;\r
+\r
+       /* frequency base */\r
+       ym2612.OPN.ST.freqbase = (ym2612.OPN.ST.rate) ? ((double)ym2612.OPN.ST.clock / ym2612.OPN.ST.rate) / pres : 0;\r
+\r
+       ym2612.OPN.eg_timer_add  = (1<<EG_SH) * ym2612.OPN.ST.freqbase;\r
+\r
+       /* make time tables */\r
+       init_timetables( dt_tab );\r
+\r
+       /* there are 2048 FNUMs that can be generated using FNUM/BLK registers\r
+        but LFO works with one more bit of a precision so we really need 4096 elements */\r
+       /* calculate fnumber -> increment counter table */\r
+       for(i = 0; i < 4096; i++)\r
+       {\r
+               /* freq table for octave 7 */\r
+               /* OPN phase increment counter = 20bit */\r
+               fn_table[i] = (UINT32)( (double)i * 32 * ym2612.OPN.ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */\r
+       }\r
+\r
+       /* LFO freq. table */\r
+       for(i = 0; i < 8; i++)\r
+       {\r
+               /* Amplitude modulation: 64 output levels (triangle waveform); 1 level lasts for one of "lfo_samples_per_step" samples */\r
+               /* Phase modulation: one entry from lfo_pm_output lasts for one of 4 * "lfo_samples_per_step" samples  */\r
+               ym2612.OPN.lfo_freq[i] = (1.0 / lfo_samples_per_step[i]) * (1<<LFO_SH) * ym2612.OPN.ST.freqbase;\r
+       }\r
+}\r
+\r
+\r
+/* write a OPN register (0x30-0xff) */\r
+static int OPNWriteReg(int r, int v)\r
+{\r
+       int ret = 1;\r
+       FM_CH *CH;\r
+       FM_SLOT *SLOT;\r
+\r
+       UINT8 c = OPN_CHAN(r);\r
+\r
+       if (c == 3) return 0; /* 0xX3,0xX7,0xXB,0xXF */\r
+\r
+       if (r >= 0x100) c+=3;\r
+\r
+       CH = &ym2612.CH[c];\r
+\r
+       SLOT = &(CH->SLOT[OPN_SLOT(r)]);\r
+\r
+       switch( r & 0xf0 ) {\r
+       case 0x30:      /* DET , MUL */\r
+               set_det_mul(CH,SLOT,v);\r
+               break;\r
+\r
+       case 0x40:      /* TL */\r
+               set_tl(SLOT,v);\r
+               break;\r
+\r
+       case 0x50:      /* KS, AR */\r
+               set_ar_ksr(CH,SLOT,v);\r
+               break;\r
+\r
+       case 0x60:      /* bit7 = AM ENABLE, DR | depends on ksr */\r
+               set_dr(SLOT,v);\r
+               if(v&0x80) CH->AMmasks |=   1<<OPN_SLOT(r);\r
+               else       CH->AMmasks &= ~(1<<OPN_SLOT(r));\r
+               break;\r
+\r
+       case 0x70:      /*     SR | depends on ksr */\r
+               set_sr(SLOT,v);\r
+               break;\r
+\r
+       case 0x80:      /* SL, RR | depends on ksr */\r
+               set_sl_rr(SLOT,v);\r
+               break;\r
+\r
+       case 0x90:      /* SSG-EG */\r
+               // removed.\r
+               ret = 0;\r
+               break;\r
+\r
+       case 0xa0:\r
+               switch( OPN_SLOT(r) ){\r
+               case 0:         /* 0xa0-0xa2 : FNUM1 | depends on fn_h (below) */\r
+                       {\r
+                               UINT32 fn = (((UINT32)( (CH->fn_h)&7))<<8) + v;\r
+                               UINT8 blk = CH->fn_h>>3;\r
+                               /* keyscale code */\r
+                               CH->kcode = (blk<<2) | opn_fktable[fn >> 7];\r
+                               /* phase increment counter */\r
+                               CH->fc = fn_table[fn*2]>>(7-blk);\r
+\r
+                               /* store fnum in clear form for LFO PM calculations */\r
+                               CH->block_fnum = (blk<<11) | fn;\r
+\r
+                               CH->SLOT[SLOT1].Incr=-1;\r
+                       }\r
+                       break;\r
+               case 1:         /* 0xa4-0xa6 : FNUM2,BLK */\r
+                       CH->fn_h = v&0x3f;\r
+                       ret = 0;\r
+                       break;\r
+               case 2:         /* 0xa8-0xaa : 3CH FNUM1 */\r
+                       if(r < 0x100)\r
+                       {\r
+                               UINT32 fn = (((UINT32)(ym2612.OPN.SL3.fn_h&7))<<8) + v;\r
+                               UINT8 blk = ym2612.OPN.SL3.fn_h>>3;\r
+                               /* keyscale code */\r
+                               ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];\r
+                               /* phase increment counter */\r
+                               ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk);\r
+                               ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn;\r
+                               ym2612.CH[2].SLOT[SLOT1].Incr=-1;\r
+                       }\r
+                       break;\r
+               case 3:         /* 0xac-0xae : 3CH FNUM2,BLK */\r
+                       if(r < 0x100)\r
+                               ym2612.OPN.SL3.fn_h = v&0x3f;\r
+                       ret = 0;\r
+                       break;\r
+               default:\r
+                       ret = 0;\r
+                       break;\r
+               }\r
+               break;\r
+\r
+       case 0xb0:\r
+               switch( OPN_SLOT(r) ){\r
+               case 0:         /* 0xb0-0xb2 : FB,ALGO */\r
+                       {\r
+                               int feedback = (v>>3)&7;\r
+                               CH->ALGO = v&7;\r
+                               CH->FB   = feedback ? feedback+6 : 0;\r
+                       }\r
+                       break;\r
+               case 1:         /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */\r
+                       {\r
+                               int panshift = c<<1;\r
+\r
+                               /* b0-2 PMS */\r
+                               CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */\r
+\r
+                               /* b4-5 AMS */\r
+                               CH->ams = lfo_ams_depth_shift[(v>>4) & 3];\r
+\r
+                               /* PAN :  b7 = L, b6 = R */\r
+                               ym2612.OPN.pan &= ~(3<<panshift);\r
+                               ym2612.OPN.pan |= ((v & 0xc0) >> 6) << panshift; // ..LRLR\r
+                       }\r
+                       break;\r
+               default:\r
+                       ret = 0;\r
+                       break;\r
+               }\r
+               break;\r
+       default:\r
+               ret = 0;\r
+               break;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+\r
+/*******************************************************************************/\r
+/*      YM2612 local section                                                   */\r
+/*******************************************************************************/\r
+\r
+/* Generate samples for YM2612 */\r
+int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)\r
+{\r
+       int pan;\r
+       int active_chs = 0;\r
+\r
+       // if !is_buf_empty, it means it has valid samples to mix with, else it may contain trash\r
+       if (is_buf_empty) memset32(buffer, 0, length<<stereo);\r
+\r
+/*\r
+       {\r
+               int c, s;\r
+               ppp();\r
+               for (c = 0; c < 6; c++) {\r
+                       int slr = 0, slm;\r
+                       printf("%i: ", c);\r
+                       for (s = 0; s < 4; s++) {\r
+                               if (ym2612.CH[c].SLOT[s].state != EG_OFF) slr = 1;\r
+                               printf(" %i", ym2612.CH[c].SLOT[s].state != EG_OFF);\r
+                       }\r
+                       slm = (ym2612.slot_mask&(0xf<<(c*4))) ? 1 : 0;\r
+                       printf(" | %i", slm);\r
+                       printf(" | %i\n", ym2612.CH[c].SLOT[SLOT1].Incr==-1);\r
+                       if (slr != slm) exit(1);\r
+               }\r
+       }\r
+*/\r
+       /* refresh PG and EG */\r
+       refresh_fc_eg_chan( &ym2612.CH[0] );\r
+       refresh_fc_eg_chan( &ym2612.CH[1] );\r
+       if( (ym2612.OPN.ST.mode & 0xc0) )\r
+               /* 3SLOT MODE */\r
+               refresh_fc_eg_chan_sl3();\r
+       else\r
+               refresh_fc_eg_chan( &ym2612.CH[2] );\r
+       refresh_fc_eg_chan( &ym2612.CH[3] );\r
+       refresh_fc_eg_chan( &ym2612.CH[4] );\r
+       refresh_fc_eg_chan( &ym2612.CH[5] );\r
+\r
+       pan = ym2612.OPN.pan;\r
+       if (stereo) stereo = 1;\r
+\r
+       /* mix to 32bit dest */\r
+       // flags: stereo, ?, disabled, ?, pan_r, pan_l\r
+       chan_render_prep();\r
+       if (ym2612.slot_mask & 0x00000f) active_chs |= chan_render(buffer, length, 0, stereo|((pan&0x003)<<4)) << 0;\r
+       if (ym2612.slot_mask & 0x0000f0) active_chs |= chan_render(buffer, length, 1, stereo|((pan&0x00c)<<2)) << 1;\r
+       if (ym2612.slot_mask & 0x000f00) active_chs |= chan_render(buffer, length, 2, stereo|((pan&0x030)   )) << 2;\r
+       if (ym2612.slot_mask & 0x00f000) active_chs |= chan_render(buffer, length, 3, stereo|((pan&0x0c0)>>2)) << 3;\r
+       if (ym2612.slot_mask & 0x0f0000) active_chs |= chan_render(buffer, length, 4, stereo|((pan&0x300)>>4)) << 4;\r
+       if (ym2612.slot_mask & 0xf00000) active_chs |= chan_render(buffer, length, 5, stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)) << 5;\r
+       chan_render_finish();\r
+\r
+       return active_chs; // 1 if buffer updated\r
+}\r
+\r
+\r
+/* initialize YM2612 emulator */\r
+void YM2612Init_(int clock, int rate)\r
+{\r
+       memset(&ym2612, 0, sizeof(ym2612));\r
+       init_tables();\r
+\r
+       ym2612.OPN.ST.clock = clock;\r
+       ym2612.OPN.ST.rate = rate;\r
+\r
+       OPNSetPres( 6*24 );\r
+\r
+       /* Extend handler */\r
+       YM2612ResetChip_();\r
+}\r
+\r
+\r
+/* reset */\r
+void YM2612ResetChip_(void)\r
+{\r
+       int i;\r
+\r
+       memset(ym2612.REGS, 0, sizeof(ym2612.REGS));\r
+\r
+       set_timers( 0x30 ); /* mode 0 , timer reset */\r
+       ym2612.REGS[0x27] = 0x30;\r
+\r
+       ym2612.OPN.eg_timer = 0;\r
+       ym2612.OPN.eg_cnt   = 0;\r
+       ym2612.OPN.ST.status = 0;\r
+\r
+       reset_channels( &ym2612.CH[0] );\r
+       for(i = 0xb6 ; i >= 0xb4 ; i-- )\r
+       {\r
+               OPNWriteReg(i      ,0xc0);\r
+               OPNWriteReg(i|0x100,0xc0);\r
+               ym2612.REGS[i      ] = 0xc0;\r
+               ym2612.REGS[i|0x100] = 0xc0;\r
+       }\r
+       for(i = 0xb2 ; i >= 0x30 ; i-- )\r
+       {\r
+               OPNWriteReg(i      ,0);\r
+               OPNWriteReg(i|0x100,0);\r
+       }\r
+       for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(i,0);\r
+       /* DAC mode clear */\r
+       ym2612.dacen = 0;\r
+       ym2612.addr_A1 = 0;\r
+}\r
+\r
+\r
+/* YM2612 write */\r
+/* a = address */\r
+/* v = value   */\r
+/* returns 1 if sample affecting state changed */\r
+int YM2612Write_(unsigned int a, unsigned int v)\r
+{\r
+       int addr, ret=1;\r
+\r
+       v &= 0xff;      /* adjust to 8 bit bus */\r
+\r
+       switch( a&3){\r
+       case 0: /* address port 0 */\r
+               ym2612.OPN.ST.address = v;\r
+               ym2612.addr_A1 = 0;\r
+               ret=0;\r
+               break;\r
+\r
+       case 1: /* data port 0    */\r
+               if (ym2612.addr_A1 != 0) {\r
+                       ret=0;\r
+                       break;  /* verified on real YM2608 */\r
+               }\r
+\r
+               addr = ym2612.OPN.ST.address;\r
+\r
+               switch( addr & 0xf0 )\r
+               {\r
+               case 0x20:      /* 0x20-0x2f Mode */\r
+                       switch( addr )\r
+                       {\r
+                       case 0x22:      /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */\r
+                               if (v&0x08) /* LFO enabled ? */\r
+                               {\r
+                                       ym2612.OPN.lfo_inc = ym2612.OPN.lfo_freq[v&7];\r
+                               }\r
+                               else\r
+                               {\r
+                                       ym2612.OPN.lfo_inc = 0;\r
+                               }\r
+                               break;\r
+#if 0 // handled elsewhere\r
+                       case 0x24: { // timer A High 8\r
+                                       int TAnew = (ym2612.OPN.ST.TA & 0x03)|(((int)v)<<2);\r
+                                       if(ym2612.OPN.ST.TA != TAnew) {\r
+                                               // we should reset ticker only if new value is written. Outrun requires this.\r
+                                               ym2612.OPN.ST.TA = TAnew;\r
+                                               ym2612.OPN.ST.TAC = (1024-TAnew)*18;\r
+                                               ym2612.OPN.ST.TAT = 0;\r
+                                       }\r
+                               }\r
+                               ret=0;\r
+                               break;\r
+                       case 0x25: { // timer A Low 2\r
+                                       int TAnew = (ym2612.OPN.ST.TA & 0x3fc)|(v&3);\r
+                                       if(ym2612.OPN.ST.TA != TAnew) {\r
+                                               ym2612.OPN.ST.TA = TAnew;\r
+                                               ym2612.OPN.ST.TAC = (1024-TAnew)*18;\r
+                                               ym2612.OPN.ST.TAT = 0;\r
+                                       }\r
+                               }\r
+                               ret=0;\r
+                               break;\r
+                       case 0x26: // timer B\r
+                               if(ym2612.OPN.ST.TB != v) {\r
+                                       ym2612.OPN.ST.TB = v;\r
+                                       ym2612.OPN.ST.TBC  = (256-v)<<4;\r
+                                       ym2612.OPN.ST.TBC *= 18;\r
+                                       ym2612.OPN.ST.TBT  = 0;\r
+                               }\r
+                               ret=0;\r
+                               break;\r
+#endif\r
+                       case 0x27:      /* mode, timer control */\r
+                               set_timers( v );\r
+                               ret=0;\r
+                               break;\r
+                       case 0x28:      /* key on / off */\r
+                               {\r
+                                       UINT8 c;\r
+\r
+                                       c = v & 0x03;\r
+                                       if( c == 3 ) { ret=0; break; }\r
+                                       if( v&0x04 ) c+=3;\r
+                                       if(v&0x10) FM_KEYON(c,SLOT1); else FM_KEYOFF(c,SLOT1);\r
+                                       if(v&0x20) FM_KEYON(c,SLOT2); else FM_KEYOFF(c,SLOT2);\r
+                                       if(v&0x40) FM_KEYON(c,SLOT3); else FM_KEYOFF(c,SLOT3);\r
+                                       if(v&0x80) FM_KEYON(c,SLOT4); else FM_KEYOFF(c,SLOT4);\r
+                                       break;\r
+                               }\r
+                       case 0x2a:      /* DAC data (YM2612) */\r
+                               ym2612.dacout = ((int)v - 0x80) << 6;   /* level unknown (notaz: 8 seems to be too much) */\r
+                               ret=0;\r
+                               break;\r
+                       case 0x2b:      /* DAC Sel  (YM2612) */\r
+                               /* b7 = dac enable */\r
+                               ym2612.dacen = v & 0x80;\r
+                               ret=0;\r
+                               break;\r
+                       default:\r
+                               break;\r
+                       }\r
+                       break;\r
+               default:        /* 0x30-0xff OPN section */\r
+                       /* write register */\r
+                       ret = OPNWriteReg(addr,v);\r
+               }\r
+               break;\r
+\r
+       case 2: /* address port 1 */\r
+               ym2612.OPN.ST.address = v;\r
+               ym2612.addr_A1 = 1;\r
+               ret=0;\r
+               break;\r
+\r
+       case 3: /* data port 1    */\r
+               if (ym2612.addr_A1 != 1) {\r
+                       ret=0;\r
+                       break;  /* verified on real YM2608 */\r
+               }\r
+\r
+               addr = ym2612.OPN.ST.address | 0x100;\r
+\r
+               ret = OPNWriteReg(addr, v);\r
+               break;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+#if 0\r
+UINT8 YM2612Read_(void)\r
+{\r
+       return ym2612.OPN.ST.status;\r
+}\r
+\r
+int YM2612PicoTick_(int n)\r
+{\r
+       int ret = 0;\r
+\r
+       // timer A\r
+       if(ym2612.OPN.ST.mode & 0x01 && (ym2612.OPN.ST.TAT+=64*n) >= ym2612.OPN.ST.TAC) {\r
+               ym2612.OPN.ST.TAT -= ym2612.OPN.ST.TAC;\r
+               if(ym2612.OPN.ST.mode & 0x04) ym2612.OPN.ST.status |= 1;\r
+               // CSM mode total level latch and auto key on\r
+               if(ym2612.OPN.ST.mode & 0x80) {\r
+                       CSMKeyControll( &(ym2612.CH[2]) ); // Vectorman2, etc.\r
+                       ret = 1;\r
+               }\r
+       }\r
+\r
+       // timer B\r
+       if(ym2612.OPN.ST.mode & 0x02 && (ym2612.OPN.ST.TBT+=64*n) >= ym2612.OPN.ST.TBC) {\r
+               ym2612.OPN.ST.TBT -= ym2612.OPN.ST.TBC;\r
+               if(ym2612.OPN.ST.mode & 0x08) ym2612.OPN.ST.status |= 2;\r
+       }\r
+\r
+       return ret;\r
+}\r
+#endif\r
+\r
+void YM2612PicoStateLoad_(void)\r
+{\r
+       reset_channels( &ym2612.CH[0] );\r
+       ym2612.slot_mask = 0xffffff;\r
+}\r
+\r
+/* rather stupid design because I wanted to fit in unused register "space" */\r
+typedef struct\r
+{\r
+       UINT32  state_phase;\r
+       INT16   volume;\r
+} ym_save_addon_slot;\r
+\r
+typedef struct\r
+{\r
+       UINT32  magic;\r
+       UINT8   address;\r
+       UINT8   status;\r
+       UINT8   addr_A1;\r
+       UINT8   unused;\r
+       int     TAT;\r
+       int     TBT;\r
+       UINT32  eg_cnt;         // 10\r
+       UINT32  eg_timer;\r
+       UINT32  lfo_cnt;\r
+       UINT16  lfo_ampm;\r
+       UINT16  unused2;\r
+       UINT32  keyon_field;    // 20\r
+       UINT32  kcode_fc_sl3_3;\r
+       UINT32  reserved[2];\r
+} ym_save_addon;\r
+\r
+typedef struct\r
+{\r
+       UINT16  block_fnum[6];\r
+       UINT16  block_fnum_sl3[3];\r
+       UINT16  reserved[7];\r
+} ym_save_addon2;\r
+\r
+\r
+void YM2612PicoStateSave2(int tat, int tbt)\r
+{\r
+       ym_save_addon_slot ss;\r
+       ym_save_addon2 sa2;\r
+       ym_save_addon sa;\r
+       unsigned char *ptr;\r
+       int c, s;\r
+\r
+       memset(&sa, 0, sizeof(sa));\r
+       memset(&sa2, 0, sizeof(sa2));\r
+\r
+       // chans 1,2,3\r
+       ptr = &ym2612.REGS[0x0b8];\r
+       for (c = 0; c < 3; c++)\r
+       {\r
+               for (s = 0; s < 4; s++) {\r
+                       ss.state_phase = (ym2612.CH[c].SLOT[s].state << 29) | (ym2612.CH[c].SLOT[s].phase >> 3);\r
+                       ss.volume = ym2612.CH[c].SLOT[s].volume;\r
+                       if (ym2612.CH[c].SLOT[s].key)\r
+                               sa.keyon_field |= 1 << (c*4 + s);\r
+                       memcpy(ptr, &ss, 6);\r
+                       ptr += 6;\r
+               }\r
+               sa2.block_fnum[c] = ym2612.CH[c].block_fnum;\r
+       }\r
+       // chans 4,5,6\r
+       ptr = &ym2612.REGS[0x1b8];\r
+       for (; c < 6; c++)\r
+       {\r
+               for (s = 0; s < 4; s++) {\r
+                       ss.state_phase = (ym2612.CH[c].SLOT[s].state << 29) | (ym2612.CH[c].SLOT[s].phase >> 3);\r
+                       ss.volume = ym2612.CH[c].SLOT[s].volume;\r
+                       if (ym2612.CH[c].SLOT[s].key)\r
+                               sa.keyon_field |= 1 << (c*4 + s);\r
+                       memcpy(ptr, &ss, 6);\r
+                       ptr += 6;\r
+               }\r
+               sa2.block_fnum[c] = ym2612.CH[c].block_fnum;\r
+       }\r
+       for (c = 0; c < 3; c++)\r
+       {\r
+               sa2.block_fnum_sl3[c] = ym2612.OPN.SL3.block_fnum[c];\r
+       }\r
+\r
+       memcpy(&ym2612.REGS[0], &sa2, sizeof(sa2)); // 0x20 max\r
+\r
+       // other things\r
+       ptr = &ym2612.REGS[0x100];\r
+       sa.magic = 0x41534d59; // 'YMSA'\r
+       sa.address = ym2612.OPN.ST.address;\r
+       sa.status  = ym2612.OPN.ST.status;\r
+       sa.addr_A1 = ym2612.addr_A1;\r
+       sa.TAT     = tat;\r
+       sa.TBT     = tbt;\r
+       sa.eg_cnt  = ym2612.OPN.eg_cnt;\r
+       sa.eg_timer = ym2612.OPN.eg_timer;\r
+       sa.lfo_cnt  = ym2612.OPN.lfo_cnt;\r
+       sa.lfo_ampm = g_lfo_ampm;\r
+       memcpy(ptr, &sa, sizeof(sa)); // 0x30 max\r
+}\r
+\r
+int YM2612PicoStateLoad2(int *tat, int *tbt)\r
+{\r
+       ym_save_addon_slot ss;\r
+       ym_save_addon2 sa2;\r
+       ym_save_addon sa;\r
+       unsigned char *ptr;\r
+       UINT32 fn;\r
+       UINT8 blk;\r
+       int c, s;\r
+\r
+       ptr = &ym2612.REGS[0x100];\r
+       memcpy(&sa, ptr, sizeof(sa)); // 0x30 max\r
+       if (sa.magic != 0x41534d59) return -1;\r
+\r
+       ptr = &ym2612.REGS[0];\r
+       memcpy(&sa2, ptr, sizeof(sa2));\r
+\r
+       ym2612.OPN.ST.address = sa.address;\r
+       ym2612.OPN.ST.status = sa.status;\r
+       ym2612.addr_A1 = sa.addr_A1;\r
+       ym2612.OPN.eg_cnt = sa.eg_cnt;\r
+       ym2612.OPN.eg_timer = sa.eg_timer;\r
+       ym2612.OPN.lfo_cnt = sa.lfo_cnt;\r
+       g_lfo_ampm = sa.lfo_ampm;\r
+       if (tat != NULL) *tat = sa.TAT;\r
+       if (tbt != NULL) *tbt = sa.TBT;\r
+\r
+       // chans 1,2,3\r
+       ptr = &ym2612.REGS[0x0b8];\r
+       for (c = 0; c < 3; c++)\r
+       {\r
+               for (s = 0; s < 4; s++) {\r
+                       memcpy(&ss, ptr, 6);\r
+                       ym2612.CH[c].SLOT[s].state = ss.state_phase >> 29;\r
+                       ym2612.CH[c].SLOT[s].phase = ss.state_phase << 3;\r
+                       ym2612.CH[c].SLOT[s].volume = ss.volume;\r
+                       ym2612.CH[c].SLOT[s].key = (sa.keyon_field & (1 << (c*4 + s))) ? 1 : 0;\r
+                       ym2612.CH[c].SLOT[s].ksr = (UINT8)-1;\r
+                       ptr += 6;\r
+               }\r
+               ym2612.CH[c].SLOT[SLOT1].Incr=-1;\r
+               ym2612.CH[c].block_fnum = sa2.block_fnum[c];\r
+               fn = ym2612.CH[c].block_fnum & 0x7ff;\r
+               blk = ym2612.CH[c].block_fnum >> 11;\r
+               ym2612.CH[c].kcode= (blk<<2) | opn_fktable[fn >> 7];\r
+               ym2612.CH[c].fc = fn_table[fn*2]>>(7-blk);\r
+       }\r
+       // chans 4,5,6\r
+       ptr = &ym2612.REGS[0x1b8];\r
+       for (; c < 6; c++)\r
+       {\r
+               for (s = 0; s < 4; s++) {\r
+                       memcpy(&ss, ptr, 6);\r
+                       ym2612.CH[c].SLOT[s].state = ss.state_phase >> 29;\r
+                       ym2612.CH[c].SLOT[s].phase = ss.state_phase << 3;\r
+                       ym2612.CH[c].SLOT[s].volume = ss.volume;\r
+                       ym2612.CH[c].SLOT[s].key = (sa.keyon_field & (1 << (c*4 + s))) ? 1 : 0;\r
+                       ym2612.CH[c].SLOT[s].ksr = (UINT8)-1;\r
+                       ptr += 6;\r
+               }\r
+               ym2612.CH[c].SLOT[SLOT1].Incr=-1;\r
+               ym2612.CH[c].block_fnum = sa2.block_fnum[c];\r
+               fn = ym2612.CH[c].block_fnum & 0x7ff;\r
+               blk = ym2612.CH[c].block_fnum >> 11;\r
+               ym2612.CH[c].kcode= (blk<<2) | opn_fktable[fn >> 7];\r
+               ym2612.CH[c].fc = fn_table[fn*2]>>(7-blk);\r
+       }\r
+       for (c = 0; c < 3; c++)\r
+       {\r
+               ym2612.OPN.SL3.block_fnum[c] = sa2.block_fnum_sl3[c];\r
+               fn = ym2612.OPN.SL3.block_fnum[c] & 0x7ff;\r
+               blk = ym2612.OPN.SL3.block_fnum[c] >> 11;\r
+               ym2612.OPN.SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];\r
+               ym2612.OPN.SL3.fc[c] = fn_table[fn*2]>>(7-blk);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+void *YM2612GetRegs(void)\r
+{\r
+       return ym2612.REGS;\r
+}\r
+\r