Added Aztech Sound Galaxy Pro 16 AB (Washington, AZ2316A) and Aztech Sound

Galaxy Nova 16 Extra (Clinton, AZ1605) emulation. Patch from EluanCM.
Clinton is currently marked as DEVICE_NOT_WORKING due to issues with DOS drivers.
This commit is contained in:
SarahW 2020-03-11 21:21:09 +00:00
commit 1181b13c2d
17 changed files with 2051 additions and 179 deletions

View file

@ -40,7 +40,7 @@ mca.c mcr.c mem.c mem_bios.c mfm_at.c mfm_xebec.c model.c mouse.c mouse_msystems
neat.c nmi.c nvr.c olivetti_m24.c opti495.c paths.c pc.c pc87306.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c \
ps2_nvr.c nvr_tc8521.c pzx.c rom.c rtc.c rtc_tc8521.c scamp.c scat.c scsi.c scsi_53c400.c scsi_aha1540.c scsi_cd.c scsi_hd.c \
scsi_ibm.c scsi_zip.c serial.c sio.c sis496.c sl82c460.c sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_audiopci.c \
sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \
sound_azt2316a.c sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \
sound_sb.c sound_sb_dsp.c sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c \
sst39sf010.c tandy_eeprom.c tandy_rom.c t1000.c t3100e.c timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c \
vid_ati18800.c vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_compaq_cga.c vid_ega.c \

View file

@ -26,7 +26,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
mvp3.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o \
piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scamp.o scat.o scsi.o \
scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_ibm.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o \
sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \
sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_azt2316a.o sound_cms.o sound_dbopl.o \
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o \
sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \

View file

@ -26,7 +26,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
mvp3.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o \
piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scamp.o scat.o scsi.o \
scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_ibm.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o \
sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \
sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_azt2316a.o sound_cms.o sound_dbopl.o \
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o \
sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \

View file

