Fix slow/missing note OPL2 playback on complex songs

This commit is contained in:
Ian Scott committed 2025-06-15 22:26:45 -06:00
1 parent 771f8f8948
commit 88f52d6d96
4 files changed
+52 -85

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ extern "C" {
#include <stdbool.h>
#define SETTINGS_MAGIC 0x70677573 // "pgus" in ascii
#define SETTINGS_VERSION 2
#define SETTINGS_VERSION 3
// Settings struct has generous padding for future settings by aligning to 4 bytes
typedef struct Settings {
+2 -2
View File
@@ -383,7 +383,7 @@ static void OPLTimer_CalculateEndTime(opl_timer_t *timer)
}
}
static void WriteRegister(unsigned int reg_num, unsigned int value)
void OPL_Pico_WriteRegister(unsigned int reg_num, unsigned int value)
{
switch (reg_num)
{
@@ -450,7 +450,7 @@ void OPL_Pico_PortWrite(opl_port_t port, unsigned int value)
}
else if (port == OPL_DATA_PORT)
{
WriteRegister(register_num, value);
OPL_Pico_WriteRegister(register_num, value);
}
}
+19 -45
View File
@@ -69,10 +69,9 @@ extern void sbdsp_process();
#include "opl.h"
void play_adlib(void);
extern "C" int OPL_Pico_Init(unsigned int);
extern "C" void OPL_Pico_PortWrite(opl_port_t, unsigned int);
extern "C" unsigned int OPL_Pico_PortRead(opl_port_t);
// #include "cmd_buffers.h"
// cms_buffer_t opl_buffer = { {0}, 0, 0 };
#include "cmd_buffers.h"
cms_buffer_t opl_buffer = { {0}, 0, 0 };
#endif
#ifdef CDROM
@@ -648,29 +647,18 @@ __force_inline void handle_iow(void) {
if ((port >> 4) == sb_port_test) {
switch (port - settings.SB.basePort) {
// OPL ports
case 0x8 ... 0x9:
case 0x8:
// Fast write
// pio_sm_put(pio0, IOW_PIO_SM, IO_END);
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
/*
opl_buffer.cmds[opl_buffer.head++] = {
OPL_REGISTER_PORT,
(uint8_t)(iow_read & 0xFF)
};
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
// pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
opl_buffer.cmds[opl_buffer.head].addr = (uint16_t)(iow_read & 0xFF);
// Fast write - return early as we've already written 0x0u to the PIO
return;
*/
OPL_Pico_PortWrite((opl_port_t)(port & 1), (uint8_t)(iow_read & 0xFF));
break;
/*
case 0x9:
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
opl_buffer.cmds[opl_buffer.head++] = {
OPL_DATA_PORT,
(uint8_t)(iow_read & 0xFF)
};
opl_buffer.cmds[opl_buffer.head++].data = (uint8_t)(iow_read & 0xFF);
break;
*/
// DSP ports
default:
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
@@ -690,29 +678,19 @@ __force_inline void handle_iow(void) {
#endif
#if defined(SOUND_OPL)
if ((port & 0x3fe) == settings.SB.oplBasePort) {
/*
// Fast write
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
opl_buffer.cmds[opl_buffer.head++] = {
OPL_REGISTER_PORT,
(uint8_t)(iow_read & 0xFF)
};
// Fast write - return early as we've already written 0x0u to the PIO
return;
*/
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
OPL_Pico_PortWrite((opl_port_t)(port & 1), (uint8_t)(iow_read & 0xFF));
/*
} else if (port == settings.SB.oplBasePort + 1) {
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
if (settings.SB.oplSpeedSensitive) {
busy_wait_us(1); // busy wait for speed sensitive games
if ((port & 1) == 0) {
// Fast write
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
opl_buffer.cmds[opl_buffer.head].addr = (uint16_t)(iow_read & 0xFF);
// Fast write - return early as we've already written 0x0u to the PIO
return;
} else {
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
if (settings.SB.oplSpeedSensitive) {
busy_wait_us(1); // busy wait for speed sensitive games
}
opl_buffer.cmds[opl_buffer.head++].data = (uint8_t)(iow_read & 0xFF);
}
opl_buffer.cmds[opl_buffer.head++] = {
OPL_DATA_PORT,
(uint8_t)(iow_read & 0xFF)
};
*/
} else // if follows down below
#endif // SOUND_OPL
#ifdef SOUND_TANDY
@@ -848,12 +826,10 @@ __force_inline void handle_ior(void) {
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
switch (port - settings.SB.basePort) {
case 0x8:
/*
// wait for OPL buffer to process
while (opl_buffer.tail != opl_buffer.head) {
tight_loop_contents();
}
*/
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | OPL_Pico_PortRead(OPL_REGISTER_PORT));
break;
default:
@@ -876,12 +852,10 @@ __force_inline void handle_ior(void) {
if (port == settings.SB.oplBasePort) {
// Tell PIO to wait for data
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
/*
// wait for OPL buffer to process
while (opl_buffer.tail != opl_buffer.head) {
tight_loop_contents();
}
*/
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | OPL_Pico_PortRead(OPL_REGISTER_PORT));
} else // if follows down below
#endif
+30 -37
View File
@@ -31,7 +31,7 @@
#include "opl.h"
extern "C" void OPL_Pico_simple(int16_t *buffer, uint32_t nsamples);
extern "C" void OPL_Pico_PortWrite(opl_port_t, unsigned int);
extern "C" void OPL_Pico_WriteRegister(unsigned int reg_num, unsigned int value);
#include "audio_fifo.h"
#if SOUND_SB
@@ -192,7 +192,9 @@ void play_adlib() {
uint32_t cd_left = 0;
uint32_t cd_index = 0;
int16_t opl_samples[SAMPLES_PER_BUFFER * 2] = {0};
constexpr uint32_t OPL_SAMPLE_COUNT = 8;
constexpr uint32_t OPL_BUFFER_BITS = (OPL_SAMPLE_COUNT << 1) - 1;
int16_t opl_samples[OPL_SAMPLE_COUNT << 1] = {0};
uint32_t opl_ratio = fixed_ratio(49716, 44100);
printf("opl_ratio: %x ", opl_ratio);
uint32_t opl_pos = 0;
@@ -203,7 +205,6 @@ void play_adlib() {
int32_t accum[2] = {0};
for (;;) {
#if CDROM
has_cd_samples = cdrom_audio_callback_simple(&cdrom, cd_samples, SAMPLES_PER_BUFFER << 1, true);
#endif
@@ -221,44 +222,36 @@ void play_adlib() {
accum[1] += cd_samples[(i << 1) + 1];
}
#endif // CDROM
uint32_t opl_index = (opl_pos >> FRAC_BITS);
// uint32_t opl_index = i;
uint32_t opl_frac = opl_pos & FRAC_MASK;
opl_pos += opl_ratio;
// printf("%x %x\n", opl_index, opl_frac);
uint32_t opl_index = (opl_pos >> FRAC_BITS);
// uint32_t opl_index = i;
uint32_t opl_frac = opl_pos & FRAC_MASK;
opl_pos += opl_ratio;
#if !SB_BUFFERLESS // don't support OPL in bufferless for now
if (
((opl_index & SAMPLES_PER_BUFFER) && opl_sample_idx != 0x0) ||
(!(opl_index & SAMPLES_PER_BUFFER) && opl_sample_idx != SAMPLES_PER_BUFFER)
) {
opl_sample_idx = (opl_index + SAMPLES_PER_BUFFER) & SAMPLES_PER_BUFFER;
/*
bool notfirst = false;
while (opl_buffer.tail != opl_buffer.head) {
if (!notfirst) {
if (
((opl_index & OPL_SAMPLE_COUNT) && opl_sample_idx != 0x0) ||
(!(opl_index & OPL_SAMPLE_COUNT) && opl_sample_idx != OPL_SAMPLE_COUNT)
) {
opl_sample_idx = (opl_index + OPL_SAMPLE_COUNT) & OPL_SAMPLE_COUNT;
// bool notfirst = false;
while (opl_buffer.tail != opl_buffer.head) {
// if (!notfirst) {
#ifndef PICOW
gpio_xor_mask(LED_PIN);
// gpio_xor_mask(LED_PIN);
#endif
notfirst = true;
}
auto cmd = opl_buffer.cmds[opl_buffer.tail];
OPL_Pico_PortWrite((opl_port_t)cmd.addr, cmd.data);
++opl_buffer.tail;
}
*/
OPL_Pico_simple(opl_samples + opl_sample_idx, SAMPLES_PER_BUFFER);
// notfirst = true;
// }
auto cmd = opl_buffer.cmds[opl_buffer.tail];
OPL_Pico_WriteRegister(cmd.addr, cmd.data);
++opl_buffer.tail;
}
int32_t opl_sample = lerp_fixed(
opl_samples[opl_index & 0x1ff],
opl_samples[(opl_index + 1) & 0x1ff],
opl_frac);
accum[0] += opl_samples[opl_index & 0x1ff];
accum[1] += opl_samples[opl_index & 0x1ff];
#if CDROM
//}
#endif
OPL_Pico_simple(opl_samples + opl_sample_idx, OPL_SAMPLE_COUNT);
}
int32_t opl_sample = lerp_fixed(
opl_samples[opl_index & OPL_BUFFER_BITS],
opl_samples[(opl_index + 1) & OPL_BUFFER_BITS],
opl_frac);
accum[0] += opl_sample;
accum[1] += opl_sample;
#if SOUND_SB
if (!sb_left) {
// putchar('t');