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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
10
src/config.c
10
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -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
387
src/sound/snd_opl_ymfm.cpp
Normal 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,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user