From 7f9f072b3e51324a299b07bd2140f1cebebcb261 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 3 Mar 2024 16:19:01 +0600 Subject: [PATCH] Add ESS ES1688 (COMPLETELY UNTESTED!!!) --- src/include/86box/sound.h | 4 + src/sound/snd_ess.c | 261 +++++++++++++++++++++++++++++++++++++- src/sound/sound.c | 1 + 3 files changed, 265 insertions(+), 1 deletion(-) diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index b8f9be5b2..c6fdada89 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -184,6 +184,10 @@ extern const device_t cmi8338_onboard_device; extern const device_t cmi8738_device; extern const device_t cmi8738_onboard_device; extern const device_t cmi8738_6ch_onboard_device; + +/* ESS Technology */ +extern const device_t ess_1688_device; + #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_ess.c b/src/sound/snd_ess.c index d762117cd..5b6852b68 100644 --- a/src/sound/snd_ess.c +++ b/src/sound/snd_ess.c @@ -255,4 +255,263 @@ ess_mixer_reset(ess_t *ess) { ess_mixer_write(4, 0, ess); ess_mixer_write(5, 0, ess); -} \ No newline at end of file +} + +void +ess_get_buffer_sbpro(int32_t *buffer, int len, void *priv) +{ + sb_t *sb = (sb_t *) priv; + const sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + double out_l = 0.0; + double out_r = 0.0; + + sb_dsp_update(&sb->dsp); + + for (int c = 0; c < len * 2; c += 2) { + out_l = 0.0; + out_r = 0.0; + + /* TODO: Implement the stereo switch on the mixer instead of on the dsp? */ + if (mixer->output_filter) { + out_l += (sb_iir(0, 0, (double) sb->dsp.buffer[c]) * mixer->voice_l) / 3.9; + out_r += (sb_iir(0, 1, (double) sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3.9; + } else { + out_l += (sb->dsp.buffer[c] * mixer->voice_l) / 3.0; + out_r += (sb->dsp.buffer[c + 1] * mixer->voice_r) / 3.0; + } + + /* TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. */ + out_l *= mixer->master_l; + out_r *= mixer->master_r; + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + sb->dsp.pos = 0; +} + +void +ess_get_music_buffer_sbpro(int32_t *buffer, int len, void *priv) +{ + ess_t *ess = (ess_t *) priv; + const ess_mixer_t *mixer = &ess->mixer_sbpro; + double out_l = 0.0; + double out_r = 0.0; + const int32_t *opl_buf = NULL; + const int32_t *opl2_buf = NULL; + + opl_buf = ess->opl.update(ess->opl.priv); + + sb_dsp_update(&ess->dsp); + + for (int c = 0; c < len * 2; c += 2) { + out_l = 0.0; + out_r = 0.0; + + { + out_l = (((double) opl_buf[c]) * mixer->fm_l) * 0.7171630859375; + out_r = (((double) opl_buf[c + 1]) * mixer->fm_r) * 0.7171630859375; + if (ess->opl_mix && ess->opl_mixer) + ess->opl_mix(ess->opl_mixer, &out_l, &out_r); + } + + /* TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. */ + out_l *= mixer->master_l; + out_r *= mixer->master_r; + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + ess->opl.reset_buffer(ess->opl.priv); +} + +void +ess_filter_cd_audio(int channel, double *buffer, void *priv) +{ + const ess_t *ess = (ess_t *) priv; + const ess_mixer_t *mixer = &ess->mixer_sbpro; + double c; + double cd = channel ? mixer->cd_r : mixer->cd_l; + double master = channel ? mixer->master_r : mixer->master_l; + + if (mixer->output_filter) + c = (sb_iir(2, channel, *buffer) * cd) / 3.9; + else + c = (*buffer * cd) / 3.0; + *buffer = c * master; +} + +static void * +ess_1688_init(UNUSED(const device_t *info)) +{ + /* SB Pro 2 port mappings, 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface. */ + ess_t *ess = malloc(sizeof(ess_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(ess, 0, sizeof(ess_t)); + + fm_driver_get(FM_ESFM, &ess->opl); + + sb_dsp_set_real_opl(&ess->dsp, 1); + sb_dsp_init(&ess->dsp, SBPRO2, SB_SUBTYPE_ESS_ES1688, ess); + sb_dsp_setaddr(&ess->dsp, addr); + sb_dsp_setirq(&ess->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&ess->dsp, device_get_config_int("dma")); + ess_mixer_reset(ess); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + { + io_sethandler(addr, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(addr + 8, 0x0002, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + } + + ess->mixer_enabled = 1; + io_sethandler(addr + 4, 0x0002, + ess_mixer_read, NULL, NULL, + ess_mixer_write, NULL, NULL, + ess); + sound_add_handler(ess_get_buffer_sbpro, ess); + music_add_handler(ess_get_music_buffer_sbpro, ess); + sound_set_cd_audio_filter(ess_filter_cd_audio, ess); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &ess->dsp); + + return ess; +} + +void +ess_close(void *priv) +{ + ess_t *ess = (ess_t *) priv; + sb_dsp_close(&ess->dsp); + + free(ess); +} + +void +ess_speed_changed(void *priv) +{ + ess_t *ess = (ess_t *) priv; + + sb_dsp_speed_changed(&ess->dsp); +} + +static const device_config_t ess_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x220, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 7, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "DMA 0", + .value = 0 + }, + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { .description = "" } + } + }, + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { + .name = "receive_input", + .description = "Receive input (SB MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +const device_t ess_1688_device = { + .name = "ESS Technology ESS1688", + .internal_name = "ess_1688", + .flags = DEVICE_ISA, + .local = 0, + .init = ess_1688_init, + .close = ess_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = ess_speed_changed, + .force_redraw = NULL, + .config = ess_config +}; \ No newline at end of file diff --git a/src/sound/sound.c b/src/sound/sound.c index 81f70d921..2f6b91aca 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -165,6 +165,7 @@ static const SOUND_CARD sound_cards[] = { { &es1371_device }, { &ad1881_device }, { &cs4297a_device }, + { &ess_1688_device }, { NULL } // clang-format on };