diff --git a/src/Makefile.am b/src/Makefile.am index 8a427b3..4bf80a1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,7 +25,7 @@ linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c olivetti_m24.c opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c serial.c sis496.c sound.c \ sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \ sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \ -sound_speaker.c sound_ssi2001.c sound_wss.c soundopenal.c tandy_eeprom.c tandy_rom.c thread-pthread.c \ +sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c thread-pthread.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_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c \ vid_icd2061.c vid_ics2595.c vid_incolor.c vid_mda.c vid_olivetti_m24.c vid_oti067.c vid_paradise.c vid_pc200.c \ diff --git a/src/Makefile.mingw b/src/Makefile.mingw index e8a9be3..9812ed0 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -12,7 +12,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.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 \ - soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ + sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \ vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index 5e5de6f..d5dfcbd 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -11,7 +11,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \ serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.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_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \ vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ diff --git a/src/sound_adlibgold.c b/src/sound_adlibgold.c index 43bb9ff..c183a5a 100644 --- a/src/sound_adlibgold.c +++ b/src/sound_adlibgold.c @@ -4,6 +4,7 @@ #include "device.h" #include "sound_opl.h" +#include "sound_ym7128.h" #include "dma.h" #include "io.h" #include "pic.h" @@ -45,11 +46,14 @@ typedef struct adgold_t } adgold_mma; opl_t opl; + ym7128_t ym7128; int16_t opl_buffer[SOUNDBUFLEN * 2]; int16_t mma_buffer[2][SOUNDBUFLEN]; int pos; + + int surround_enabled; } adgold_t; void adgold_timer_poll(); @@ -74,7 +78,7 @@ void adgold_update_irq_status(adgold_t *adgold) if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) { - pclog("adgold irq %02X\n", adgold->adgold_status); +// pclog("adgold irq %02X\n", adgold->adgold_status); picint(0x80); } @@ -146,6 +150,11 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19); break; + case 0x18: /*Surround*/ + adgold->adgold_38x_regs[0x18] = val; + ym7128_write(&adgold->ym7128, val); + break; + default: adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; break; @@ -215,7 +224,7 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) if (!(adgold->adgold_mma_regs[0][0x9] & 1)) adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; - pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]); +// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]); if (adgold->adgold_mma_regs[0][0xc] & 1) { if (adgold->adgold_mma_regs[0][0xc] & 0x80) @@ -253,7 +262,7 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) } } } - pclog("adgold end\n"); +// pclog("adgold end\n"); } adgold->adgold_mma_enable[0] = val & 0x01; break; @@ -302,7 +311,7 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) if (!(adgold->adgold_mma_regs[1][0x9] & 1)) adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; - pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]); +// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]); if (adgold->adgold_mma_regs[1][0xc] & 1) { while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) @@ -310,7 +319,7 @@ void adgold_write(uint16_t addr, uint8_t val, void *p) adgold_getsamp_dma(adgold, 1); } } - pclog("adgold end\n"); +// pclog("adgold end\n"); } adgold->adgold_mma_enable[1] = val & 0x01; break; @@ -362,7 +371,10 @@ uint8_t adgold_read(uint16_t addr, void *p) switch (adgold->adgold_38x_addr) { case 0x00: /*Control/ID*/ - temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ + if (adgold->surround_enabled) + temp = 0x50; /*16-bit ISA, surround module, no telephone/CDROM*/ + else + temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ break; default: @@ -400,7 +412,7 @@ uint8_t adgold_read(uint16_t addr, void *p) temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; break; } - if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp); +// if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp); return temp; } @@ -480,7 +492,7 @@ void adgold_timer_poll(void *p) if (!adgold->adgold_mma.timer0_count) { adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; - pclog("Timer 0 interrupt\n"); +// pclog("Timer 0 interrupt\n"); adgold->adgold_mma_status |= 0x10; adgold_update_irq_status(adgold); } @@ -497,7 +509,7 @@ void adgold_timer_poll(void *p) if (!adgold->adgold_mma.timer1_count) { adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; - pclog("Timer 1 interrupt\n"); +// pclog("Timer 1 interrupt\n"); adgold->adgold_mma_status |= 0x20; adgold_update_irq_status(adgold); } @@ -508,7 +520,7 @@ void adgold_timer_poll(void *p) if (!adgold->adgold_mma.timer2_count) { adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; - pclog("Timer 2 interrupt\n"); +// pclog("Timer 2 interrupt\n"); adgold->adgold_mma_status |= 0x40; adgold_update_irq_status(adgold); } @@ -540,14 +552,24 @@ void adgold_timer_poll(void *p) static void adgold_get_buffer(int16_t *buffer, int len, void *p) { adgold_t *adgold = (adgold_t *)p; + int16_t adgold_buffer[len*2]; int c; opl3_update2(&adgold->opl); for (c = 0; c < len * 2; c++) { - buffer[c] += adgold->opl.buffer[c]; - buffer[c] += adgold->mma_buffer[c & 1][c >> 1] / 2; + adgold_buffer[c] = adgold->opl.buffer[c] / 2; + adgold_buffer[c] += adgold->mma_buffer[c & 1][c >> 1] / 4; + buffer[c] += adgold_buffer[c]; + } + + if (adgold->surround_enabled) + { + ym7128_apply(&adgold->ym7128, adgold_buffer, len); + + for (c = 0; c < len * 2; c++) + buffer[c] += adgold_buffer[c]; } adgold->opl.pos = 0; @@ -557,10 +579,22 @@ static void adgold_get_buffer(int16_t *buffer, int len, void *p) void *adgold_init() { + FILE *f; adgold_t *adgold = malloc(sizeof(adgold_t)); memset(adgold, 0, sizeof(adgold_t)); + adgold->surround_enabled = device_get_config_int("surround"); + opl3_init(&adgold->opl); + if (adgold->surround_enabled) + ym7128_init(&adgold->ym7128); + + f = romfopen("nvr/adgold.bin", "rb"); + if (f) + { + fread(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } adgold->adgold_status = 0xf; adgold->adgold_38x_addr = 0; @@ -585,11 +619,32 @@ void *adgold_init() void adgold_close(void *p) { + FILE *f; adgold_t *adgold = (adgold_t *)p; + f = romfopen("nvr/adgold.bin", "wb"); + if (f) + { + fwrite(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + free(adgold); } +static device_config_t adgold_config[] = +{ + { + .name = "surround", + .description = "Surround module", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + device_t adgold_device = { "AdLib Gold", @@ -599,5 +654,6 @@ device_t adgold_device = NULL, NULL, NULL, - NULL + NULL, + adgold_config }; diff --git a/src/sound_ym7128.c b/src/sound_ym7128.c new file mode 100644 index 0000000..f194456 --- /dev/null +++ b/src/sound_ym7128.c @@ -0,0 +1,142 @@ +#include "ibm.h" +#include "sound_ym7128.h" + +static int attenuation[32]; +static int tap_position[32]; + +void ym7128_init(ym7128_t *ym7128) +{ + int c; + double out = 65536.0; + + for (c = 0; c < 32; c++) + tap_position[c] = c * (2400 / 31); + + for (c = 31; c >= 1; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + attenuation[0] = 0; +} + +#define GET_ATTENUATION(val) (val & 0x20) ? -attenuation[val & 0x1f] : attenuation[val & 0x1f] + +void ym7128_write(ym7128_t *ym7128, uint8_t val) +{ + int new_dat = val & 1; + int new_sci = val & 2; + int new_a0 = val & 4; +// pclog("ym7128_write %i %i %i\n", new_dat, new_sci, new_a0); + if (!ym7128->sci && new_sci) + ym7128->dat = (ym7128->dat << 1) | new_dat; + + if (ym7128->a0 != new_a0) + { +// pclog("ym7128 write %i %02x\n", ym7128->a0, ym7128->dat); + if (!ym7128->a0) + ym7128->reg_sel = ym7128->dat & 0x1f; + else + { +// pclog("YM7128 write %02x %02x\n", ym7128->reg_sel, ym7128->dat); + switch (ym7128->reg_sel) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); +// pclog(" GL[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); +// pclog(" GR[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); + break; + + case 0x10: + ym7128->vm = GET_ATTENUATION(ym7128->dat); +// pclog(" VM = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x11: + ym7128->vc = GET_ATTENUATION(ym7128->dat); +// pclog(" VC = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x12: + ym7128->vl = GET_ATTENUATION(ym7128->dat); +// pclog(" VL = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x13: + ym7128->vr = GET_ATTENUATION(ym7128->dat); +// pclog(" VR = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + + case 0x14: + ym7128->c0 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c0 |= 0xfffff000; + break; + case 0x15: + ym7128->c1 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c1 |= 0xfffff000; + break; + + case 0x16: case 0x17: case 0x18: case 0x19: + case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: + ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; +// pclog(" T[%i] = %i\n", ym7128->reg_sel - 0x16, tap_position[ym7128->dat & 0x1f]); + break; + } + ym7128->regs[ym7128->reg_sel] = ym7128->dat; + } + ym7128->dat = 0; + } + + ym7128->sci = new_sci; + ym7128->a0 = new_a0; +} + +#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) + +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) +{ + int c, d; + + for (c = 0; c < len*2; c += 4) + { + /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ + int32_t samp = ((int32_t)buffer[c] + (int32_t)buffer[c+1] + (int32_t)buffer[c+2] + (int32_t)buffer[c+3]) / 4; + int32_t filter_temp, filter_out; + int32_t samp_l = 0, samp_r = 0; + + filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); + filter_out = (filter_out * ym7128->vc) >> 16; + + samp = (samp * ym7128->vm) >> 16; + samp += filter_out; + + ym7128->delay_buffer[ym7128->delay_pos] = samp; + + for (d = 0; d < 8; d++) + { + samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gl[d]) >> 16; + samp_r += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gr[d]) >> 16; + } + + samp_l = (samp_l * ym7128->vl*2) >> 16; + samp_r = (samp_r * ym7128->vr*2) >> 16; + + buffer[c] = ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2; + buffer[c+1] = ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2; + buffer[c+2] = samp_l; + buffer[c+3] = samp_r; + + ym7128->delay_pos++; + if (ym7128->delay_pos >= 2400) + ym7128->delay_pos = 0; + + ym7128->filter_dat = filter_temp; + ym7128->prev_l = samp_l; + ym7128->prev_r = samp_r; + } +} diff --git a/src/sound_ym7128.h b/src/sound_ym7128.h new file mode 100644 index 0000000..d7a5415 --- /dev/null +++ b/src/sound_ym7128.h @@ -0,0 +1,25 @@ +typedef struct ym7128_t +{ + int a0, sci; + uint8_t dat; + + int reg_sel; + uint8_t regs[32]; + + int gl[8], gr[8]; + int vm, vc, vl, vr; + int c0, c1; + int t[9]; + + int16_t filter_dat; + int16_t prev_l, prev_r; + + int16_t delay_buffer[2400]; + int delay_pos; + + int16_t last_samp; +} ym7128_t; + +void ym7128_init(ym7128_t *ym7128); +void ym7128_write(ym7128_t *ym7128, uint8_t val); +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len);