diff --git a/src/include/86box/snd_opl.h b/src/include/86box/snd_opl.h index f01ea0214..38077e1d3 100644 --- a/src/include/86box/snd_opl.h +++ b/src/include/86box/snd_opl.h @@ -38,7 +38,8 @@ typedef struct { uint8_t status; uint8_t status_mask; uint8_t timer_ctrl; - uint16_t timer[2]; + uint16_t timer_count[2], + timer_cur_count[2]; pc_timer_t timers[2]; diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 07a7370fe..7fbfd3fc6 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -51,35 +51,66 @@ enum { }; -static void -status_update(opl_t *dev) -{ - if (dev->status & (STATUS_TIMER_1 | STATUS_TIMER_2) & dev->status_mask) - dev->status |= STATUS_TIMER_ALL; - else - dev->status &= ~STATUS_TIMER_ALL; -} +#ifdef ENABLE_OPL_LOG +int opl_do_log = ENABLE_OPL_LOG; static void -timer_set(opl_t *dev, int timer, uint64_t period) +opl_log(const char *fmt, ...) { - timer_on_auto(&dev->timers[timer], ((double) period) * 20.0); + va_list ap; + + if (opl_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } } +#else +#define opl_log(fmt, ...) +#endif static void timer_over(opl_t *dev, int tmr) { - if (tmr) { + opl_log("Count wrapped around to zero, reloading timer %i...\n", tmr); + + if (tmr == 1) { dev->status |= STATUS_TIMER_2; - timer_set(dev, 1, dev->timer[1] * 16); + dev->timer_cur_count[1] = dev->timer_count[1]; } else { dev->status |= STATUS_TIMER_1; - timer_set(dev, 0, dev->timer[0] * 4); + dev->timer_cur_count[0] = dev->timer_count[0]; } +} - status_update(dev); + +static void +timer_tick(opl_t *dev, int tmr) +{ + dev->timer_cur_count[tmr] = (dev->timer_cur_count[tmr] + 1) & 0xff; + + opl_log("Ticking timer %i, count now %02X...\n", tmr, dev->timer_cur_count[tmr]); + + if (dev->timer_cur_count[tmr] == 0x00) + timer_over(dev, tmr); + + timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); +} + + +static void +timer_control(opl_t *dev, int tmr, int start) +{ + timer_on_auto(&dev->timers[tmr], 0.0); + + if (start) { + opl_log("Loading timer %i count: %02X = %02X\n", tmr, dev->timer_cur_count[tmr], dev->timer_count[tmr]); + dev->timer_cur_count[tmr] = dev->timer_count[tmr]; + timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); + } else + opl_log("Timer %i stopped\n", tmr); } @@ -88,7 +119,7 @@ timer_1(void *priv) { opl_t *dev = (opl_t *)priv; - timer_over(dev, 0); + timer_tick(dev, 0); } @@ -97,27 +128,56 @@ timer_2(void *priv) { opl_t *dev = (opl_t *)priv; - timer_over(dev, 1); + timer_tick(dev, 1); } static uint8_t opl_read(opl_t *dev, uint16_t port) { - if (! (port & 1)) - return((dev->status & dev->status_mask) | (dev->is_opl3 ? 0x00 : 0x06)); + uint8_t ret = 0xff; - if (dev->is_opl3 && ((port & 0x03) == 0x03)) - return(0x00); + if ((port & 0x0003) == 0x0000) { + ret = ((dev->status & dev->status_mask) | (dev->is_opl3 ? 0x00 : 0x06)); + if (dev->status & dev->status_mask) + ret |= STATUS_TIMER_ALL; + } - return(dev->is_opl3 ? 0x00 : 0xff); + return ret; } static void opl_write(opl_t *dev, uint16_t port, uint8_t val) { - if (! (port & 1)) { + if ((port & 0x0001) == 0x0001) { + nuked_write_reg_buffered(dev->opl, dev->port, val); + + switch (dev->port) { + case 0x02: /* Timer 1 */ + dev->timer_count[0] = val; + opl_log("Timer 0 count now: %i\n", dev->timer_count[0]); + break; + + case 0x03: /* Timer 2 */ + dev->timer_count[1] = val; + opl_log("Timer 1 count now: %i\n", dev->timer_count[1]); + break; + + case 0x04: /* Timer control */ + if (val & CTRL_IRQ_RESET) { + opl_log("Resetting timer status...\n"); + dev->status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + } else { + timer_control(dev, 0, val & CTRL_TIMER1_CTRL); + timer_control(dev, 1, val & CTRL_TIMER2_CTRL); + dev->timer_ctrl = val; + dev->status_mask = (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK) & ~(val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)); + opl_log("Status mask now %02X (val = %02X)\n", dev->status_mask, val); + } + break; + } + } else { dev->port = nuked_write_addr(dev->opl, port, val) & 0x01ff; if (! dev->is_opl3) @@ -125,40 +185,6 @@ opl_write(opl_t *dev, uint16_t port, uint8_t val) return; } - - nuked_write_reg_buffered(dev->opl, dev->port, val); - - switch (dev->port) { - case 0x02: // timer 1 - dev->timer[0] = 256 - val; - break; - - case 0x03: // timer 2 - dev->timer[1] = 256 - val; - break; - - case 0x04: // timer control - if (val & CTRL_IRQ_RESET) { - dev->status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); - status_update(dev); - return; - } - if ((val ^ dev->timer_ctrl) & CTRL_TIMER1_CTRL) { - if (val & CTRL_TIMER1_CTRL) - timer_set(dev, 0, dev->timer[0] * 4); - else - timer_set(dev, 0, 0); - } - if ((val ^ dev->timer_ctrl) & CTRL_TIMER2_CTRL) { - if (val & CTRL_TIMER2_CTRL) - timer_set(dev, 1, dev->timer[1] * 16); - else - timer_set(dev, 1, 0); - } - dev->status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; - dev->timer_ctrl = val; - break; - } } diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c index 0a5124913..46dbbf071 100644 --- a/src/sound/snd_opl_nuked.c +++ b/src/sound/snd_opl_nuked.c @@ -1079,7 +1079,7 @@ nuked_write_addr(void *priv, uint16_t port, uint8_t val) uint16_t addr; addr = val; - if ((port & 0x0002) && (addr == 0x0005 || dev->newm)) + if ((port & 0x0002) && ((addr == 0x0005) || dev->newm)) addr |= 0x0100; return(addr); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index e42317536..5f38085a2 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -106,7 +106,7 @@ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { int32_t out = 0; if (sb->opl_enabled) - out = ((sb->opl.buffer[c] * (sb->opl_emu ? 47000 : 51000)) >> 16); + out = ((sb->opl.buffer[c] * 47000) >> 16); //TODO: Recording: Mic and line In with AGC out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; @@ -140,7 +140,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) int32_t out = 0; if (sb->opl_enabled) - out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * 47000) >> 15); /* TODO: Recording : I assume it has direct mic and line in like sb2 */ /* It is unclear from the docs if it has a filter, but it probably does */ @@ -188,11 +188,11 @@ void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) * Each chip stores data into the LEFT channel * only (no sample alternating.) */ - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - out_r = ((((sb->opl2.buffer[c] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * 47000) >> 15); + out_r = ((((sb->opl2.buffer[c] * mixer->fm_r) >> 16) * 47000) >> 15); } else { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * 47000) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * 47000) >> 15); } } @@ -244,8 +244,8 @@ static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) int32_t out_l = 0, out_r = 0, in_l, in_r; if (sb->opl_enabled) { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * 47000) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * 47000) >> 15); } /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ @@ -328,8 +328,8 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) int c_emu8k = (((c/2) * 44100) / 48000)*2; if (sb->opl_enabled) { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 15) * 47000) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 15) * 47000) >> 16); } out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 15); @@ -636,6 +636,9 @@ void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) { /* Reset */ /* Changed defaults from -14dB to 0dB*/ + mixer->regs[0x0E]=0x02; + sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0E] & 2); + mixer->regs[0x30]=31 << 3; mixer->regs[0x31]=31 << 3; mixer->regs[0x32]=31 << 3; @@ -826,6 +829,9 @@ uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) case 0x08: ret = ((mixer->regs[0x36] >> 4) & 0x0f); break; + case 0x0e: + ret = 0x02; + break; case 0x22: ret = ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); break;