/* sound.c YM2612 and SN76489 emulation */ #include "shared.h" /* YM2612 data */ int fm_timera_tab[0x400]; /* Precalculated timer A values */ int fm_timerb_tab[0x100]; /* Precalculated timer B values */ uint8 fm_reg[2][0x100]; /* Register arrays (2x256) */ uint8 fm_latch[2]; /* Register latches */ uint8 fm_status; /* Read-only status flags */ t_timer timer[2]; /* Timers A and B */ /* Initialize the YM2612 and SN76489 emulation */ void sound_init(void) { /* Timers run at half the YM2612 input clock */ float clock = ((53.693175 / 7) / 2); int i; /* Make Timer A table */ for(i = 0; i < 1024; i += 1) { /* Formula is "time(us) = 72 * (1024 - A) / clock" */ fm_timera_tab[i] = ((int)(float)(72 * (1024 - i)) / (clock)); } /* Make Timer B table */ for(i = 0; i < 256; i += 1) { /* Formula is "time(us) = 1152 * (256 - B) / clock" */ fm_timerb_tab[i] = (int)(float)(1152 * (256 - i)) / clock; } } void sound_reset(void) { if(snd.enabled) { YM2612ResetChip(0); } } void fm_write(int address, int data) { int a0 = (address & 1); int a1 = (address >> 1) & 1; if(a0) { /* Register data */ fm_reg[a1][fm_latch[a1]] = data; /* Timer control only in set A */ if(a1 == 0) switch(fm_latch[a1]) { case 0x24: /* Timer A (LSB) */ timer[0].index = (timer[0].index & 0x0003) | (data << 2); timer[0].index &= 0x03FF; timer[0].base = fm_timera_tab[timer[0].index]; break; case 0x25: /* Timer A (MSB) */ timer[0].index = (timer[0].index & 0x03FC) | (data & 3); timer[0].index &= 0x03FF; timer[0].base = fm_timera_tab[timer[0].index]; break; case 0x26: /* Timer B */ timer[1].index = data; timer[1].base = timer[1].count = fm_timerb_tab[timer[1].index]; break; case 0x27: /* Timer Control */ /* LOAD */ timer[0].running = (data >> 0) & 1; if(timer[0].running) timer[0].count = 0; timer[1].running = (data >> 1) & 1; if(timer[1].running) timer[1].count = 0; /* ENABLE */ timer[0].enable = (data >> 2) & 1; timer[1].enable = (data >> 3) & 1; /* RESET */ if(data & 0x10) fm_status &= ~1; if(data & 0x20) fm_status &= ~2; break; } } else { /* Register latch */ fm_latch[a1] = data; } if(snd.enabled) { if(snd.fm.curStage - snd.fm.lastStage > 1) { int16 *tempBuffer[2]; tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage; tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; YM2612UpdateOne(0, (int16 **)tempBuffer, snd.fm.curStage - snd.fm.lastStage); snd.fm.lastStage = snd.fm.curStage; } YM2612Write(0, address & 3, data); } } int fm_read(int address) { return (fm_status); } void fm_update_timers(void) { int i; /* Process YM2612 timers */ for(i = 0; i < 2; i += 1) { /* Is the timer running? */ if(timer[i].running) { /* Each scanline takes up roughly 64 microseconds */ timer[i].count += 64; /* Check if the counter overflowed */ if(timer[i].count > timer[i].base) { /* Reload counter */ timer[i].count = 0; /* Disable timer */ timer[i].running = 0; /* Set overflow flag (if flag setting is enabled) */ if(timer[i].enable) { fm_status |= (1 << i); } } } } } void psg_write(int data) { if(snd.enabled) { if(snd.psg.curStage - snd.psg.lastStage > 1) { int16 *tempBuffer; tempBuffer = snd.psg.buffer + snd.psg.lastStage; SN76496Update(0, tempBuffer, snd.psg.curStage - snd.psg.lastStage); snd.psg.lastStage = snd.psg.curStage; } SN76496Write(0, data); } }