@ -15,6 +15,7 @@
#include "sound_adlib.h"
#include "sound_adlibgold.h"
#include "sound_audiopci.h"
#include "sound_azt2316a.h"
#include "sound_pas16.h"
#include "sound_sb.h"
#include "sound_sb_dsp.h"
@ -35,23 +36,25 @@ typedef struct
static SOUND_CARD sound_cards[] =
{
{"None", "none", NULL},
{"Adlib", "adlib", &adlib_device},
{"Adlib", "adlib_mca", &adlib_mca_device},
{"Sound Blaster 1.0", "sb", &sb_1_device},
{"Sound Blaster 1.5", "sb1.5", &sb_15_device},
{"Sound Blaster MCV", "sbmcv", &sb_mcv_device},
{"Sound Blaster 2.0", "sb2.0", &sb_2_device},
{"Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device},
{"Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device},
{"Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device},
{"Sound Blaster 16", "sb16", &sb_16_device},
{"Sound Blaster AWE32", "sbawe32", &sb_awe32_device},
{"Adlib Gold", "adlibgold", &adgold_device},
{"Windows Sound System", "wss", &wss_device},
{"Pro Audio Spectrum 16", "pas16", &pas16_device},
{"Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device},
{"Sound Blaster PCI 128", "sbpci128", &es1371_device},
{"None", "none", NULL},
{"Adlib", "adlib", &adlib_device},
{"Adlib", "adlib_mca", &adlib_mca_device},
{"Sound Blaster 1.0", "sb", &sb_1_device},
{"Sound Blaster 1.5", "sb1.5", &sb_15_device},
{"Sound Blaster MCV", "sbmcv", &sb_mcv_device},
{"Sound Blaster 2.0", "sb2.0", &sb_2_device},
{"Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device},
{"Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device},
{"Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device},
{"Sound Blaster 16", "sb16", &sb_16_device},
{"Sound Blaster AWE32", "sbawe32", &sb_awe32_device},
{"Adlib Gold", "adlibgold", &adgold_device},
{"Windows Sound System", "wss", &wss_device},
{"Aztech Sound Galaxy Pro 16 AB (Washington)", "azt2316a", &azt2316a_device},
{"Aztech Sound Galaxy Nova 16 Extra (Clinton)", "azt1605", &azt1605_device},
{"Pro Audio Spectrum 16", "pas16", &pas16_device},
{"Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device},
{"Sound Blaster PCI 128", "sbpci128", &es1371_device},
{"", "", NULL}
};

View file

@ -4,8 +4,10 @@
#include "pic.h"
#include "sound.h"
#include "sound_ad1848.h"
#include "x86.h"
static int ad1848_vols[64];
static int ad1848_vols_6bits[64];
static uint32_t ad1848_vols_5bits_aux_gain[32];
void ad1848_setirq(ad1848_t *ad1848, int irq)
{
@ -21,7 +23,7 @@ uint8_t ad1848_read(uint16_t addr, void *p)
{
ad1848_t *ad1848 = (ad1848_t *)p;
uint8_t temp = 0xff;
// pclog("ad1848_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc);
switch (addr & 3)
{
case 0: /*Index*/
@ -34,7 +36,10 @@ uint8_t ad1848_read(uint16_t addr, void *p)
temp = ad1848->status;
break;
}
// pclog("return %02X\n", temp);
// if ((addr & 3) == 1 && (ad1848->index & 0x1f) > 0x0f)
// pclog("ad1848_read_EXTENDED - addr %04X %04X(%08X):%08X return %02X\n", addr, CS, cs, cpu_state.pc, temp);
// else
// pclog("ad1848_read - addr %04X %04X(%08X):%08X return %02X\n", addr, CS, cs, cpu_state.pc, temp);
return temp;
}
@ -42,11 +47,18 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p)
{
ad1848_t *ad1848 = (ad1848_t *)p;
double freq;
// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc);
uint32_t new_cd_vol_l, new_cd_vol_r;
// if ((addr & 3) == 0 && (val & 0x1f) > 0x0f)
// pclog("ad1848_write_EXTENDED - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc);
// else
// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc);
switch (addr & 3)
{
case 0: /*Index*/
ad1848->index = val & 0xf;
if (ad1848->regs[12] & 0x40 && ad1848->type == AD1848_TYPE_CS4231)
ad1848->index = val & 0x1f; // cs4231a extended mode enabled
else
ad1848->index = val & 0x0f; // ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes?
ad1848->trd = val & 0x20;
ad1848->mce = val & 0x40;
break;
@ -71,29 +83,49 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p)
break;
case 9:
if (!ad1848->enable && (val & 0x41) == 0x01)
{
if (ad1848->timer_latch)
timer_set_delay_u64(&ad1848->timer, ad1848->timer_latch);
else
timer_set_delay_u64(&ad1848->timer, TIMER_USEC);
}
if (!ad1848->enable && (val & 0x41) == 0x01)
{
if (ad1848->timer_latch)
timer_set_delay_u64(&ad1848->timer, ad1848->timer_latch);
else
timer_set_delay_u64(&ad1848->timer, TIMER_USEC);
}
ad1848->enable = ((val & 0x41) == 0x01);
if (!ad1848->enable)
{
timer_disable(&ad1848->timer);
{
timer_disable(&ad1848->timer);
ad1848->out_l = ad1848->out_r = 0;
}
}
break;
case 12:
ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80;
return;
case 14:
ad1848->count = ad1848->regs[15] | (val << 8);
break;
// TODO: see which of the extended registers should be read only
}
ad1848->regs[ad1848->index] = val;
if (ad1848->type == AD1848_TYPE_CS4231) // TODO: configure CD volume for CS4248/AD1848 too
{
if (ad1848->regs[0x12] & 0x80)
new_cd_vol_l = 0;
else
new_cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f];
if (ad1848->regs[0x13] & 0x80)
new_cd_vol_r = 0;
else
new_cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f];
// Apparently there is no master volume to modulate here
// (The windows mixer just adjusts all registers at the same
// time when the master slider is adjusted)
sound_set_cd_volume(new_cd_vol_l, new_cd_vol_r);
}
break;
case 2:
ad1848->status &= 0xfe;
@ -125,7 +157,7 @@ static void ad1848_poll(void *p)
timer_advance_u64(&ad1848->timer, TIMER_USEC*1000);
ad1848_update(ad1848);
// TODO: line in, mic, etc...
if (ad1848->enable)
{
int32_t temp;
@ -155,12 +187,12 @@ static void ad1848_poll(void *p)
if (ad1848->regs[6] & 0x80)
ad1848->out_l = 0;
else
ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16;
ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16;
if (ad1848->regs[7] & 0x80)
ad1848->out_r = 0;
else
ad1848->out_r = (ad1848->out_r * ad1848_vols[ad1848->regs[7] & 0x3f]) >> 16;
ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16;
if (ad1848->count < 0)
{
@ -179,15 +211,17 @@ static void ad1848_poll(void *p)
else
{
ad1848->out_l = ad1848->out_r = 0;
sound_set_cd_volume(0, 0);
// pclog("ad1848_poll : not enable\n");
}
}
void ad1848_init(ad1848_t *ad1848)
void ad1848_init(ad1848_t *ad1848, int type)
{
int c;
double attenuation;
ad1848->type = type;
ad1848->enable = 0;
ad1848->status = 0xcc;
@ -195,15 +229,24 @@ void ad1848_init(ad1848_t *ad1848)
ad1848->mce = 0x40;
ad1848->regs[0] = ad1848->regs[1] = 0;
ad1848->regs[2] = ad1848->regs[3] = 0x80;
ad1848->regs[2] = ad1848->regs[3] = 0x80; // AZT2316A Line-in
ad1848->regs[4] = ad1848->regs[5] = 0x80;
ad1848->regs[6] = ad1848->regs[7] = 0x80;
ad1848->regs[6] = ad1848->regs[7] = 0x80; // AZT2316A Master?
ad1848->regs[8] = 0;
ad1848->regs[9] = 0x08;
ad1848->regs[10] = ad1848->regs[11] = 0;
ad1848->regs[12] = 0xa;
if (ad1848->type == AD1848_TYPE_CS4248 || ad1848->type == AD1848_TYPE_CS4231)
ad1848->regs[12] = 0x8a;
else
ad1848->regs[12] = 0xa;
ad1848->regs[13] = 0;
ad1848->regs[14] = ad1848->regs[15] = 0;
if (ad1848->type == AD1848_TYPE_CS4231)
{
ad1848->regs[0x12] = ad1848->regs[0x13] = 0x80; // AZT2316A CD
ad1848->regs[0x1A] = 0x80; // AZT2316A Mic
}
ad1848->out_l = 0;
ad1848->out_r = 0;
@ -220,9 +263,23 @@ void ad1848_init(ad1848_t *ad1848)
attenuation = pow(10, attenuation / 10);
ad1848_vols[c] = (int)(attenuation * 65536);
// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]);
ad1848_vols_6bits[c] = (int)(attenuation * 65536);
// pclog("ad1848_vols_6bits %i = %f %i\n", c, attenuation, ad1848_vols_6bits[c]);
}
for (c = 0; c < 32; c++)
{
attenuation = 12.0;
if (c & 0x01) attenuation -= 1.5;
if (c & 0x02) attenuation -= 3.0;
if (c & 0x04) attenuation -= 6.0;
if (c & 0x08) attenuation -= 12.0;
if (c & 0x10) attenuation -= 24.0;
attenuation = pow(10, attenuation / 10);
ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536);
// pclog("ad1848_vols_5bits_aux_gain %i = %f %i\n", c, attenuation, ad1848_vols_5bits_aux_gain[c]);
}
timer_add(&ad1848->timer, ad1848_poll, ad1848, 0);
}

View file

@ -1,9 +1,13 @@
#include "timer.h"
#define AD1848_TYPE_DEFAULT 0
#define AD1848_TYPE_CS4248 1
#define AD1848_TYPE_CS4231 2
typedef struct ad1848_t
{
int index;
uint8_t regs[16];
uint8_t regs[32]; // 16 original + 16 CS4231A extensions
uint8_t status;
int trd;
@ -20,10 +24,12 @@ typedef struct ad1848_t
int freq;
pc_timer_t timer;
uint64_t timer_latch;
uint64_t timer_latch;
int16_t buffer[MAXSOUNDBUFLEN * 2];
int pos;
int type;
} ad1848_t;
void ad1848_setirq(ad1848_t *ad1848, int irq);
@ -35,4 +41,4 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p);
void ad1848_update(ad1848_t *ad1848);
void ad1848_speed_changed(ad1848_t *ad1848);
void ad1848_init(ad1848_t *ad1848);
void ad1848_init(ad1848_t *ad1848, int type);

1620
src/sound_azt2316a.c Normal file

File diff suppressed because it is too large Load diff

4
src/sound_azt2316a.h Normal file
View file

@ -0,0 +1,4 @@
extern device_t azt2316a_device;
extern device_t azt1605_device;
void azt2316a_enable_wss(uint8_t enable, void *p);

View file

@ -1,3 +1,5 @@
#ifndef SOUND_EMU8K_H
#define SOUND_EMU8K_H
/* All these defines are in samples, not in bytes. */
#define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF
@ -773,3 +775,5 @@ Treble Parameters:
0xD308 0xD308 0xD308 0xD308 0xD308 0xD308 0xD3019 0xD32A 0xD34C 0xD36E 0xD36E 0xD36E
0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002
*/
#endif /* SOUND_EMU8K_H */

View file

@ -1,5 +1,6 @@
#include "ibm.h"
#include "io.h"
#include "pic.h"
#include "plat-midi.h"
#include "sound_mpu401_uart.h"
@ -9,6 +10,14 @@ enum
STATUS_INPUT_NOT_READY = 0x80
};
static void mpu401_uart_raise_irq(void *p)
{
mpu401_uart_t *mpu = (mpu401_uart_t *)p;
if (mpu->irq != -1)
picint(1 << mpu->irq);
}
static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p)
{
mpu401_uart_t *mpu = (mpu401_uart_t *)p;
@ -18,15 +27,20 @@ static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p)
switch (val)
{
case 0xff: /*Reset*/
// From Roland: "An ACK will not be sent back upon sending a SYSTEM RESET to leave the UART MODE ($3F)."
// But actual behaviour is weird. For example, the MPU401 port test in the AZT1605 drivers for Windows NT
// want this to return an Ack but the IRQ test in the same driver wants this to raise no interrupts!
mpu->rx_data = 0xfe; /*Acknowledge*/
mpu->status = 0;
mpu->status = STATUS_OUTPUT_NOT_READY;
mpu->uart_mode = 0;
//mpu401_uart_raise_irq(p);
break;
case 0x3f: /*Enter UART mode*/
mpu->rx_data = 0xfe; /*Acknowledge*/
mpu->status = 0;
mpu->status = STATUS_OUTPUT_NOT_READY;
mpu->uart_mode = 1;
mpu401_uart_raise_irq(p);
break;
}
return;
@ -45,14 +59,30 @@ static uint8_t mpu401_uart_read(uint16_t addr, void *p)
return mpu->status;
/*Data*/
mpu->status |= STATUS_INPUT_NOT_READY;
mpu->status = STATUS_INPUT_NOT_READY;
return mpu->rx_data;
}
void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr)
void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq)
{
mpu->status = STATUS_INPUT_NOT_READY;
mpu->uart_mode = 0;
mpu->addr = addr;
mpu->irq = irq;
io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu);
}
void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr)
{
io_removehandler(mpu->addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu);
mpu->addr = addr;
if (addr != 0)
io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu);
}
void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq)
{
mpu->irq = irq;
}

