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
This commit is contained in:
Adrien Moulin
2022-07-25 20:24:31 +02:00
parent b10cd69dca
commit 808337aac3
22 changed files with 975 additions and 555 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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*/

View File

@@ -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*/

View File

@@ -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 {

View File

@@ -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_*/

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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:

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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,
};

387
src/sound/snd_opl_ymfm.cpp Normal file
View File

@@ -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, <adrien@elyosh.org>
*
* Copyright 2022 Adrien Moulin.
*/
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#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 <typename ChipType>
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<ChipType> *drv = (YMFMChip<ChipType> *) priv;
drv->m_engine->engine_timer_expired(0);
}
static void timer2(void *priv)
{
YMFMChip<ChipType> *drv = (YMFMChip<ChipType> *) 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 <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#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<ymfm::ym3812>(3579545, FM_YM3812, 48000);
break;
case FM_YMF262:
fm = (YMFMChipBase *) new YMFMChip<ymfm::ymf262>(14318181, FM_YMF262, 48000);
break;
case FM_YMF289B:
fm = (YMFMChipBase *) new YMFMChip<ymfm::ymf289b>(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,
};
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -1 +1 @@
add_library(ymfm STATIC ymfm_opl.cpp)
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)

View File

@@ -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 \