/*\r
-** This is a bunch of remains of original fm.c from MAME project. All stuff \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
\r
#else\r
extern YM2612 *ym2612_940;\r
-extern int *mix_buffer;\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
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
} 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
#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
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
\r
\r
/* Generate samples for YM2612 */\r
-void YM2612UpdateOne_(short *buffer, int length, int stereo)\r
+int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)\r
{\r
int pan;\r
-#ifndef EXTERNAL_YM2612\r
- int i;\r
- static int *mix_buffer = 0, mix_buffer_length = 0;\r
-#endif\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
/* refresh PG and EG */\r
refresh_fc_eg_chan( &ym2612.CH[0] );\r
pan = ym2612.OPN.pan;\r
if (stereo) stereo = 1;\r
\r
-#ifndef EXTERNAL_YM2612\r
- if (mix_buffer_length < length) {\r
- mix_buffer = realloc(mix_buffer, length*4<<stereo); // FIXME: need to free this at some point\r
- if (!mix_buffer) return;\r
- mix_buffer_length = length;\r
- }\r
-#endif\r
- memset(mix_buffer, 0, length*4<<stereo);\r
+ /* mix to 32bit dest */\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
- /* mix to 32bit temporary buffer */\r
- chan_render(mix_buffer, length, &ym2612.CH[0], stereo|((pan&0x003)<<4)); // flags: stereo, lastchan, disabled, ?, pan_r, pan_l\r
- chan_render(mix_buffer, length, &ym2612.CH[1], stereo|((pan&0x00c)<<2));\r
- chan_render(mix_buffer, length, &ym2612.CH[2], stereo|((pan&0x030) ));\r
- chan_render(mix_buffer, length, &ym2612.CH[3], stereo|((pan&0x0c0)>>2));\r
- chan_render(mix_buffer, length, &ym2612.CH[4], stereo|((pan&0x300)>>4));\r
- chan_render(mix_buffer, length, &ym2612.CH[5], stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)|2);\r
-\r
-#ifndef EXTERNAL_YM2612\r
- /* limit and mix to output buffer */\r
- if (stereo) {\r
- int *mb = mix_buffer;\r
- for (i = length; i > 0; i--) {\r
- int l, r;\r
- l = r = *buffer;\r
- l += *mb++, r += *mb++;\r
- Limit( l, MAXOUT, MINOUT );\r
- Limit( r, MAXOUT, MINOUT );\r
- *buffer++ = l; *buffer++ = r;\r
- }\r
- } else {\r
- for (i = 0; i < length; i++) {\r
- int l = mix_buffer[i];\r
- l += buffer[i];\r
- Limit( l, MAXOUT, MINOUT );\r
- buffer[i] = l;\r
- }\r
- }\r
-#endif\r
+ return active_chs; // 1 if buffer updated\r
}\r
\r
\r
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
{\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
{\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
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
}\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
}\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
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
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