ISA Covox's and clones
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
475
src/sound/snd_covox.c
Normal 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
|
||||
};
|
||||
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user