View file

@ -1,9 +1,18 @@
#ifndef SOUND_MPU401_UART
#define SOUND_MPU401_UART
typedef struct mpu401_uart_t
{
uint8_t status;
uint8_t rx_data;
int uart_mode;
int uart_mode;
uint16_t addr;
int irq;
} mpu401_uart_t;
void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr);
void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq);
void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr);
void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq);
#endif /* SOUND_MPU401_UART */

View file

@ -737,7 +737,7 @@ void *pas16_init()
memset(pas16, 0, sizeof(pas16_t));
opl3_init(&pas16->opl, 0);
sb_dsp_init(&pas16->dsp, SB2);
sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16);
io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16);

View file

@ -21,102 +21,6 @@ FILE* soundfsb = 0/*NULL*/;
FILE* soundfsbin = 0/*NULL*/;
#endif
/* SB 2.0 CD version */
typedef struct sb_ct1335_mixer_t
{
int32_t master;
int32_t voice;
int32_t fm;
int32_t cd;
uint8_t index;
uint8_t regs[256];
} sb_ct1335_mixer_t;
/* SB PRO */
typedef struct sb_ct1345_mixer_t
{
int32_t master_l, master_r;
int32_t voice_l, voice_r;
int32_t fm_l, fm_r;
int32_t cd_l, cd_r;
int32_t line_l, line_r;
int32_t mic;
/*see sb_ct1745_mixer for values for input selector*/
int32_t input_selector;
int input_filter;
int in_filter_freq;
int output_filter;
int stereo;
int stereo_isleft;
uint8_t index;
uint8_t regs[256];
} sb_ct1345_mixer_t;
/* SB16 and AWE32 */
typedef struct sb_ct1745_mixer_t
{
int32_t master_l, master_r;
int32_t voice_l, voice_r;
int32_t fm_l, fm_r;
int32_t cd_l, cd_r;
int32_t line_l, line_r;
int32_t mic;
int32_t speaker;
int bass_l, bass_r;
int treble_l, treble_r;
int output_selector;
#define OUTPUT_MIC 1
#define OUTPUT_CD_R 2
#define OUTPUT_CD_L 4
#define OUTPUT_LINE_R 8
#define OUTPUT_LINE_L 16
int input_selector_left;
int input_selector_right;
#define INPUT_MIC 1
#define INPUT_CD_R 2
#define INPUT_CD_L 4
#define INPUT_LINE_R 8
#define INPUT_LINE_L 16
#define INPUT_MIDI_R 32
#define INPUT_MIDI_L 64
int mic_agc;
int32_t input_gain_L;
int32_t input_gain_R;
int32_t output_gain_L;
int32_t output_gain_R;
uint8_t index;
uint8_t regs[256];
} sb_ct1745_mixer_t;
typedef struct sb_t
{
opl_t opl;
sb_dsp_t dsp;
union {
sb_ct1335_mixer_t mixer_sb2;
sb_ct1345_mixer_t mixer_sbpro;
sb_ct1745_mixer_t mixer_sb16;
};
mpu401_uart_t mpu;
emu8k_t emu8k;
int pos;
uint8_t pos_regs[8];
int opl_emu;
} sb_t;
/* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps.
Note that for positive dB values, this is not amplitude, it is amplitude-1. */
const float sb_bass_treble_4bits[]= {
@ -195,7 +99,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p)
sb->dsp.pos = 0;
}
static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p)
void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p)
{
sb_t *sb = (sb_t *)p;
sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro;
@ -950,7 +854,7 @@ void *sb_1_init()
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB1);
sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@ -972,7 +876,7 @@ void *sb_15_init()
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB15);
sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@ -993,7 +897,7 @@ void *sb_mcv_init()
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB15);
sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, 0);//addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@ -1024,7 +928,7 @@ void *sb_2_init()
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB2);
sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@ -1061,7 +965,7 @@ void *sb_pro_v1_init()
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SBPRO);
sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@ -1091,7 +995,7 @@ void *sb_pro_v2_init()
uint16_t addr = device_get_config_int("addr");
sb->opl_emu = device_get_config_int("opl_emu");
opl3_init(&sb->opl, sb->opl_emu);
sb_dsp_init(&sb->dsp, SBPRO2);
sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@ -1118,7 +1022,7 @@ void *sb_pro_mcv_init()
sb->opl_emu = device_get_config_int("opl_emu");
opl3_init(&sb->opl, sb->opl_emu);
sb_dsp_init(&sb->dsp, SBPRO2);
sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb);
sb_ct1345_mixer_reset(sb);
/* I/O handlers activated in sb_mcv_write */
sound_add_handler(sb_get_buffer_sbpro, sb);
@ -1139,7 +1043,7 @@ void *sb_16_init()
uint16_t addr = device_get_config_int("addr");
sb->opl_emu = device_get_config_int("opl_emu");
opl3_init(&sb->opl, sb->opl_emu);
sb_dsp_init(&sb->dsp, SB16);
sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
// TODO: irq and dma options too?
sb_ct1745_mixer_reset(sb);
@ -1148,7 +1052,7 @@ void *sb_16_init()
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb);
sound_add_handler(sb_get_buffer_sb16, sb);
mpu401_uart_init(&sb->mpu, 0x330);
mpu401_uart_init(&sb->mpu, 0x330, -1);
return sb;
@ -1169,7 +1073,7 @@ void *sb_awe32_init()
uint16_t emu_addr = device_get_config_int("emu_addr");
sb->opl_emu = device_get_config_int("opl_emu");
opl3_init(&sb->opl, sb->opl_emu);
sb_dsp_init(&sb->dsp, SB16 + 1);
sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
// TODO: irq and dma options too?
sb_ct1745_mixer_reset(sb);
@ -1178,7 +1082,7 @@ void *sb_awe32_init()
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb);
sound_add_handler(sb_get_buffer_emu8k, sb);
mpu401_uart_init(&sb->mpu, 0x330);
mpu401_uart_init(&sb->mpu, 0x330, -1);
emu8k_init(&sb->emu8k, emu_addr, onboard_ram);
return sb;

