From 808337aac32d83eaa140791b7bdb05f91f7d5885 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Mon, 25 Jul 2022 20:24:31 +0200 Subject: [PATCH] OPL: add the faster YMFM cores This refactors the OPL interface in two drivers : Nuked and YMFM Nuked is used by default, YMFM can be enabled with [Sound] fm_driver = ymfm --- src/86box.c | 1 + src/chipset/via_pipc.c | 14 +- src/config.c | 10 + src/include/86box/86box.h | 2 +- src/include/86box/snd_opl.h | 62 ++--- src/include/86box/snd_opl_nuked.h | 10 - src/include/86box/snd_sb.h | 2 +- src/include/86box/timer.h | 8 + src/sound/CMakeLists.txt | 5 +- src/sound/snd_adlib.c | 35 ++- src/sound/snd_adlibgold.c | 24 +- src/sound/snd_azt2316a.c | 8 +- src/sound/snd_cmi8x38.c | 28 +-- src/sound/snd_cs423x.c | 21 +- src/sound/snd_opl.c | 301 +++-------------------- src/sound/snd_opl_nuked.c | 283 ++++++++++++++++++++-- src/sound/snd_opl_ymfm.cpp | 387 ++++++++++++++++++++++++++++++ src/sound/snd_pas16.c | 14 +- src/sound/snd_sb.c | 277 ++++++++++----------- src/sound/snd_wss.c | 30 +-- src/sound/ymfm/CMakeLists.txt | 2 +- src/win/Makefile.mingw | 6 +- 22 files changed, 975 insertions(+), 555 deletions(-) create mode 100644 src/sound/snd_opl_ymfm.cpp diff --git a/src/86box.c b/src/86box.c index cb9fa52a7..f6b791901 100644 --- a/src/86box.c +++ b/src/86box.c @@ -183,6 +183,7 @@ int confirm_exit = 1; /* (C) enable exit confirmation */ int confirm_save = 1; /* (C) enable save confirmation */ int enable_discord = 0; /* (C) enable Discord integration */ int pit_mode = -1; /* (C) force setting PIT mode */ +int fm_driver = 0; /* (C) select FM sound driver */ /* Statistics. */ extern int mmuflush; diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index bcb54130f..b8c06b9f4 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -760,7 +760,7 @@ pipc_fm_read(uint16_t addr, void *priv) uint8_t ret = 0x00; #else pipc_t *dev = (pipc_t *) priv; - uint8_t ret = opl3_read(addr, &dev->sb->opl); + uint8_t ret = dev->sb->opl.read(addr, dev->sb->opl.priv); #endif pipc_log("PIPC: fm_read(%02X) = %02X\n", addr & 0x03, ret); @@ -794,7 +794,7 @@ pipc_fm_write(uint16_t addr, uint8_t val, void *priv) } } #else - opl3_write(addr, val, &dev->sb->opl); + dev->sb->opl.write(addr, val, dev->sb->opl.priv); #endif } @@ -807,22 +807,22 @@ pipc_sb_handlers(pipc_t *dev, uint8_t modem) sb_dsp_setaddr(&dev->sb->dsp, 0); if (dev->sb_base) { - io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); - io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); } mpu401_change_addr(dev->sb->mpu, 0); mpu401_setirq(dev->sb->mpu, 0); - io_removehandler(0x388, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(0x388, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); if (dev->ac97_regs[0][0x42] & 0x01) { dev->sb_base = 0x220 + (0x20 * (dev->ac97_regs[0][0x43] & 0x03)); sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); if (dev->ac97_regs[0][0x42] & 0x04) { - io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); - io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); } io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); diff --git a/src/config.c b/src/config.c index 8554dcc7a..81bbc016f 100644 --- a/src/config.c +++ b/src/config.c @@ -68,6 +68,7 @@ #include <86box/plat.h> #include <86box/plat_dir.h> #include <86box/ui.h> +#include <86box/snd_opl.h> typedef struct _list_ { @@ -1110,6 +1111,13 @@ load_sound(void) sound_is_float = 1; else sound_is_float = 0; + + p = config_get_string(cat, "fm_driver", "nuked"); + if (!strcmp(p, "ymfm")) { + fm_driver = FM_DRV_YMFM; + } else { + fm_driver = FM_DRV_NUKED; + } } /* Load "Network" section. */ @@ -2630,6 +2638,8 @@ save_sound(void) else config_set_string(cat, "sound_type", (sound_is_float == 1) ? "float" : "int16"); + config_set_string(cat, "fm_driver", (fm_driver == FM_DRV_NUKED) ? "nuked" : "ymfm"); + delete_section_if_empty(cat); } diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 86fe740c9..3d2806ce7 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -136,7 +136,7 @@ extern int is_pentium; /* TODO: Move back to cpu/cpu.h when it's figured out, extern int fixed_size_x, fixed_size_y; extern double mouse_sensitivity; /* (C) Mouse sensitivity scale */ extern int pit_mode; /* (C) force setting PIT mode */ - +extern int fm_driver; /* (C) select FM sound driver */ extern char exe_path[2048]; /* path (dir) of executable */ extern char usr_path[1024]; /* path (dir) of user data */ diff --git a/src/include/86box/snd_opl.h b/src/include/86box/snd_opl.h index ac8eef6fd..a2e8dd521 100644 --- a/src/include/86box/snd_opl.h +++ b/src/include/86box/snd_opl.h @@ -17,38 +17,40 @@ #ifndef SOUND_OPL_H #define SOUND_OPL_H -typedef void (*tmrfunc)(void *priv, int timer, uint64_t period); +enum fm_type { + FM_YM3812 = 0, + FM_YMF262, + FM_YMF289B, + FM_MAX +}; + +enum fm_driver { + FM_DRV_NUKED = 0, + FM_DRV_YMFM, + FM_DRV_MAX +}; -/* Define an OPLx chip. */ typedef struct { -#ifdef SOUND_OPL_NUKED_H - nuked_t *opl; -#else - void *opl; + uint8_t (*read)(uint16_t port, void *priv); + void (*write)(uint16_t port, uint8_t val, void *priv); + int32_t * (*update)(void *priv); + void (*reset_buffer)(void *priv); + void (*set_do_cycles)(void *priv, int8_t do_cycles); + void *priv; +} fm_drv_t; + +extern uint8_t fm_driver_get(int chip_id, fm_drv_t *drv); + +extern const fm_drv_t nuked_opl_drv; +extern const fm_drv_t ymfm_drv; + +#ifdef EMU_DEVICE_H +extern const device_t ym3812_nuked_device; +extern const device_t ymf262_nuked_device; + +extern const device_t ym3812_ymfm_device; +extern const device_t ymf262_ymfm_device; +extern const device_t ymf289b_ymfm_device; #endif - int8_t flags, pad; - - uint16_t port; - uint8_t status, timer_ctrl; - uint16_t timer_count[2], - timer_cur_count[2]; - - pc_timer_t timers[2]; - - int pos; - int32_t buffer[SOUNDBUFLEN * 2]; -} opl_t; - -extern void opl_set_do_cycles(opl_t *dev, int8_t do_cycles); - -extern uint8_t opl2_read(uint16_t port, void *); -extern void opl2_write(uint16_t port, uint8_t val, void *); -extern void opl2_init(opl_t *); -extern void opl2_update(opl_t *); - -extern uint8_t opl3_read(uint16_t port, void *); -extern void opl3_write(uint16_t port, uint8_t val, void *); -extern void opl3_init(opl_t *); -extern void opl3_update(opl_t *); #endif /*SOUND_OPL_H*/ diff --git a/src/include/86box/snd_opl_nuked.h b/src/include/86box/snd_opl_nuked.h index af65d266b..93ea4ba35 100644 --- a/src/include/86box/snd_opl_nuked.h +++ b/src/include/86box/snd_opl_nuked.h @@ -20,15 +20,5 @@ #ifndef SOUND_OPL_NUKED_H #define SOUND_OPL_NUKED_H -extern void *nuked_init(uint32_t sample_rate); -extern void nuked_close(void *); - -extern uint16_t nuked_write_addr(void *, uint16_t port, uint8_t val); -extern void nuked_write_reg(void *, uint16_t reg, uint8_t v); -extern void nuked_write_reg_buffered(void *, uint16_t reg, uint8_t v); - -extern void nuked_generate(void *, int32_t *buf); -extern void nuked_generate_resampled(void *, int32_t *buf); -extern void nuked_generate_stream(void *, int32_t *sndptr, uint32_t num); #endif /*SOUND_OPL_NUKED_H*/ diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index bf0b437b0..bf44d4d6d 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -129,7 +129,7 @@ typedef struct sb_t { opl_enabled, mixer_enabled; cms_t cms; - opl_t opl, + fm_drv_t opl, opl2; sb_dsp_t dsp; union { diff --git a/src/include/86box/timer.h b/src/include/86box/timer.h index 63ca8965b..afbcec140 100644 --- a/src/include/86box/timer.h +++ b/src/include/86box/timer.h @@ -56,6 +56,10 @@ typedef struct pc_timer_t struct pc_timer_t *prev, *next; } pc_timer_t; +#ifdef __cplusplus +extern "C" { +#endif + /*Timestamp of nearest enabled timer. CPU emulation must call timer_process() when TSC matches or exceeds this.*/ extern uint32_t timer_target; @@ -237,4 +241,8 @@ timer_process_inline(void) timer_target = timer_head->ts.ts32.integer; } +#ifdef __cplusplus +} +#endif + #endif /*_TIMER_H_*/ diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index c0aaa2790..581f8d517 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -13,7 +13,7 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_resid.cc +add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_resid.cc midi.c snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_ac97_codec.c snd_ac97_via.c snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c @@ -105,6 +105,9 @@ if(MUNT) endif() endif() +add_subdirectory(ymfm) +target_link_libraries(86Box ymfm) + if(PAS16) target_compile_definitions(snd PRIVATE USE_PAS16) target_sources(snd PRIVATE snd_pas16.c) diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 1592131d0..d4bc1e3ca 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -33,7 +33,7 @@ adlib_log(const char *fmt, ...) #endif typedef struct adlib_t { - opl_t opl; + fm_drv_t opl; uint8_t pos_regs[8]; } adlib_t; @@ -44,12 +44,12 @@ adlib_get_buffer(int32_t *buffer, int len, void *p) adlib_t *adlib = (adlib_t *) p; int c; - opl2_update(&adlib->opl); + int32_t *opl_buf = adlib->opl.update(adlib->opl.priv); for (c = 0; c < len * 2; c++) - buffer[c] += (int32_t) adlib->opl.buffer[c]; + buffer[c] += (int32_t) opl_buf[c]; - adlib->opl.pos = 0; + adlib->opl.reset_buffer(adlib->opl.priv); } uint8_t @@ -76,14 +76,14 @@ adlib_mca_write(int port, uint8_t val, void *p) case 0x102: if ((adlib->pos_regs[2] & 1) && !(val & 1)) io_removehandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &adlib->opl); + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); if (!(adlib->pos_regs[2] & 1) && (val & 1)) io_sethandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &adlib->opl); + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); break; } adlib->pos_regs[port & 7] = val; @@ -104,11 +104,11 @@ adlib_init(const device_t *info) memset(adlib, 0, sizeof(adlib_t)); adlib_log("adlib_init\n"); - opl2_init(&adlib->opl); + fm_driver_get(FM_YM3812, &adlib->opl); io_sethandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &adlib->opl); + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); sound_add_handler(adlib_get_buffer, adlib); return adlib; } @@ -119,9 +119,9 @@ adlib_mca_init(const device_t *info) adlib_t *adlib = adlib_init(info); io_removehandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &adlib->opl); + adlib->opl.read, NULL, NULL, + adlib->opl.write, NULL, NULL, + adlib->opl.priv); mca_add(adlib_mca_read, adlib_mca_write, adlib_mca_feedb, @@ -137,7 +137,6 @@ void adlib_close(void *p) { adlib_t *adlib = (adlib_t *) p; - free(adlib); } diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 652c672e2..0e504065b 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -54,7 +54,7 @@ typedef struct adgold_t { int voice_count[2], voice_latch[2]; } adgold_mma; - opl_t opl; + fm_drv_t opl; ym7128_t ym7128; int fm_vol_l, fm_vol_r; @@ -194,7 +194,7 @@ adgold_write(uint16_t addr, uint8_t val, void *p) switch (addr & 7) { case 0: case 1: - opl3_write(addr, val, &adgold->opl); + adgold->opl.write(addr, val, adgold->opl.priv); break; case 2: @@ -209,7 +209,7 @@ adgold_write(uint16_t addr, uint8_t val, void *p) if (adgold->adgold_38x_state) /*Write to control chip*/ adgold->adgold_38x_addr = val; else - opl3_write(addr, val, &adgold->opl); + adgold->opl.write(addr, val, adgold->opl.priv); break; case 3: if (adgold->adgold_38x_state) { @@ -275,7 +275,7 @@ adgold_write(uint16_t addr, uint8_t val, void *p) break; } } else - opl3_write(addr, val, &adgold->opl); + adgold->opl.write(addr, val, adgold->opl.priv); break; case 4: case 6: @@ -501,14 +501,14 @@ adgold_read(uint16_t addr, void *p) switch (addr & 7) { case 0: case 1: - temp = opl3_read(addr, &adgold->opl); + temp = adgold->opl.read(addr, adgold->opl.priv); break; case 2: if (adgold->adgold_38x_state) /*Read from control chip*/ temp = adgold->adgold_status; else - temp = opl3_read(addr, &adgold->opl); + temp = adgold->opl.read(addr, adgold->opl.priv); break; case 3: @@ -527,7 +527,7 @@ adgold_read(uint16_t addr, void *p) temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; } } else - temp = opl3_read(addr, &adgold->opl); + temp = adgold->opl.read(addr, adgold->opl.priv); break; case 4: @@ -713,13 +713,13 @@ adgold_get_buffer(int32_t *buffer, int len, void *p) int c; - opl3_update(&adgold->opl); + int32_t *opl_buf = adgold->opl.update(adgold->opl.priv); adgold_update(adgold); for (c = 0; c < len * 2; c += 2) { - adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c] = ((opl_buf[c] * adgold->fm_vol_l) >> 7) / 2; adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; - adgold_buffer[c + 1] = ((adgold->opl.buffer[c + 1] * adgold->fm_vol_r) >> 7) / 2; + adgold_buffer[c + 1] = ((opl_buf[c + 1] * adgold->fm_vol_r) >> 7) / 2; adgold_buffer[c + 1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; } @@ -808,7 +808,7 @@ adgold_get_buffer(int32_t *buffer, int len, void *p) buffer[c + 1] += temp; } - adgold->opl.pos = 0; + adgold->opl.reset_buffer(adgold->opl.priv); adgold->pos = 0; free(adgold_buffer); @@ -881,7 +881,7 @@ adgold_init(const device_t *info) adgold->gameport_enabled = device_get_config_int("gameport"); - opl3_init(&adgold->opl); + fm_driver_get(FM_YMF262, &adgold->opl); if (adgold->surround_enabled) ym7128_init(&adgold->ym7128); diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index a72e1dbe5..890734450 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1149,7 +1149,7 @@ azt_init(const device_t *info) azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[i]; if (azt2316a->sb->opl_enabled) - opl3_init(&azt2316a->sb->opl); + fm_driver_get(FM_YMF262, &azt2316a->sb->opl); sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); @@ -1158,9 +1158,9 @@ azt_init(const device_t *info) sb_ct1345_mixer_reset(azt2316a->sb); /* DSP I/O handler is activated in sb_dsp_setaddr */ if (azt2316a->sb->opl_enabled) { - io_sethandler(azt2316a->cur_addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); - io_sethandler(azt2316a->cur_addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(azt2316a->cur_addr + 0, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); + io_sethandler(azt2316a->cur_addr + 8, 0x0002, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); + io_sethandler(0x0388, 0x0004, azt2316a->sb->opl.read, NULL, NULL, azt2316a->sb->opl.write, NULL, NULL, azt2316a->sb->opl.priv); } io_sethandler(azt2316a->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, azt2316a->sb); diff --git a/src/sound/snd_cmi8x38.c b/src/sound/snd_cmi8x38.c index 4ce76508e..d4a54880b 100644 --- a/src/sound/snd_cmi8x38.c +++ b/src/sound/snd_cmi8x38.c @@ -473,10 +473,10 @@ static void cmi8x38_remap_sb(cmi8x38_t *dev) { if (dev->sb_base) { - io_removehandler(dev->sb_base, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &dev->sb->opl); - io_removehandler(dev->sb_base + 8, 0x0002, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 8, 0x0002, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); io_removehandler(dev->sb_base + 4, 0x0002, cmi8x38_sb_mixer_read, NULL, NULL, cmi8x38_sb_mixer_write, NULL, NULL, dev); @@ -493,10 +493,10 @@ cmi8x38_remap_sb(cmi8x38_t *dev) cmi8x38_log("CMI8x38: remap_sb(%04X)\n", dev->sb_base); if (dev->sb_base) { - io_sethandler(dev->sb_base, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &dev->sb->opl); - io_sethandler(dev->sb_base + 8, 0x0002, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 8, 0x0002, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); io_sethandler(dev->sb_base + 4, 0x0002, cmi8x38_sb_mixer_read, NULL, NULL, cmi8x38_sb_mixer_write, NULL, NULL, dev); @@ -508,8 +508,8 @@ static void cmi8x38_remap_opl(cmi8x38_t *dev) { if (dev->opl_base) { - io_removehandler(dev->opl_base, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->opl_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); } dev->opl_base = (dev->type == CMEDIA_CMI8338) ? 0x388 : opl_ports_cmi8738[dev->io_regs[0x17] & 0x03]; @@ -520,8 +520,8 @@ cmi8x38_remap_opl(cmi8x38_t *dev) cmi8x38_log("CMI8x38: remap_opl(%04X)\n", dev->opl_base); if (dev->opl_base) { - io_sethandler(dev->opl_base, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->opl_base, 0x0004, dev->sb->opl.read, NULL, NULL, + dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); } } @@ -593,7 +593,7 @@ cmi8x38_read(uint16_t addr, void *priv) if (dev->type == CMEDIA_CMI8338) goto io_reg; else - ret = opl3_read(addr, &dev->sb->opl); + ret = dev->sb->opl.read(addr, dev->sb->opl.priv); break; case 0x80: @@ -872,7 +872,7 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv) case 0x50 ... 0x5f: if (dev->type != CMEDIA_CMI8338) - opl3_write(addr, val, &dev->sb->opl); + dev->sb->opl.write(addr, val, dev->sb->opl.priv); return; case 0x92: diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 1f366e373..31f4e8e6c 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -505,18 +505,19 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) { cs423x_t *dev = (cs423x_t *) priv; int c, opl_wss = dev->opl_wss; + int32_t *opl_buf = NULL; /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ ad1848_update(&dev->ad1848); if (opl_wss) - opl3_update(&dev->sb->opl); + opl_buf = dev->sb->opl.update(dev->sb->opl.priv); /* Don't output anything if the analog section is powered down. */ if (!(dev->indirect_regs[2] & 0xa4)) { for (c = 0; c < len * 2; c += 2) { if (opl_wss) { - buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; - buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; + buffer[c] += (opl_buf[c] * dev->ad1848.fm_vol_l) >> 16; + buffer[c + 1] += (opl_buf[c + 1] * dev->ad1848.fm_vol_r) >> 16; } buffer[c] += dev->ad1848.buffer[c] / 2; @@ -526,7 +527,7 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) dev->ad1848.pos = 0; if (opl_wss) - dev->sb->opl.pos = 0; + dev->sb->opl.reset_buffer(dev->sb->opl.priv); } static void @@ -590,14 +591,14 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv } if (dev->opl_base) { - io_removehandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->opl_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); dev->opl_base = 0; } if (dev->sb_base) { sb_dsp_setaddr(&dev->sb->dsp, 0); - io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); - io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_removehandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); io_removehandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); dev->sb_base = 0; @@ -618,14 +619,14 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv if (config->io[1].base != ISAPNP_IO_DISABLED) { dev->opl_base = config->io[1].base; - io_sethandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->opl_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); } if (config->io[2].base != ISAPNP_IO_DISABLED) { dev->sb_base = config->io[2].base; sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); - io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); - io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base, 4, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); + io_sethandler(dev->sb_base + 8, 2, dev->sb->opl.read, NULL, NULL, dev->sb->opl.write, NULL, NULL, dev->sb->opl.priv); io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); io_sethandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); } diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 6cba7b3e8..cce75bf39 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -28,285 +28,44 @@ #include "cpu.h" #include <86box/86box.h> +#include <86box/device.h> #include <86box/io.h> -#include <86box/timer.h> #include <86box/sound.h> #include <86box/snd_opl.h> -#include <86box/snd_opl_nuked.h> -enum { - FLAG_CYCLES = 0x02, - FLAG_OPL3 = 0x01 -}; - -enum { - STAT_TMR_OVER = 0x60, - STAT_TMR1_OVER = 0x40, - STAT_TMR2_OVER = 0x20, - STAT_TMR_ANY = 0x80 -}; - -enum { - CTRL_RESET = 0x80, - CTRL_TMR_MASK = 0x60, - CTRL_TMR1_MASK = 0x40, - CTRL_TMR2_MASK = 0x20, - CTRL_TMR2_START = 0x02, - CTRL_TMR1_START = 0x01 -}; - -#ifdef ENABLE_OPL_LOG -int opl_do_log = ENABLE_OPL_LOG; - -static void -opl_log(const char *fmt, ...) -{ - 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_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) { - dev->status |= ((STAT_TMR1_OVER >> tmr) & ~dev->timer_ctrl); - dev->timer_cur_count[tmr] = dev->timer_count[tmr]; - - opl_log("Count wrapped around to zero, reloading timer %i (%02X), status = %02X...\n", tmr, (STAT_TMR1_OVER >> tmr), dev->status); - } - - 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]; - if (dev->flags & FLAG_OPL3) - timer_tick(dev, tmr); /* Per the YMF 262 datasheet, OPL3 starts counting immediately, unlike OPL2. */ - else - timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); - } else { - opl_log("Timer %i stopped\n", tmr); - if (tmr == 1) { - dev->status &= ~STAT_TMR2_OVER; - } else - dev->status &= ~STAT_TMR1_OVER; - } -} - -static void -timer_1(void *priv) -{ - opl_t *dev = (opl_t *) priv; - - timer_tick(dev, 0); -} - -static void -timer_2(void *priv) -{ - opl_t *dev = (opl_t *) priv; - - timer_tick(dev, 1); -} - -static uint8_t -opl_read(opl_t *dev, uint16_t port) -{ - uint8_t ret = 0xff; - - if ((port & 0x0003) == 0x0000) { - ret = dev->status; - if (dev->status & STAT_TMR_OVER) - ret |= STAT_TMR_ANY; - } - - opl_log("OPL statret = %02x, status = %02x\n", ret, dev->status); - - return ret; -} - -static void -opl_write(opl_t *dev, uint16_t port, uint8_t val) -{ - 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_RESET) { - opl_log("Resetting timer status...\n"); - dev->status &= ~STAT_TMR_OVER; - } else { - dev->timer_ctrl = val; - timer_control(dev, 0, val & CTRL_TMR1_START); - timer_control(dev, 1, val & CTRL_TMR2_START); - opl_log("Status mask now %02X (val = %02X)\n", (val & ~CTRL_TMR_MASK) & CTRL_TMR_MASK, val); - } - break; - } - } else { - dev->port = nuked_write_addr(dev->opl, port, val) & 0x01ff; - - if (!(dev->flags & FLAG_OPL3)) - dev->port &= 0x00ff; - } -} - -void -opl_set_do_cycles(opl_t *dev, int8_t do_cycles) -{ - if (do_cycles) - dev->flags |= FLAG_CYCLES; - else - dev->flags &= ~FLAG_CYCLES; -} - -static void -opl_init(opl_t *dev, int is_opl3) -{ - memset(dev, 0x00, sizeof(opl_t)); - - dev->flags = FLAG_CYCLES; - if (is_opl3) - dev->flags |= FLAG_OPL3; - else - dev->status = 0x06; - - /* Create a NukedOPL object. */ - dev->opl = nuked_init(48000); - - timer_add(&dev->timers[0], timer_1, dev, 0); - timer_add(&dev->timers[1], timer_2, dev, 0); -} - -void -opl_close(opl_t *dev) -{ - /* Release the NukedOPL object. */ - if (dev->opl) { - nuked_close(dev->opl); - dev->opl = NULL; - } -} +static uint32_t fm_dev_inst[FM_DRV_MAX][FM_MAX]; uint8_t -opl2_read(uint16_t port, void *priv) -{ - opl_t *dev = (opl_t *) priv; +fm_driver_get(int chip_id, fm_drv_t *drv) { + switch (chip_id) { + case FM_YM3812: + if (fm_driver == FM_DRV_NUKED) { + *drv = nuked_opl_drv; + drv->priv = device_add_inst(&ym3812_nuked_device, fm_dev_inst[fm_driver][chip_id]++); + } else { + *drv = ymfm_drv; + drv->priv = device_add_inst(&ym3812_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + } + break; - if (dev->flags & FLAG_CYCLES) - cycles -= ((int) (isa_timing * 8)); + case FM_YMF262: + if (fm_driver == FM_DRV_NUKED) { + *drv = nuked_opl_drv; + drv->priv = device_add_inst(&ymf262_nuked_device, fm_dev_inst[fm_driver][chip_id]++); + } else { + *drv = ymfm_drv; + drv->priv = device_add_inst(&ymf262_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + } + break; - opl2_update(dev); - opl_log("OPL2 port read = %04x\n", port); + case FM_YMF289B: + *drv = ymfm_drv; + drv->priv = device_add_inst(&ymf289b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++); + break; - return (opl_read(dev, port)); -} - -void -opl2_write(uint16_t port, uint8_t val, void *priv) -{ - opl_t *dev = (opl_t *) priv; - - opl2_update(dev); - - opl_log("OPL2 port write = %04x\n", port); - opl_write(dev, port, val); -} - -void -opl2_init(opl_t *dev) -{ - opl_init(dev, 0); -} - -void -opl2_update(opl_t *dev) -{ - if (dev->pos >= sound_pos_global) { - return; + default: + return 0; } - nuked_generate_stream(dev->opl, - &dev->buffer[dev->pos * 2], - sound_pos_global - dev->pos); - - for (; dev->pos < sound_pos_global; dev->pos++) { - dev->buffer[dev->pos * 2] /= 2; - dev->buffer[(dev->pos * 2) + 1] = dev->buffer[dev->pos * 2]; - } -} - -uint8_t -opl3_read(uint16_t port, void *priv) -{ - opl_t *dev = (opl_t *) priv; - - if (dev->flags & FLAG_CYCLES) - cycles -= ((int) (isa_timing * 8)); - - opl3_update(dev); - - return (opl_read(dev, port)); -} - -void -opl3_write(uint16_t port, uint8_t val, void *priv) -{ - opl_t *dev = (opl_t *) priv; - - opl3_update(dev); - - opl_write(dev, port, val); -} - -void -opl3_init(opl_t *dev) -{ - opl_init(dev, 1); -} - -/* API to sound interface. */ -void -opl3_update(opl_t *dev) -{ - if (dev->pos >= sound_pos_global) - return; - - nuked_generate_stream(dev->opl, - &dev->buffer[dev->pos * 2], - sound_pos_global - dev->pos); - - for (; dev->pos < sound_pos_global; dev->pos++) { - dev->buffer[dev->pos * 2] /= 2; - dev->buffer[(dev->pos * 2) + 1] /= 2; - } -} + return 1; +}; diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c index 347316e4e..8e1a7e774 100644 --- a/src/sound/snd_opl_nuked.c +++ b/src/sound/snd_opl_nuked.c @@ -46,6 +46,8 @@ #include <86box/snd_opl_nuked.h> #include <86box/sound.h> #include <86box/timer.h> +#include <86box/device.h> +#include <86box/snd_opl.h> #define WRBUF_SIZE 1024 #define WRBUF_DELAY 1 @@ -169,6 +171,56 @@ typedef struct chip { wrbuf_t wrbuf[WRBUF_SIZE]; } nuked_t; +typedef struct { + nuked_t opl; + int8_t flags, pad; + + uint16_t port; + uint8_t status, timer_ctrl; + uint16_t timer_count[2], + timer_cur_count[2]; + + pc_timer_t timers[2]; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; +} nuked_drv_t; + +enum { + FLAG_CYCLES = 0x02, + FLAG_OPL3 = 0x01 +}; + +enum { + STAT_TMR_OVER = 0x60, + STAT_TMR1_OVER = 0x40, + STAT_TMR2_OVER = 0x20, + STAT_TMR_ANY = 0x80 +}; + +enum { + CTRL_RESET = 0x80, + CTRL_TMR_MASK = 0x60, + CTRL_TMR1_MASK = 0x40, + CTRL_TMR2_MASK = 0x20, + CTRL_TMR2_START = 0x02, + CTRL_TMR1_START = 0x01 +}; + +#ifdef ENABLE_OPL_LOG +static void +nuked_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +} +#else +# define nuked_log(fmt, ...) +#endif + // logsin table static const uint16_t logsinrom[256] = { 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, @@ -1270,10 +1322,8 @@ nuked_generate(void *priv, int32_t *bufp) } void -nuked_generate_resampled(void *priv, int32_t *bufp) +nuked_generate_resampled(nuked_t *dev, int32_t *bufp) { - nuked_t *dev = (nuked_t *) priv; - while (dev->samplecnt >= dev->rateratio) { dev->oldsamples[0] = dev->samples[0]; dev->oldsamples[1] = dev->samples[1]; @@ -1292,9 +1342,8 @@ nuked_generate_resampled(void *priv, int32_t *bufp) } void -nuked_generate_stream(void *priv, int32_t *sndptr, uint32_t num) +nuked_generate_stream(nuked_t *dev, int32_t *sndptr, uint32_t num) { - nuked_t *dev = (nuked_t *) priv; uint32_t i; for (i = 0; i < num; i++) { @@ -1303,13 +1352,11 @@ nuked_generate_stream(void *priv, int32_t *sndptr, uint32_t num) } } -void * -nuked_init(uint32_t samplerate) +void +nuked_init(nuked_t *dev, uint32_t samplerate) { - nuked_t *dev; uint8_t i; - dev = (nuked_t *) malloc(sizeof(nuked_t)); memset(dev, 0x00, sizeof(nuked_t)); for (i = 0; i < 36; i++) { @@ -1350,14 +1397,222 @@ nuked_init(uint32_t samplerate) dev->rateratio = (samplerate << RSM_FRAC) / 49716; dev->tremoloshift = 4; dev->vibshift = 1; - - return (dev); } -void -nuked_close(void *priv) +static void +nuked_timer_tick(nuked_drv_t *dev, int tmr) { - nuked_t *dev = (nuked_t *) priv; + dev->timer_cur_count[tmr] = (dev->timer_cur_count[tmr] + 1) & 0xff; + nuked_log("Ticking timer %i, count now %02X...\n", tmr, dev->timer_cur_count[tmr]); + + if (dev->timer_cur_count[tmr] == 0x00) { + dev->status |= ((STAT_TMR1_OVER >> tmr) & ~dev->timer_ctrl); + dev->timer_cur_count[tmr] = dev->timer_count[tmr]; + + nuked_log("Count wrapped around to zero, reloading timer %i (%02X), status = %02X...\n", tmr, (STAT_TMR1_OVER >> tmr), dev->status); + } + + timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); +} + +static void +nuked_timer_control(nuked_drv_t *dev, int tmr, int start) +{ + timer_on_auto(&dev->timers[tmr], 0.0); + + if (start) { + nuked_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]; + if (dev->flags & FLAG_OPL3) + nuked_timer_tick(dev, tmr); /* Per the YMF 262 datasheet, OPL3 starts counting immediately, unlike OPL2. */ + else + timer_on_auto(&dev->timers[tmr], (tmr == 1) ? 320.0 : 80.0); + } else { + nuked_log("Timer %i stopped\n", tmr); + if (tmr == 1) { + dev->status &= ~STAT_TMR2_OVER; + } else + dev->status &= ~STAT_TMR1_OVER; + } +} + +static void +nuked_timer_1(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + nuked_timer_tick(dev, 0); +} + +static void +nuked_timer_2(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + nuked_timer_tick(dev, 1); +} + +static void +nuked_drv_set_do_cycles(void *priv, int8_t do_cycles) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + + if (do_cycles) + dev->flags |= FLAG_CYCLES; + else + dev->flags &= ~FLAG_CYCLES; +} + +static void * +nuked_drv_init(const device_t *info) +{ + nuked_drv_t *dev = (nuked_drv_t *) calloc(1, sizeof(nuked_drv_t)); + dev->flags = FLAG_CYCLES; + if (info->local == FM_YMF262) + dev->flags |= FLAG_OPL3; + else + dev->status = 0x06; + + /* Initialize the NukedOPL object. */ + nuked_init(&dev->opl, 48000); + + timer_add(&dev->timers[0], nuked_timer_1, dev, 0); + timer_add(&dev->timers[1], nuked_timer_2, dev, 0); + + return dev; +} + +static void +nuked_drv_close(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; free(dev); } + +static int32_t * +nuked_drv_update(void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + + if (dev->pos >= sound_pos_global) + return dev->buffer; + + nuked_generate_stream(&dev->opl, + &dev->buffer[dev->pos * 2], + sound_pos_global - dev->pos); + + for (; dev->pos < sound_pos_global; dev->pos++) { + dev->buffer[dev->pos * 2] /= 2; + dev->buffer[(dev->pos * 2) + 1] /= 2; + } + + return dev->buffer; +} + +static uint8_t +nuked_drv_read(uint16_t port, void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *) priv; + + if (dev->flags & FLAG_CYCLES) + cycles -= ((int) (isa_timing * 8)); + + nuked_drv_update(dev); + + uint8_t ret = 0xff; + + if ((port & 0x0003) == 0x0000) { + ret = dev->status; + if (dev->status & STAT_TMR_OVER) + ret |= STAT_TMR_ANY; + } + + nuked_log("OPL statret = %02x, status = %02x\n", ret, dev->status); + + return ret; +} + +static void +nuked_drv_write(uint16_t port, uint8_t val, void *priv) +{ + nuked_drv_t *dev = (nuked_drv_t *)priv; + nuked_drv_update(dev); + + 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; + nuked_log("Timer 0 count now: %i\n", dev->timer_count[0]); + break; + + case 0x03: /* Timer 2 */ + dev->timer_count[1] = val; + nuked_log("Timer 1 count now: %i\n", dev->timer_count[1]); + break; + + case 0x04: /* Timer control */ + if (val & CTRL_RESET) { + nuked_log("Resetting timer status...\n"); + dev->status &= ~STAT_TMR_OVER; + } else { + dev->timer_ctrl = val; + nuked_timer_control(dev, 0, val & CTRL_TMR1_START); + nuked_timer_control(dev, 1, val & CTRL_TMR2_START); + nuked_log("Status mask now %02X (val = %02X)\n", (val & ~CTRL_TMR_MASK) & CTRL_TMR_MASK, val); + } + break; + } + } else { + dev->port = nuked_write_addr(&dev->opl, port, val) & 0x01ff; + + if (!(dev->flags & FLAG_OPL3)) + dev->port &= 0x00ff; + } +} + +static void +nuked_drv_reset_buffer(void *priv) { + nuked_drv_t *dev = (nuked_drv_t *)priv; + + dev->pos = 0; +} + +const device_t ym3812_nuked_device = { + .name = "Yamaha YM3812 OPL2 (NUKED)", + .internal_name = "ym3812_nuked", + .flags = 0, + .local = FM_YM3812, + .init = nuked_drv_init, + .close = nuked_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ymf262_nuked_device = { + .name = "Yamaha YMF262 OPL3 (NUKED)", + .internal_name = "ymf262_nuked", + .flags = 0, + .local = FM_YMF262, + .init = nuked_drv_init, + .close = nuked_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const fm_drv_t nuked_opl_drv = { + &nuked_drv_read, + &nuked_drv_write, + &nuked_drv_update, + &nuked_drv_reset_buffer, + &nuked_drv_set_do_cycles, + NULL, +}; \ No newline at end of file diff --git a/src/sound/snd_opl_ymfm.cpp b/src/sound/snd_opl_ymfm.cpp new file mode 100644 index 000000000..f82d64822 --- /dev/null +++ b/src/sound/snd_opl_ymfm.cpp @@ -0,0 +1,387 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Interface to the YMFM emulator. + * + * + * Authors: Adrien Moulin, + * + * Copyright 2022 Adrien Moulin. + */ + +#include +#include +#include +#include +#include "ymfm/ymfm_opl.h" + +extern "C" { +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/sound.h> +#include <86box/snd_opl.h> +} + +#define RSM_FRAC 10 + +enum { + FLAG_CYCLES = (1 << 0) +}; + +class YMFMChipBase +{ +public: + YMFMChipBase(uint32_t clock, fm_type type, uint32_t samplerate) + : m_buf_pos(0), m_flags(0), m_type(type) + { + memset(m_buffer, 0, sizeof(m_buffer)); + } + + virtual ~YMFMChipBase() + { + } + + fm_type type() const { return m_type; } + int8_t flags() const { return m_flags; } + void set_do_cycles(int8_t do_cycles) { do_cycles ? m_flags |= FLAG_CYCLES : m_flags &= ~FLAG_CYCLES; } + int32_t *buffer() const { return (int32_t *)m_buffer; } + void reset_buffer() { m_buf_pos = 0; } + + virtual uint32_t sample_rate() const = 0; + + virtual void write(uint16_t addr, uint8_t data) = 0; + virtual void generate(int32_t *data, uint32_t num_samples) = 0; + virtual void generate_resampled(int32_t *data, uint32_t num_samples) = 0; + virtual int32_t * update() = 0; + virtual uint8_t read(uint16_t addr) = 0; + +protected: + int32_t m_buffer[SOUNDBUFLEN * 2]; + uint32_t m_buf_pos; + int8_t m_flags; + fm_type m_type; +}; + +template +class YMFMChip : public YMFMChipBase, public ymfm::ymfm_interface +{ +public: + YMFMChip(uint32_t clock, fm_type type, uint32_t samplerate) + : YMFMChipBase(clock, type, samplerate) + , m_chip(*this) + , m_clock(clock) + , m_samplecnt(0) + { + memset(m_samples, 0, sizeof(m_samples)); + memset(m_oldsamples, 0, sizeof(m_oldsamples)); + m_rateratio = (samplerate << RSM_FRAC) / m_chip.sample_rate(m_clock); + m_clock_us = 1000000 / (double) m_clock; + + timer_add(&m_timers[0], YMFMChip::timer1, this, 0); + timer_add(&m_timers[1], YMFMChip::timer2, this, 0); + } + + virtual uint32_t sample_rate() const override + { + return m_chip.sample_rate(m_clock); + } + + virtual void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) override + { + if (tnum > 1) + return; + + pc_timer_t *timer = &m_timers[tnum]; + if (duration_in_clocks < 0) { + timer_stop(timer); + } else { + double period = m_clock_us * duration_in_clocks; + timer_on_auto(timer, period); + } + } + + virtual void generate(int32_t *data, uint32_t num_samples) override + { + for (uint32_t i = 0; i < num_samples; i++) { + m_chip.generate(&m_output); + if (ChipType::OUTPUTS == 1) { + *data++ = m_output.data[0]; + *data++ = m_output.data[0]; + } else { + *data++ = m_output.data[0]; + *data++ = m_output.data[1 % ChipType::OUTPUTS]; + } + } + } + +virtual void generate_resampled(int32_t *data, uint32_t num_samples) override + { + for (uint32_t i = 0; i < num_samples; i++) { + while (m_samplecnt >= m_rateratio) { + m_oldsamples[0] = m_samples[0]; + m_oldsamples[1] = m_samples[1]; + m_chip.generate(&m_output); + if (ChipType::OUTPUTS == 1) { + m_samples[0] = m_output.data[0]; + m_samples[1] = m_output.data[0]; + } else { + m_samples[0] = m_output.data[0]; + m_samples[1] = m_output.data[1 % ChipType::OUTPUTS]; + } + m_samplecnt -= m_rateratio; + } + + *data++ = ((int32_t) ((m_oldsamples[0] * (m_rateratio - m_samplecnt) + + m_samples[0] * m_samplecnt) + / m_rateratio)); + *data++ = ((int32_t) ((m_oldsamples[1] * (m_rateratio - m_samplecnt) + + m_samples[1] * m_samplecnt) + / m_rateratio)); + + m_samplecnt += 1 << RSM_FRAC; + } + } + + + /*virtual void generate_resampled(int32_t *data, uint32_t num_samples) override + { + for (uint32_t i = 0; i < num_samples; i++) { + while (m_samplecnt >= m_rateratio) { + m_oldsamples[0] = m_samples[0]; + m_oldsamples[1] = m_samples[1]; + generate(m_samples, 1); + m_samplecnt -= m_rateratio; + } + + *data++ = ((int32_t) ((m_oldsamples[0] * (m_rateratio - m_samplecnt) + + m_samples[0] * m_samplecnt) + / m_rateratio)) / 2; + *data++ = ((int32_t) ((m_oldsamples[1] * (m_rateratio - m_samplecnt) + + m_samples[1] * m_samplecnt) + / m_rateratio)) / 2; + + m_samplecnt += 1 << RSM_FRAC; + } + }*/ + + virtual int32_t *update() override + { + if (m_buf_pos >= sound_pos_global) + return m_buffer; + + generate_resampled(&m_buffer[m_buf_pos * 2], sound_pos_global - m_buf_pos); + + for (; m_buf_pos < sound_pos_global; m_buf_pos++) { + m_buffer[m_buf_pos * 2] /= 2; + m_buffer[(m_buf_pos * 2) + 1] /= 2; + } + + return m_buffer; + } + + virtual void write(uint16_t addr, uint8_t data) override + { + m_chip.write(addr, data); + } + + virtual uint8_t read(uint16_t addr) override + { + return m_chip.read(addr); + } + + static void timer1(void *priv) + { + YMFMChip *drv = (YMFMChip *) priv; + drv->m_engine->engine_timer_expired(0); + } + + static void timer2(void *priv) + { + YMFMChip *drv = (YMFMChip *) priv; + drv->m_engine->engine_timer_expired(1); + } + +private: + ChipType m_chip; + uint32_t m_clock; + double m_clock_us; + typename ChipType::output_data m_output; + pc_timer_t m_timers[2]; + + // Resampling + int32_t m_rateratio; + int32_t m_samplecnt; + int32_t m_oldsamples[2]; + int32_t m_samples[2]; +}; + +extern "C" +{ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include "cpu.h" +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/snd_opl.h> + +#ifdef ENABLE_OPL_LOG +static int opl_do_log = ENABLE_OPL_LOG; + +static void +opl_log(const char *fmt, ...) +{ + 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 * +ymfm_drv_init(const device_t *info) +{ + YMFMChipBase *fm; + + switch (info->local) { + case FM_YM3812: + default: + fm = (YMFMChipBase *) new YMFMChip(3579545, FM_YM3812, 48000); + break; + + case FM_YMF262: + fm = (YMFMChipBase *) new YMFMChip(14318181, FM_YMF262, 48000); + break; + + case FM_YMF289B: + fm = (YMFMChipBase *) new YMFMChip(33868800, FM_YMF289B, 48000); + break; + } + + fm->set_do_cycles(1); + + return fm; +} + +static void +ymfm_drv_close(void *priv) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + + if (drv != NULL) + delete(drv); +} + +static uint8_t +ymfm_drv_read(uint16_t port, void *priv) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + + if (drv->flags() & FLAG_CYCLES) { + cycles -= ((int) (isa_timing * 8)); + } + + uint8_t ret = drv->read(port); + drv->update(); + + opl_log("YMFM read port %04x, status = %02x\n", port, ret); + return ret; +} + +static void +ymfm_drv_write(uint16_t port, uint8_t val, void *priv) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + opl_log("YMFM write port %04x value = %02x\n", port, val); + drv->write(port, val); + drv->update(); +} + +static int32_t * +ymfm_drv_update(void *priv) { + YMFMChipBase *drv = (YMFMChipBase *) priv; + + return drv->update(); +} + +static void +ymfm_drv_reset_buffer(void *priv) { + YMFMChipBase *drv = (YMFMChipBase *) priv; + + drv->reset_buffer(); +} + +static void +ymfm_drv_set_do_cycles(void *priv, int8_t do_cycles) +{ + YMFMChipBase *drv = (YMFMChipBase *) priv; + drv->set_do_cycles(do_cycles); +} + +const device_t ym3812_ymfm_device = { + .name = "Yamaha YM3812 OPL2 (YMFM)", + .internal_name = "ym3812_ymfm", + .flags = 0, + .local = FM_YM3812, + .init = ymfm_drv_init, + .close = ymfm_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ymf262_ymfm_device = { + .name = "Yamaha YMF262 OPL3 (YMFM)", + .internal_name = "ymf262_ymfm", + .flags = 0, + .local = FM_YMF262, + .init = ymfm_drv_init, + .close = ymfm_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ymf289b_ymfm_device = { + .name = "Yamaha YMF289B OPL3-L (YMFM)", + .internal_name = "ymf289b_ymfm", + .flags = 0, + .local = FM_YMF289B, + .init = ymfm_drv_init, + .close = ymfm_drv_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const fm_drv_t ymfm_drv { + &ymfm_drv_read, + &ymfm_drv_write, + &ymfm_drv_update, + &ymfm_drv_reset_buffer, + &ymfm_drv_set_do_cycles, + NULL, +}; + +} diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 33bd51b34..1662598c9 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -137,7 +137,7 @@ typedef struct pas16_t { int64_t enable[3]; } pit; - opl_t opl; + fm_drv_t opl; sb_dsp_t dsp; int16_t pcm_buffer[2][SOUNDBUFLEN]; @@ -201,7 +201,7 @@ pas16_in(uint16_t port, void *p) case 0x389: case 0x38a: case 0x38b: - temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl); + temp = pas16->opl.read((port - pas16->base) + 0x388, pas16->opl.priv); break; case 0xb88: @@ -301,7 +301,7 @@ pas16_out(uint16_t port, uint8_t val, void *p) case 0x389: case 0x38a: case 0x38b: - opl3_write((port - pas16->base) + 0x388, val, &pas16->opl); + pas16->opl.write((port - pas16->base) + 0x388, val, pas16->opl.priv); break; case 0xb88: @@ -702,17 +702,17 @@ pas16_get_buffer(int32_t *buffer, int len, void *p) pas16_t *pas16 = (pas16_t *) p; int c; - opl3_update(&pas16->opl); + int32_t *opl_buf = pas16->opl.update(pas16->opl.priv); sb_dsp_update(&pas16->dsp); pas16_update(pas16); for (c = 0; c < len * 2; c++) { - buffer[c] += pas16->opl.buffer[c]; + buffer[c] += opl_buf[c]; buffer[c] += (int16_t) (sb_iir(0, c & 1, (double) pas16->dsp.buffer[c]) / 1.3) / 2; buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); } pas16->pos = 0; - pas16->opl.pos = 0; + pas16->opl.reset_buffer(pas16->opl.priv); pas16->dsp.pos = 0; } @@ -722,7 +722,7 @@ pas16_init(const device_t *info) pas16_t *pas16 = malloc(sizeof(pas16_t)); memset(pas16, 0, sizeof(pas16_t)); - opl3_init(&pas16->opl); + fm_driver_get(FM_YMF262, &pas16->opl); sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16); io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index aaafd11fa..75c59e11e 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -183,9 +183,10 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *p) sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; int c; double out_mono = 0.0, out_l = 0.0, out_r = 0.0; + int32_t *opl_buf = NULL; if (sb->opl_enabled) - opl2_update(&sb->opl); + opl_buf = sb->opl.update(sb->opl.priv); sb_dsp_update(&sb->dsp); @@ -198,7 +199,7 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *p) out_r = 0.0; if (sb->opl_enabled) - out_mono = ((double) sb->opl.buffer[c]) * 0.7171630859375; + out_mono = ((double) opl_buf[c]) * 0.7171630859375; if (sb->cms_enabled) { out_l += sb->cms.buffer[c]; @@ -234,7 +235,7 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *p) sb->pos = 0; if (sb->opl_enabled) - sb->opl.pos = 0; + sb->opl.reset_buffer(sb->opl.priv); sb->dsp.pos = 0; @@ -265,13 +266,14 @@ sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; int c; double out_l = 0.0, out_r = 0.0; + int32_t *opl_buf, *opl2_buf; if (sb->opl_enabled) { if (sb->dsp.sb_type == SBPRO) { - opl2_update(&sb->opl); - opl2_update(&sb->opl2); + opl_buf = sb->opl.update(sb->opl.priv); + opl2_buf = sb->opl2.update(sb->opl2.priv); } else - opl3_update(&sb->opl); + opl_buf = sb->opl.update(sb->opl.priv); } sb_dsp_update(&sb->dsp); @@ -283,11 +285,11 @@ sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) if (sb->dsp.sb_type == SBPRO) { /* Two chips for LEFT and RIGHT channels. Each chip stores data into the LEFT channel only (no sample alternating.) */ - out_l = (((double) sb->opl.buffer[c]) * mixer->fm_l) * 0.7171630859375; - out_r = (((double) sb->opl2.buffer[c]) * mixer->fm_r) * 0.7171630859375; + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl2_buf[c]) * mixer->fm_r) * 0.7171630859375; } else { - out_l = (((double) sb->opl.buffer[c]) * mixer->fm_l) * 0.7171630859375; - out_r = (((double) sb->opl.buffer[c + 1]) * mixer->fm_r) * 0.7171630859375; + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl_buf[c + 1]) * mixer->fm_r) * 0.7171630859375; } } @@ -311,9 +313,9 @@ sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) sb->pos = 0; if (sb->opl_enabled) { - sb->opl.pos = 0; + sb->opl.reset_buffer(sb->opl.priv); if (sb->dsp.sb_type != SBPRO) - sb->opl2.pos = 0; + sb->opl2.reset_buffer(sb->opl2.priv); } sb->dsp.pos = 0; @@ -345,9 +347,10 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *p) int32_t in_l, in_r; double out_l = 0.0, out_r = 0.0; double bass_treble; + int32_t *opl_buf = NULL; if (sb->opl_enabled) - opl3_update(&sb->opl); + opl_buf = sb->opl.update(sb->opl.priv); if (sb->dsp.sb_type > SB16) emu8k_update(&sb->emu8k); @@ -361,8 +364,8 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *p) c_emu8k = ((((c / 2) * 44100) / 48000) * 2); if (sb->opl_enabled) { - out_l = ((double) sb->opl.buffer[c]) * mixer->fm_l * 0.7171630859375; - out_r = ((double) sb->opl.buffer[c + 1]) * mixer->fm_r * 0.7171630859375; + out_l = ((double) opl_buf[c]) * mixer->fm_l * 0.7171630859375; + out_r = ((double) opl_buf[c + 1]) * mixer->fm_r * 0.7171630859375; } if (sb->dsp.sb_type > SB16) { @@ -456,7 +459,7 @@ sb_get_buffer_sb16_awe32(int32_t *buffer, int len, void *p) sb->pos = 0; if (sb->opl_enabled) - sb->opl.pos = 0; + sb->opl.reset_buffer(sb->opl.priv); sb->dsp.pos = 0; @@ -1088,13 +1091,13 @@ sb_mcv_write(int port, uint8_t val, void *p) addr = sb_mcv_addr[sb->pos_regs[4] & 7]; if (sb->opl_enabled) { io_removehandler(addr + 8, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_removehandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, 0); @@ -1106,13 +1109,13 @@ sb_mcv_write(int port, uint8_t val, void *p) if (sb->opl_enabled) { io_sethandler(addr + 8, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, addr); @@ -1152,17 +1155,17 @@ sb_pro_mcv_write(int port, uint8_t val, void *p) addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; io_removehandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_removehandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_removehandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_removehandler(addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, @@ -1176,16 +1179,16 @@ sb_pro_mcv_write(int port, uint8_t val, void *p) addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; io_sethandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, sb->opl.priv); io_sethandler(addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, @@ -1208,13 +1211,13 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) switch (ld) { case 0: /* Audio */ io_removehandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_removehandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, @@ -1224,9 +1227,9 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) if (addr) { sb->opl_pnp_addr = 0; io_removehandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } sb_dsp_setaddr(&sb->dsp, 0); @@ -1240,13 +1243,13 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) addr = config->io[0].base; if (addr != ISAPNP_IO_DISABLED) { io_sethandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, @@ -1263,9 +1266,9 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) if (addr != ISAPNP_IO_DISABLED) { sb->opl_pnp_addr = addr; io_sethandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } val = config->irq[0].irq; @@ -1349,7 +1352,7 @@ sb_1_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl2_init(&sb->opl); + fm_driver_get(FM_YM3812, &sb->opl); sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); @@ -1358,13 +1361,13 @@ sb_1_init(const device_t *info) /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { io_sethandler(addr + 8, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } sb->cms_enabled = 1; @@ -1397,7 +1400,7 @@ sb_15_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl2_init(&sb->opl); + fm_driver_get(FM_YM3812, &sb->opl); sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); @@ -1406,13 +1409,13 @@ sb_15_init(const device_t *info) /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { io_sethandler(addr + 8, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } sb->cms_enabled = device_get_config_int("cms"); @@ -1445,7 +1448,7 @@ sb_mcv_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl2_init(&sb->opl); + fm_driver_get(FM_YM3812, &sb->opl); sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, 0); @@ -1490,7 +1493,7 @@ sb_2_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl2_init(&sb->opl); + fm_driver_get(FM_YM3812, &sb->opl); sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); @@ -1504,18 +1507,18 @@ sb_2_init(const device_t *info) if (sb->opl_enabled) { if (!sb->cms_enabled) { io_sethandler(addr, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.write); } io_sethandler(addr + 8, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.write); io_sethandler(0x0388, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.write); } if (sb->cms_enabled) { @@ -1550,8 +1553,8 @@ sb_pro_v1_opl_read(uint16_t port, void *priv) cycles -= ((int) (isa_timing * 8)); - (void) opl2_read(port, &sb->opl2); // read, but ignore - return (opl2_read(port, &sb->opl)); + (void) sb->opl2.read(port, sb->opl2.priv); // read, but ignore + return (sb->opl.read(port, sb->opl.priv)); } static void @@ -1559,8 +1562,8 @@ sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv) { sb_t *sb = (sb_t *) priv; - opl2_write(port, val, &sb->opl); - opl2_write(port, val, &sb->opl2); + sb->opl.write(port, val, sb->opl.priv); + sb->opl2.write(port, val, sb->opl2.priv); } static void * @@ -1578,10 +1581,10 @@ sb_pro_v1_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) { - opl2_init(&sb->opl); - opl_set_do_cycles(&sb->opl, 0); - opl2_init(&sb->opl2); - opl_set_do_cycles(&sb->opl2, 0); + fm_driver_get(FM_YM3812, &sb->opl); + sb->opl.set_do_cycles(sb->opl.priv, 0); + fm_driver_get(FM_YM3812, &sb->opl2); + sb->opl2.set_do_cycles(sb->opl2.priv, 0); } sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); @@ -1592,13 +1595,13 @@ sb_pro_v1_init(const device_t *info) /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { io_sethandler(addr, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 2, 0x0002, - opl2_read, NULL, NULL, - opl2_write, NULL, NULL, - &sb->opl2); + sb->opl2.read, NULL, NULL, + sb->opl2.write, NULL, NULL, + sb->opl2.priv); io_sethandler(addr + 8, 0x0002, sb_pro_v1_opl_read, NULL, NULL, sb_pro_v1_opl_write, NULL, NULL, @@ -1638,7 +1641,7 @@ sb_pro_v2_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); @@ -1648,17 +1651,17 @@ sb_pro_v2_init(const device_t *info) /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { io_sethandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } sb->mixer_enabled = 1; @@ -1687,7 +1690,7 @@ sb_pro_mcv_init(const device_t *info) memset(sb, 0, sizeof(sb_t)); sb->opl_enabled = 1; - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_ct1345_mixer_reset(sb); @@ -1713,7 +1716,7 @@ sb_pro_compat_init(const device_t *info) sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_ct1345_mixer_reset(sb); @@ -1740,7 +1743,7 @@ sb_16_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); @@ -1751,17 +1754,17 @@ sb_16_init(const device_t *info) if (sb->opl_enabled) { io_sethandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } sb->mixer_enabled = 1; @@ -1792,7 +1795,7 @@ sb_16_pnp_init(const device_t *info) memset(sb, 0x00, sizeof(sb_t)); sb->opl_enabled = 1; - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_ct1745_mixer_reset(sb); @@ -1835,7 +1838,7 @@ sb_16_compat_init(const device_t *info) sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_ct1745_mixer_reset(sb); @@ -1900,7 +1903,7 @@ sb_awe32_init(const device_t *info) sb->opl_enabled = device_get_config_int("opl"); if (sb->opl_enabled) - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, SBAWE32, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); @@ -1911,17 +1914,17 @@ sb_awe32_init(const device_t *info) if (sb->opl_enabled) { io_sethandler(addr, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(addr + 8, 0x0002, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); io_sethandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &sb->opl); + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); } sb->mixer_enabled = 1; @@ -1956,7 +1959,7 @@ sb_awe32_pnp_init(const device_t *info) memset(sb, 0x00, sizeof(sb_t)); sb->opl_enabled = 1; - opl3_init(&sb->opl); + fm_driver_get(FM_YMF262, &sb->opl); sb_dsp_init(&sb->dsp, ((info->local == 2) || (info->local == 3) || (info->local == 4)) ? SBAWE64 : SBAWE32, SB_SUBTYPE_DEFAULT, sb); sb_ct1745_mixer_reset(sb); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 8df4791c6..b4859e128 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -52,7 +52,7 @@ typedef struct wss_t { uint8_t config; ad1848_t ad1848; - opl_t opl; + fm_drv_t opl; int opl_enabled; uint8_t pos_regs[8]; @@ -81,14 +81,14 @@ wss_get_buffer(int32_t *buffer, int len, void *priv) wss_t *wss = (wss_t *) priv; int c; - opl3_update(&wss->opl); + int32_t *opl_buf = wss->opl.update(wss->opl.priv); ad1848_update(&wss->ad1848); for (c = 0; c < len * 2; c++) { - buffer[c] += wss->opl.buffer[c]; + buffer[c] += opl_buf[c]; buffer[c] += wss->ad1848.buffer[c] / 2; } - wss->opl.pos = 0; + wss->opl.reset_buffer(wss->opl.priv); wss->ad1848.pos = 0; } @@ -102,7 +102,7 @@ wss_init(const device_t *info) wss->opl_enabled = device_get_config_int("opl"); if (wss->opl_enabled) - opl3_init(&wss->opl); + fm_driver_get(FM_YMF262, &wss->opl); ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); @@ -111,9 +111,9 @@ wss_init(const device_t *info) if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &wss->opl); + wss->opl.read, NULL, NULL, + wss->opl.write, NULL, NULL, + wss->opl.priv); io_sethandler(addr, 0x0004, wss_read, NULL, NULL, @@ -150,9 +150,9 @@ ncr_audio_mca_write(int port, uint8_t val, void *priv) addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; io_removehandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &wss->opl); + wss->opl.read, NULL, NULL, + wss->opl.write, NULL, NULL, + wss->opl.priv); io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, @@ -169,9 +169,9 @@ ncr_audio_mca_write(int port, uint8_t val, void *priv) if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, - opl3_read, NULL, NULL, - opl3_write, NULL, NULL, - &wss->opl); + wss->opl.read, NULL, NULL, + wss->opl.write, NULL, NULL, + wss->opl.priv); io_sethandler(addr, 0x0004, wss_read, NULL, NULL, @@ -197,7 +197,7 @@ ncr_audio_init(const device_t *info) wss_t *wss = malloc(sizeof(wss_t)); memset(wss, 0, sizeof(wss_t)); - opl3_init(&wss->opl); + fm_driver_get(FM_YMF262, &wss->opl); ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); ad1848_setirq(&wss->ad1848, 7); diff --git a/src/sound/ymfm/CMakeLists.txt b/src/sound/ymfm/CMakeLists.txt index da02f8132..2041719ae 100644 --- a/src/sound/ymfm/CMakeLists.txt +++ b/src/sound/ymfm/CMakeLists.txt @@ -1 +1 @@ -add_library(ymfm STATIC ymfm_opl.cpp) \ No newline at end of file +add_library(ymfm STATIC ymfm_misc.cpp ymfm_opl.cpp ymfm_opm.cpp ymfm_opn.cpp ymfm_opq.cpp ymfm_opz.cpp ymfm_pcm.cpp ymfm_adpcm.cpp) \ No newline at end of file diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 8c29a24a1..75b847dde 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -241,7 +241,7 @@ VPATH := $(EXPATH) . $(CODEGEN) minitrace cpu \ sio sound \ sound/munt sound/munt/c_interface sound/munt/sha1 \ sound/munt/srchelper sound/munt/srchelper/srctools/src \ - sound/resid-fp \ + sound/resid-fp sound/ymfm \ scsi video network network/slirp win ifeq ($(X64), y) TOOL_PREFIX := x86_64-w64-mingw32- @@ -670,7 +670,9 @@ PRINTOBJ := png.o prt_cpmap.o \ prt_escp.o prt_text.o prt_ps.o SNDOBJ := sound.o \ - snd_opl.o snd_opl_nuked.o \ + snd_opl.o snd_opl_nuked.o snd_opl_ymfm.o \ + ymfm_adpcm.o ymfm_misc.o ymfm_opl.o ymfm_opm.o \ + ymfm_opn.o ymfm_opq.o ymfm_opz.o ymfm_pcm.o ymfm_ssg.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ filter.o pot.o sid.o voice.o wave6581__ST.o \