MCUME/MCUME_teensy/teensygen/sound.c

171 wiersze
4.5 KiB
C

/*
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);
}
}