View file

@ -1,3 +1,10 @@
#ifndef SOUND_SB_H
#define SOUND_SB_H
#include "sound_emu8k.h"
#include "sound_mpu401_uart.h"
#include "sound_sb_dsp.h"
extern device_t sb_1_device;
extern device_t sb_15_device;
extern device_t sb_mcv_device;
@ -7,3 +14,110 @@ extern device_t sb_pro_v2_device;
extern device_t sb_pro_mcv_device;
extern device_t sb_16_device;
extern device_t sb_awe32_device;
/* SB 2.0 CD version */
typedef struct sb_ct1335_mixer_t
{
int32_t master;
int32_t voice;
int32_t fm;
int32_t cd;
uint8_t index;
uint8_t regs[256];
} sb_ct1335_mixer_t;
/* SB PRO */
typedef struct sb_ct1345_mixer_t
{
int32_t master_l, master_r;
int32_t voice_l, voice_r;
int32_t fm_l, fm_r;
int32_t cd_l, cd_r;
int32_t line_l, line_r;
int32_t mic;
/*see sb_ct1745_mixer for values for input selector*/
int32_t input_selector;
int input_filter;
int in_filter_freq;
int output_filter;
int stereo;
int stereo_isleft;
uint8_t index;
uint8_t regs[256];
} sb_ct1345_mixer_t;
/* SB16 and AWE32 */
typedef struct sb_ct1745_mixer_t
{
int32_t master_l, master_r;
int32_t voice_l, voice_r;
int32_t fm_l, fm_r;
int32_t cd_l, cd_r;
int32_t line_l, line_r;
int32_t mic;
int32_t speaker;
int bass_l, bass_r;
int treble_l, treble_r;
int output_selector;
#define OUTPUT_MIC 1
#define OUTPUT_CD_R 2
#define OUTPUT_CD_L 4
#define OUTPUT_LINE_R 8
#define OUTPUT_LINE_L 16
int input_selector_left;
int input_selector_right;
#define INPUT_MIC 1
#define INPUT_CD_R 2
#define INPUT_CD_L 4
#define INPUT_LINE_R 8
#define INPUT_LINE_L 16
#define INPUT_MIDI_R 32
#define INPUT_MIDI_L 64
int mic_agc;
int32_t input_gain_L;
int32_t input_gain_R;
int32_t output_gain_L;
int32_t output_gain_R;
uint8_t index;
uint8_t regs[256];
} sb_ct1745_mixer_t;
typedef struct sb_t
{
opl_t opl;
sb_dsp_t dsp;
union {
sb_ct1335_mixer_t mixer_sb2;
sb_ct1345_mixer_t mixer_sbpro;
sb_ct1745_mixer_t mixer_sb16;
};
mpu401_uart_t mpu;
emu8k_t emu8k;
int pos;
uint8_t pos_regs[8];
int opl_emu;
} sb_t;
// exported for clone cards
void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p);
void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p);
uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p);
void sb_ct1345_mixer_reset(sb_t* sb);
void sb_close(void *p);
void sb_speed_changed(void *p);
void sb_add_status_info(char *s, int max_len, void *p);
#endif /* SOUND_SB_H */

