ISA Covox's and clones

This commit is contained in:
Jasmine Iwanek
2025-05-30 21:28:13 -04:00
parent eafb95c558
commit 3485391905
5 changed files with 515 additions and 3 deletions

View File

@@ -12,9 +12,11 @@
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2018 Miran Grca.
* Copyright 2016-2025 Miran Grca.
* Copyright 2024-2025 Jasmine Iwanek.
*/
#ifndef EMU_SOUND_H
@@ -132,6 +134,12 @@ extern const device_t cmi8738_device;
extern const device_t cmi8738_onboard_device;
extern const device_t cmi8738_6ch_onboard_device;
/* Covox ISA */
extern const device_t voicemasterkey_device;
extern const device_t soundmasterplus_device;
extern const device_t isadacr0_device;
extern const device_t isadacr1_device;
/* Creative Labs Game Blaster */
extern const device_t cms_device;
@@ -214,6 +222,9 @@ extern const device_t pasplus_device;
extern const device_t pas16_device;
extern const device_t pas16d_device;
/* Rainbow Arts PC-Soundman */
extern const device_t soundman_device;
/* Tandy PSSJ */
extern const device_t pssj_device;
extern const device_t pssj_isa_device;

View File

@@ -36,6 +36,7 @@ add_library(snd OBJECT
snd_azt2316a.c
snd_cms.c
snd_cmi8x38.c
snd_covox.c
snd_cs423x.c
snd_gus.c
snd_sb.c

View File

@@ -1,3 +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.
*
* This file is part of the 86Box distribution.
*
* Adlib emulation.
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2025 Miran Grca.
* Copyright 2024-2025 Jasmine Iwanek.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -33,7 +51,7 @@ adlib_log(const char *fmt, ...)
# define adlib_log(fmt, ...)
#endif
typedef struct adlib_t {
typedef struct adlib_s {
fm_drv_t opl;
uint8_t pos_regs[8];

475
src/sound/snd_covox.c Normal file
View File

@@ -0,0 +1,475 @@
/*
* 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.
*
* Rainbow Arts PC-Soundman Emulation
*
* Authors: Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2025 Jasmine Iwanek.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/mca.h>
#include <86box/sound.h>
#include <86box/filters.h>
#include <86box/timer.h>
#include <86box/snd_opl.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
#define COVOX_SOUNDMAN 0
#define COVOX_VOICEMASTERKEY 1
#define COVOX_SOUNDMASTERPLUS 2
#define COVOX_ISADACR0 3
#define COVOX_ISADACR1 4
#ifdef ENABLE_COVOX_LOG
int covox_do_log = ENABLE_COVOX_LOG;
static void
covox_log(const char *fmt, ...)
{
va_list ap;
if (covox_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define covox_log(fmt, ...)
#endif
typedef struct covox_s {
fm_drv_t opl;
uint8_t dac_val;
int16_t buffer[2][SOUNDBUFLEN];
int pos;
} covox_t;
// TODO: Can this be rolled into covox_get_buffer?
static void
covox_update(covox_t *covox)
{
for (; covox->pos < sound_pos_global; covox->pos++) {
covox->buffer[0][covox->pos] = (int8_t) (covox->dac_val ^ 0x80) * 0x40;
covox->buffer[1][covox->pos] = (int8_t) (covox->dac_val ^ 0x80) * 0x40;
}
}
uint8_t
covox_read(uint16_t addr, void *priv)
{
#if 0
const covox_t *covox = (covox_t *) priv;
#endif
covox_log("covox_read: addr=%04x\n", addr);
return 0xff;
}
void
covox_write(uint16_t addr, uint8_t val, void *priv)
{
covox_t *covox = (covox_t *) priv;
covox_log("covox_write: addr=%04x val=%02x\n", addr, val);
switch (addr) {
case 0x221: // Soundman
case 0x229: // Soundman
case 0x22f: // Soundman, voicemasterkey
case 0x231: // isadac-r1?
case 0x24f: // voicemasterkey
case 0x279: // isadac-r0 (lPT2)
case 0x28f: // voicemasterkey
case 0x2cf: // voicemasterkey
case 0x301: // Soundman
case 0x309: // Soundman
case 0x30f: // soundman
case 0x331: // soundmasterplus
case 0x339: // soundmasterplus
case 0x371: // isadac-r0
case 0x379: // isadac-r0 (lPT1)
case 0x381: // isadac-r0
case 0x3bd: // isadac-r0 (lPT1-Mono)
covox->dac_val = val;
// TODO: Is this needed here?
covox_update(covox);
break;
default:
break;
}
}
static void
covox_get_buffer(int32_t *buffer, int len, void *priv)
{
covox_t *covox = (covox_t *) priv;
covox_update(covox);
for (int c = 0; c < len; c++) {
buffer[c * 2] += dac_iir(0, covox->buffer[0][c]);
buffer[c * 2 + 1] += dac_iir(1, covox->buffer[1][c]);
}
covox->pos = 0;
}
static void
covox_get_music_buffer(int32_t *buffer, int len, void *priv)
{
covox_t *covox = (covox_t *) priv;
const int32_t *opl_buf = covox->opl.update(covox->opl.priv);
for (int c = 0; c < len * 2; c++)
buffer[c] += opl_buf[c];
if (covox->opl.reset_buffer)
covox->opl.reset_buffer(covox->opl.priv);
}
#define IO_SETHANDLER_COVOX_DAC(addr, len) \
io_sethandler((addr), (len), \
covox_read, NULL, NULL, \
covox_write, NULL, NULL, \
covox)
#define IO_SETHANDLER_COVOX_ADLIB(addr, len) \
io_sethandler((addr), (len), \
covox->opl.read, NULL, NULL, \
covox->opl.write, NULL, NULL, \
covox->opl.priv)
void *
covox_init(UNUSED(const device_t *info))
{
covox_t *covox = calloc(1, sizeof(covox_t));
uint8_t has_adlib = 0;
uint8_t has_stereo = 0;
uint8_t fixed_address = 0;
if (!covox)
return NULL;
covox_log("covox_init\n");
switch (info->local) {
case COVOX_SOUNDMAN:
fixed_address = 1;
fallthrough;
case COVOX_SOUNDMASTERPLUS:
has_adlib = 1;
break;
case COVOX_ISADACR0:
has_stereo = 1;
break;
case COVOX_ISADACR1:
has_stereo = 2;
break;
default:
break;
}
if (fixed_address) {
IO_SETHANDLER_COVOX_DAC(0x220, 0x0002);
IO_SETHANDLER_COVOX_DAC(0x228, 0x0002);
IO_SETHANDLER_COVOX_DAC(0x22e, 0x0002);
#if 0
// According to vgmpf, this is the address
IO_SETHANDLER_COVOX_DAC(0x22f, 0x0001);
#endif
IO_SETHANDLER_COVOX_DAC(0x300, 0x0002);
IO_SETHANDLER_COVOX_DAC(0x308, 0x0002);
IO_SETHANDLER_COVOX_DAC(0x30e, 0x0002);
} else {
IO_SETHANDLER_COVOX_DAC(device_get_config_hex16("base"), 0x0002);
// TODO: Needs more work
if (has_stereo)
IO_SETHANDLER_COVOX_DAC(device_get_config_hex16("base2"), 0x0002);
}
sound_add_handler(covox_get_buffer, covox);
if (has_adlib) {
fm_driver_get(FM_YM3812, &covox->opl);
if (fixed_address) {
// Adlib Clone part
IO_SETHANDLER_COVOX_ADLIB(0x380, 0x0002);
IO_SETHANDLER_COVOX_ADLIB(0x388, 0x0002);
IO_SETHANDLER_COVOX_ADLIB(0x38e, 0x0002);
} else
IO_SETHANDLER_COVOX_ADLIB(device_get_config_hex16("adlibbase"), 0x0002);
music_add_handler(covox_get_music_buffer, covox);
}
return covox;
}
void
covox_close(void *priv)
{
covox_t *covox = (covox_t *) priv;
if (covox)
free(covox);
}
// clang-format off
static const device_config_t voicemasterkey_config[] = {
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x388,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x22f", .value = 0x22f },
{ .description = "0x24f", .value = 0x24f },
{ .description = "0x28f", .value = 0x28f },
{ .description = "0x2cf", .value = 0x2cf },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
// Note: We don't support sound input on this yet
const device_t voicemasterkey_device = {
.name = "Covox Voice Master Key",
.internal_name = "voicemasterkey",
.flags = DEVICE_ISA | DEVICE_SIDECAR,
.local = COVOX_VOICEMASTERKEY,
.init = covox_init,
.close = covox_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = voicemasterkey_config
};
// clang-format off
static const device_config_t soundmasterplus_config[] = {
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x330,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x330", .value = 0x330 },
{ .description = "0x338", .value = 0x338 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "adlibbase",
.description = "Adlib Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x388,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x388", .value = 0x388 },
{ .description = "0x380", .value = 0x380 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
const device_t soundmasterplus_device = {
.name = "Covox Sound Master Plus",
.internal_name = "soundmasterplus",
.flags = DEVICE_ISA | DEVICE_SIDECAR,
.local = COVOX_SOUNDMASTERPLUS,
.init = covox_init,
.close = covox_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = soundmasterplus_config
};
// clang-format off
static const device_config_t isadacr0_config[] = {
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x380,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x220", .value = 0x220 },
{ .description = "0x228", .value = 0x228 },
{ .description = "0x22e", .value = 0x22e },
{ .description = "0x230", .value = 0x230 },
{ .description = "0x24e", .value = 0x24e },
{ .description = "0x278", .value = 0x278 },
{ .description = "0x28e", .value = 0x28e },
{ .description = "0x2ce", .value = 0x2ce },
{ .description = "0x300", .value = 0x300 },
{ .description = "0x308", .value = 0x308 },
{ .description = "0x303", .value = 0x30e },
{ .description = "0x330", .value = 0x330 },
{ .description = "0x338", .value = 0x338 },
{ .description = "0x370", .value = 0x370 },
{ .description = "0x378", .value = 0x378 },
{ .description = "0x380", .value = 0x380 },
{ .description = "0x3bc", .value = 0x3bc },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "base2",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x370,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x220", .value = 0x220 },
{ .description = "0x228", .value = 0x228 },
{ .description = "0x22e", .value = 0x22e },
{ .description = "0x230", .value = 0x230 },
{ .description = "0x24e", .value = 0x24e },
{ .description = "0x278", .value = 0x278 },
{ .description = "0x28e", .value = 0x28e },
{ .description = "0x2ce", .value = 0x2ce },
{ .description = "0x300", .value = 0x300 },
{ .description = "0x308", .value = 0x308 },
{ .description = "0x303", .value = 0x30e },
{ .description = "0x330", .value = 0x330 },
{ .description = "0x338", .value = 0x338 },
{ .description = "0x370", .value = 0x370 },
{ .description = "0x378", .value = 0x378 },
{ .description = "0x380", .value = 0x380 },
{ .description = "0x3bc", .value = 0x3bc },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
// Note: We don't support stereo on this yet
const device_t isadacr0_device = {
.name = "ISA DAC-r0",
.internal_name = "isadacr0",
.flags = DEVICE_ISA | DEVICE_SIDECAR,
.local = COVOX_ISADACR0,
.init = covox_init,
.close = covox_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isadacr0_config
};
// clang-format off
static const device_config_t isadacr1_config[] = {
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x378,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x378", .value = 0x378 },
{ .description = "0x3bc", .value = 0x3bc },
{ .description = "0x278", .value = 0x278 },
{ .description = "0x230", .value = 0x230 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "base2",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x278,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x378", .value = 0x378 },
{ .description = "0x3bc", .value = 0x3bc },
{ .description = "0x278", .value = 0x278 },
{ .description = "0x230", .value = 0x230 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
// Note: We don't support stereo on this yet
const device_t isadacr1_device = {
.name = "ISA DAC-r1",
.internal_name = "isadacr1",
.flags = DEVICE_ISA | DEVICE_SIDECAR,
.local = COVOX_ISADACR1,
.init = covox_init,
.close = covox_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isadacr1_config
};
const device_t soundman_device = {
.name = "Rainbow Arts PC-Soundman",
.internal_name = "soundman",
.flags = DEVICE_ISA | DEVICE_SIDECAR,
.local = COVOX_SOUNDMAN,
.init = covox_init,
.close = covox_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -12,9 +12,11 @@
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
* Copyright 2016-2025 Miran Grca.
* Copyright 2024-2025 Jasmine Iwanek.
*/
#include <math.h>
#include <stdarg.h>
@@ -111,6 +113,11 @@ static const SOUND_CARD sound_cards[] = {
{ &ssi2001_device },
{ &mmb_device },
{ &pasplus_device },
{ &voicemasterkey_device },
{ &soundmasterplus_device },
{ &soundman_device },
{ &isadacr0_device },
{ &isadacr1_device },
{ &sb_1_device },
{ &sb_15_device },
{ &sb_2_device },