dualcore integration in famc, bram cart C code, psp bugfixes
[picodrive.git] / Pico / sound / ym2612.c
index 60d6c81..f626260 100644 (file)
 #include <math.h>\r
 \r
 #include "ym2612.h"\r
-#include "mix.h"\r
 \r
 #ifndef EXTERNAL_YM2612\r
 #include <stdlib.h>\r
@@ -125,6 +124,8 @@ extern YM2612 *ym2612_940;
 \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
@@ -841,7 +842,7 @@ typedef struct
        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 */\r
+       UINT32 algo;     /* 50: algo[3], was_update */\r
        INT32  op1_out;\r
 } chan_rend_context;\r
 \r
@@ -1077,6 +1078,7 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
                        } 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
@@ -1091,7 +1093,7 @@ void chan_render_loop(chan_rend_context *ct, int *buffer, unsigned short length)
 #endif\r
 \r
 \r
-static void chan_render(int *buffer, int length, FM_CH *CH, UINT32 flags) // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
+static int chan_render(int *buffer, int length, FM_CH *CH, UINT32 flags) // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
 {\r
        chan_rend_context ct;\r
 \r
@@ -1193,6 +1195,8 @@ static void chan_render(int *buffer, int length, FM_CH *CH, UINT32 flags) // fla
        CH->SLOT[SLOT3].phase = ct.phase3;\r
        CH->SLOT[SLOT4].phase = ct.phase4;\r
        CH->mem_value = ct.mem;\r
+\r
+       return (ct.algo & 8) >> 3; // had output\r
 }\r
 \r
 /* update phase increment and envelope generator */\r
@@ -1587,6 +1591,7 @@ INT32 *ym2612_dacout;
 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
@@ -1613,14 +1618,15 @@ int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)
        if (stereo) stereo = 1;\r
 \r
        /* mix to 32bit dest */\r
-       chan_render(buffer, length, &ym2612.CH[0], stereo|((pan&0x003)<<4)); // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
-       chan_render(buffer, length, &ym2612.CH[1], stereo|((pan&0x00c)<<2));\r
-       chan_render(buffer, length, &ym2612.CH[2], stereo|((pan&0x030)   ));\r
-       chan_render(buffer, length, &ym2612.CH[3], stereo|((pan&0x0c0)>>2));\r
-       chan_render(buffer, length, &ym2612.CH[4], stereo|((pan&0x300)>>4));\r
-       chan_render(buffer, length, &ym2612.CH[5], stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)|2);\r
-\r
-       return 1; // buffer updated\r
+       // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
+       active_chs |= chan_render(buffer, length, &ym2612.CH[0], stereo|((pan&0x003)<<4)) << 0;\r
+       active_chs |= chan_render(buffer, length, &ym2612.CH[1], stereo|((pan&0x00c)<<2)) << 1;\r
+       active_chs |= chan_render(buffer, length, &ym2612.CH[2], stereo|((pan&0x030)   )) << 2;\r
+       active_chs |= chan_render(buffer, length, &ym2612.CH[3], stereo|((pan&0x0c0)>>2)) << 3;\r
+       active_chs |= chan_render(buffer, length, &ym2612.CH[4], stereo|((pan&0x300)>>4)) << 4;\r
+       active_chs |= chan_render(buffer, length, &ym2612.CH[5], stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)|2) << 5;\r
+\r
+       return active_chs; // 1 if buffer updated\r
 }\r
 \r
 \r
@@ -1631,8 +1637,7 @@ void YM2612Init_(int clock, int rate)
        ym2612_dacen = &ym2612.dacen;\r
        ym2612_dacout = &ym2612.dacout;\r
 \r
-       /* clear everything but the regs */\r
-       memset(ym2612.CH, 0, sizeof(ym2612)-sizeof(ym2612.REGS)-4);\r
+       memset(&ym2612, 0, sizeof(ym2612));\r
        init_tables();\r
 \r
        ym2612.OPN.ST.clock = clock;\r
@@ -1648,8 +1653,11 @@ void YM2612ResetChip_(void)
 {\r
        int i;\r
 \r
+       memset(ym2612.REGS, 0, sizeof(ym2612.REGS));\r
+\r
        OPNSetPres( 6*24 );\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
@@ -1660,6 +1668,8 @@ void YM2612ResetChip_(void)
        {\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
@@ -1669,6 +1679,7 @@ void YM2612ResetChip_(void)
        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
@@ -1696,7 +1707,9 @@ int YM2612Write_(unsigned int a, unsigned int v)
                }\r
 \r
                addr = ym2612.OPN.ST.address;\r
+#ifndef EXTERNAL_YM2612\r
                ym2612.REGS[addr] = v;\r
+#endif\r
 \r
                switch( addr & 0xf0 )\r
                {\r
@@ -1794,7 +1807,9 @@ int YM2612Write_(unsigned int a, unsigned int v)
                }\r
 \r
                addr = ym2612.OPN.ST.address | 0x100;\r
+#ifndef EXTERNAL_YM2612\r
                ym2612.REGS[addr] = v;\r
+#endif\r
 \r
                ret = OPNWriteReg(addr, v);\r
                break;\r
@@ -1842,7 +1857,7 @@ int YM2612PicoTick_(int n)
 void YM2612PicoStateLoad_(void)\r
 {\r
 #ifndef EXTERNAL_YM2612\r
-       int i, old_A1 = ym2612.addr_A1;\r
+       int i, real_A1 = ym2612.addr_A1;\r
 \r
        reset_channels( &ym2612.CH[0], 6 );\r
 \r
@@ -1851,19 +1866,23 @@ void YM2612PicoStateLoad_(void)
                YM2612Write_(0, i);\r
                YM2612Write_(1, ym2612.REGS[i]);\r
        }\r
+\r
        for(i = 0; i < 0x100; i++) {\r
                YM2612Write_(2, i);\r
                YM2612Write_(3, ym2612.REGS[i|0x100]);\r
        }\r
 \r
-       ym2612.addr_A1 = old_A1;\r
+       ym2612.addr_A1 = real_A1;\r
 #else\r
        reset_channels( &ym2612.CH[0], 6 );\r
 #endif\r
 }\r
 \r
 \r
+#ifndef EXTERNAL_YM2612\r
 void *YM2612GetRegs(void)\r
 {\r
        return ym2612.REGS;\r
 }\r
+#endif\r
+\r