diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h
index 33467cf25..a85f1515c 100644
--- a/src/include/86box/snd_sb.h
+++ b/src/include/86box/snd_sb.h
@@ -11,9 +11,11 @@
* Authors: Sarah Walker,
* Miran Grca,
* TheCollector1995,
+ * Jasmine Iwanek,
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2018 Miran Grca.
+ * Copyright 2024-2025 Jasmine Iwanek.
*/
#ifndef SOUND_SND_SB_H
@@ -196,6 +198,12 @@ typedef struct sb_t {
void (*opl_mix)(void*, double*, double*);
} sb_t;
+typedef struct goldfinch_t {
+ emu8k_t emu8k;
+
+ uint8_t pnp_rom[512];
+} goldfinch_t;
+
extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *priv);
extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *priv);
extern void sb_ct1345_mixer_reset(sb_t *sb);
diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h
index 9029b336d..e5ae227fd 100644
--- a/src/include/86box/sound.h
+++ b/src/include/86box/sound.h
@@ -158,6 +158,7 @@ extern const device_t sb_16_pnp_ide_device;
extern const device_t sb_16_compat_device;
extern const device_t sb_16_compat_nompu_device;
extern const device_t sb_16_reply_mca_device;
+extern const device_t sb_goldfinch_device;
extern const device_t sb_32_pnp_device;
extern const device_t sb_awe32_device;
extern const device_t sb_awe32_pnp_device;
diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c
index df0547fdc..8ac27882b 100644
--- a/src/sound/snd_sb.c
+++ b/src/sound/snd_sb.c
@@ -1,23 +1,21 @@
/*
- * 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.
+ * 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.
+ * This file is part of the 86Box distribution.
*
- * Sound Blaster emulation.
+ * Sound Blaster emulation.
*
+ * Authors: Sarah Walker,
+ * Miran Grca,
+ * TheCollector1995,
+ * Jasmine Iwanek,
*
- *
- * Authors: Sarah Walker,
- * Miran Grca,
- * TheCollector1995,
- * Jasmine Iwanek,
- *
- * Copyright 2008-2020 Sarah Walker.
- * Copyright 2016-2020 Miran Grca.
- * Copyright 2024 Jasmine Iwanek.
+ * Copyright 2008-2020 Sarah Walker.
+ * Copyright 2016-2020 Miran Grca.
+ * Copyright 2024-2025 Jasmine Iwanek.
*/
#include
#include
@@ -64,6 +62,7 @@
#define PNP_ROM_SB_VIBRA16C "roms/sound/creative/CT4180 PnP.BIN"
#define PNP_ROM_SB_VIBRA16CL "roms/sound/creative/CT4100 PnP.BIN"
#define PNP_ROM_SB_VIBRA16XV "roms/sound/creative/CT4170 PnP.BIN"
+#define PNP_ROM_SB_GOLDFINCH "roms/sound/creative/CT1920 PnP.BIN"
#define PNP_ROM_SB_32_PNP "roms/sound/creative/CT3600 PnP.BIN"
#define PNP_ROM_SB_AWE32_PNP "roms/sound/creative/CT3980 PnP.BIN"
#define PNP_ROM_SB_AWE64_VALUE "roms/sound/creative/CT4520 PnP.BIN"
@@ -509,6 +508,28 @@ sb_get_music_buffer_sb16_awe32(int32_t *buffer, const int len, void *priv)
sb->opl.reset_buffer(sb->opl.priv);
}
+// TODO: Goldfinch
+static void
+sb_get_wavetable_buffer_goldfinch(int32_t *buffer, const int len, void *priv)
+{
+ goldfinch_t *goldfinch = (goldfinch_t *) priv;
+
+ emu8k_update(&goldfinch->emu8k);
+
+ for (int c = 0; c < len * 2; c += 2) {
+ double out_l = 0.0;
+ double out_r = 0.0;
+
+ out_l += ((double) goldfinch->emu8k.buffer[c]);
+ out_r += ((double) goldfinch->emu8k.buffer[c + 1]);
+
+ buffer[c] += (int32_t) out_l;
+ buffer[c + 1] += (int32_t) out_r;
+ }
+
+ goldfinch->emu8k.pos = 0;
+}
+
static void
sb_get_wavetable_buffer_sb16_awe32(int32_t *buffer, const int len, void *priv)
{
@@ -2217,6 +2238,21 @@ sb_vibra16_pnp_config_changed(const uint8_t ld, isapnp_device_config_t *config,
}
}
+static void
+goldfinch_pnp_config_changed(const uint8_t ld, isapnp_device_config_t *config, void *priv)
+{
+ goldfinch_t *goldfinch = (goldfinch_t *) priv;
+
+ switch (ld) {
+ default:
+ break;
+
+ case 0: /* WaveTable */
+ emu8k_change_addr(&goldfinch->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
+ break;
+ }
+}
+
static void
sb_awe32_pnp_config_changed(const uint8_t ld, isapnp_device_config_t *config, void *priv)
{
@@ -3550,6 +3586,12 @@ sb_awe32_available(void)
return rom_present(EMU8K_ROM_PATH);
}
+static int
+sb_goldfinch_available(void)
+{
+ return sb_awe32_available() && rom_present(PNP_ROM_SB_GOLDFINCH);
+}
+
static int
sb_32_pnp_available(void)
{
@@ -3659,6 +3701,54 @@ sb_awe32_init(UNUSED(const device_t *info))
return sb;
}
+static void *
+sb_goldfinch_init(const device_t *info)
+{
+ goldfinch_t *goldfinch = malloc(sizeof(goldfinch_t));
+ int onboard_ram = device_get_config_int("onboard_ram");
+
+ memset(goldfinch, 0x00, sizeof(goldfinch_t));
+
+ wavetable_add_handler(sb_get_wavetable_buffer_goldfinch, goldfinch);
+
+ emu8k_init(&goldfinch->emu8k, 0, onboard_ram);
+
+ const char *pnp_rom_file = NULL;
+ switch (info->local) {
+ case 0:
+ pnp_rom_file = PNP_ROM_SB_GOLDFINCH;
+ break;
+
+ default:
+ break;
+ }
+
+ uint8_t *pnp_rom = NULL;
+ if (pnp_rom_file) {
+ FILE *fp = rom_fopen(pnp_rom_file, "rb");
+ uint16_t pnp_rom_len = 256;
+ if (fp) {
+ if (fread(goldfinch->pnp_rom, 1, pnp_rom_len, fp) == pnp_rom_len)
+ pnp_rom = goldfinch->pnp_rom;
+ fclose(fp);
+ }
+ }
+
+ switch (info->local) {
+ case 0:
+ isapnp_add_card(pnp_rom, sizeof(goldfinch->pnp_rom), goldfinch_pnp_config_changed,
+ NULL, NULL, NULL, goldfinch);
+ break;
+
+ default:
+ break;
+ }
+
+ emu8k_change_addr(&goldfinch->emu8k, 0);
+
+ return goldfinch;
+}
+
static void *
sb_awe32_pnp_init(const device_t *info)
{
@@ -4054,6 +4144,16 @@ sb_close(void *priv)
free(sb);
}
+static void
+sb_goldfinch_close(void *priv)
+{
+ goldfinch_t *goldfinch = (goldfinch_t *) priv;
+
+ emu8k_close(&goldfinch->emu8k);
+
+ free(goldfinch);
+}
+
static void
sb_awe32_close(void *priv)
{
@@ -4765,6 +4865,54 @@ static const device_config_t sb_16_pnp_config[] = {
{ .name = "", .description = "", .type = CONFIG_END }
};
+static const device_config_t sb_goldfinch_config[] = {
+ {
+ .name = "onboard_ram",
+ .description = "Memory size",
+ .type = CONFIG_SELECTION,
+ .default_string = "",
+ .default_int = 0,
+ .file_filter = "",
+ .spinner = { 0 },
+ .selection = {
+ {
+ .description = "None",
+ .value = 0
+ },
+ {
+ .description = "512 KB",
+ .value = 512
+ },
+ {
+ .description = "1 MB",
+ .value = 1024
+ },
+ {
+ .description = "2 MB",
+ .value = 2048
+ },
+ {
+ .description = "4 MB",
+ .value = 4096
+ },
+ {
+ .description = "8 MB",
+ .value = 8192
+ },
+ {
+ .description = "16 MB",
+ .value = 16384
+ },
+ {
+ .description = "28 MB",
+ .value = 28672
+ },
+ { .description = "" }
+ }
+ },
+ { .name = "", .description = "", .type = CONFIG_END }
+};
+
static const device_config_t sb_32_pnp_config[] = {
{
.name = "onboard_ram",
@@ -5922,6 +6070,20 @@ const device_t sb_16_compat_nompu_device = {
.config = NULL
};
+const device_t sb_goldfinch_device = {
+ .name = "Creative EMU8000 PnP (Goldfinch)",
+ .internal_name = "sb_goldfinch",
+ .flags = DEVICE_ISA | DEVICE_AT,
+ .local = 0,
+ .init = sb_goldfinch_init,
+ .close = sb_goldfinch_close,
+ .reset = NULL,
+ .available = sb_goldfinch_available,
+ .speed_changed = NULL,
+ .force_redraw = NULL,
+ .config = sb_goldfinch_config
+};
+
const device_t sb_32_pnp_device = {
.name = "Sound Blaster 32 PnP",
.internal_name = "sb32_pnp",
diff --git a/src/sound/sound.c b/src/sound/sound.c
index 06f38d125..b1762eaff 100644
--- a/src/sound/sound.c
+++ b/src/sound/sound.c
@@ -123,6 +123,7 @@ static const SOUND_CARD sound_cards[] = {
{ &sb_16_device },
{ &sb_16_pnp_device },
{ &sb_16_pnp_ide_device },
+ { &sb_goldfinch_device },
{ &sb_32_pnp_device },
{ &sb_awe32_device },
{ &sb_awe32_pnp_device },