View file

@ -10,13 +10,16 @@
#include "ibm.h"
#include "device.h"
#include "dma.h"
#include "filters.h"
#include "io.h"
#include "pic.h"
#include "sound.h"
#include "sound_azt2316a.h"
#include "sound_sb_dsp.h"
#include "timer.h"
#include "x86.h"
/*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/
#define SB_DSP_REC_SAFEFTY_MARGIN 4096
@ -205,10 +208,18 @@ void sb_doreset(sb_dsp_t *dsp)
int c;
sb_dsp_reset(dsp);
if (dsp->sb_type==SB16) sb_commands[8] = 1;
else sb_commands[8] = -1;
if (IS_AZTECH(dsp))
{
sb_commands[8] = 1;
sb_commands[9] = 1;
}
else
{
if (dsp->sb_type==SB16) sb_commands[8] = 1;
else sb_commands[8] = -1;
}
for (c = 0; c < 256; c++)
dsp->sb_asp_regs[c] = 0;
dsp->sb_asp_regs[5] = 0x01;
@ -579,6 +590,20 @@ void sb_exec_command(sb_dsp_t *dsp)
sb_add_data(dsp, ~dsp->sb_data[0]);
break;
case 0xE1: /*Get DSP version*/
if (IS_AZTECH(dsp))
{
if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11)
{
sb_add_data(dsp, 0x3);
sb_add_data(dsp, 0x1);
}
else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C)
{
sb_add_data(dsp, 0x2);
sb_add_data(dsp, 0x1);
}
break;
}
sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8);
sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff);
break;
@ -617,6 +642,32 @@ void sb_exec_command(sb_dsp_t *dsp)
case 0xFF:
break;
case 0x08: /*ASP get version*/
if (IS_AZTECH(dsp))
{
if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11)
sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */
else if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C)
sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */
else if (dsp->sb_data[0] == 0x08)
{
// EEPROM address to write followed by byte
if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE)
fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]);
dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2];
break;
}
else if (dsp->sb_data[0] == 0x07)
{
// EEPROM address to read
if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE)
fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]);
sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]);
break;
}
else
pclog("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); // 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen
break;
}
if (dsp->sb_type < SB16) break;
sb_add_data(dsp, 0x18);
break;
@ -644,10 +695,26 @@ void sb_exec_command(sb_dsp_t *dsp)
case 0x04:
case 0x05:
break;
// default:
// fatal("Exec bad SB command %02X\n",sb_command);
case 0x09: /*AZTECH mode set*/
if (dsp->sb_data[0] == 0x00)
{
pclog("AZT2316A: WSS MODE!\n");
azt2316a_enable_wss(1, dsp->parent);
}
else if (dsp->sb_data[0] == 0x01)
{
pclog("AZT2316A: SB8PROV2 MODE!\n");
azt2316a_enable_wss(0, dsp->parent);
}
else
pclog("AZT2316A: UNKNOWN MODE!\n"); // sequences 0x02->0xFF, 0x04->0xFF seen
break;
case 0x38: /*TODO: AZTECH MIDI-related? */
break;
default:
fatal("Exec bad SB command %02X\n",dsp->sb_command);
/*TODO: Some more data about the DSP registeres
* http://the.earth.li/~tfm/oldpage/sb_dsp.html
* http://www.synchrondata.com/pheaven/www/area19.htm
@ -680,7 +747,7 @@ void sb_write(uint16_t a, uint8_t v, void *priv)
dsp->sbreset = v;
return;
case 0xC: /*Command/data write*/
timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1);
timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1);
if (dsp->asp_data_len)
{
// pclog("ASP data %i\n", dsp->asp_data_len);
@ -699,11 +766,27 @@ void sb_write(uint16_t a, uint8_t v, void *priv)
dsp->sb_data_stat++;
}
else
dsp->sb_data[dsp->sb_data_stat++] = v;
{
dsp->sb_data[dsp->sb_data_stat++] = v;
if (IS_AZTECH(dsp))
{
// variable length commands
if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08)
sb_commands[dsp->sb_command] = 3;
else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07)
sb_commands[dsp->sb_command] = 2;
}
}
if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1)
{
sb_exec_command(dsp);
dsp->sb_data_stat = -1;
if (IS_AZTECH(dsp))
{
// variable length commands
if (dsp->sb_command == 0x08)
sb_commands[dsp->sb_command] = 1;
}
}
break;
}
@ -732,13 +815,31 @@ uint8_t sb_read(uint16_t a, void *priv)
if (dsp->wb_full || (dsp->busy_count & 2))
{
dsp->wb_full = timer_is_enabled(&dsp->wb_timer);
return 0xff;
// pclog("SB read 0x80\n");
if (IS_AZTECH(dsp))
return 0x80;
else
return 0xFF;
}
return 0x7f;
// pclog("SB read 0x00\n");
if (IS_AZTECH(dsp))
return 0x00;
else
return 0x7F;
case 0xE: /*Read data ready*/
picintc(1 << dsp->sb_irqnum);
dsp->sb_irq8 = dsp->sb_irq16 = 0;
return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff;
// Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working.
if (IS_AZTECH(dsp))
{
// pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80);
return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80;
}
else
{
// pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF);
return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF;
}
case 0xF: /*16-bit ack*/
dsp->sb_irq16 = 0;
if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum);
@ -751,9 +852,11 @@ static void sb_wb_clear(void *p)
{
}
void sb_dsp_init(sb_dsp_t *dsp, int type)
void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent)
{
dsp->sb_type = type;
dsp->sb_subtype = subtype;
dsp->parent = parent;
// Default values. Use sb_dsp_setxxx() methods to change.
dsp->sb_irqnum = 7;

View file

@ -1,6 +1,20 @@
#ifndef SOUND_SB_DSP_H
#define SOUND_SB_DSP_H
/*Sound Blaster Clones, for quirks*/
#define SB_SUBTYPE_DEFAULT 0 /*Handle as a Creative card*/
#define SB_SUBTYPE_CLONE_AZT2316A_0X11 1 /*Aztech Sound Galaxy Pro 16 AB, DSP 3.1 - SBPRO2 clone*/
#define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /*Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone*/
// aztech-related
#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) // check for future AZT cards here
#define AZTECH_EEPROM_SIZE 16
typedef struct sb_dsp_t
{
int sb_type;
int sb_subtype; // which clone
void *parent; // "sb_t *" if default subtype, "azt2316a_t *" if aztech.
int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output;
int sb_8_dmanum;
@ -67,9 +81,11 @@ typedef struct sb_dsp_t
int16_t record_buffer[0xFFFF];
int16_t buffer[MAXSOUNDBUFLEN * 2];
int pos;
uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; // the eeprom in the Aztech cards is attached to the DSP
} sb_dsp_t;
void sb_dsp_init(sb_dsp_t *dsp, int type);
void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent);
void sb_dsp_close(sb_dsp_t *dsp);
void sb_dsp_setirq(sb_dsp_t *dsp, int irq);
@ -86,3 +102,5 @@ void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo);
void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp);
void sb_dsp_update(sb_dsp_t *dsp);
#endif /* SOUND_SB_DSP_H */

View file

@ -84,7 +84,7 @@ void *wss_init()
opl_emu = device_get_config_int("opl_emu");
opl3_init(&wss->opl, opl_emu);
ad1848_init(&wss->ad1848);
ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT);
ad1848_setirq(&wss->ad1848, 7);
ad1848_setdma(&wss->ad1848, 3);