From aa7db63e86e23eab1f6a4ba418784662fdbe3c8d Mon Sep 17 00:00:00 2001 From: waltje Date: Sun, 8 Apr 2018 21:19:10 -0400 Subject: [PATCH] Sound cleanups, part 2. --- src/config.c | 12 +- src/emu.h | 5 +- src/pc.c | 5 +- src/sound/snd_cms.c | 366 +++--- src/sound/snd_dbopl.cpp | 5 +- src/sound/snd_gus.c | 2143 ++++++++++++++++++---------------- src/sound/snd_mpu401.c | 11 +- src/sound/snd_mpu401.h | 123 +- src/sound/sound.c | 9 +- src/sound/sound_dev.c | 3 +- src/win/VARCem.rc | 5 +- src/win/resource.h | 1 - src/win/win_settings.c | 8 +- src/win/win_settings_sound.h | 8 +- 14 files changed, 1397 insertions(+), 1307 deletions(-) diff --git a/src/config.c b/src/config.c index f19c6f3..f5a72f1 100644 --- a/src/config.c +++ b/src/config.c @@ -12,7 +12,7 @@ * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. * - * Version: @(#)config.c 1.0.11 2018/04/08 + * Version: @(#)config.c 1.0.12 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -69,9 +69,6 @@ #include "network/network.h" #include "sound/sound.h" #include "sound/midi.h" -#include "sound/snd_dbopl.h" -#include "sound/snd_mpu401.h" -#include "sound/snd_opl.h" #include "sound/sound.h" #include "video/video.h" #include "plat.h" @@ -627,8 +624,6 @@ load_sound(void) mpu401_standalone_enable = !!config_get_int(cat, "mpu401_standalone", 0); - GAMEBLASTER = !!config_get_int(cat, "gameblaster", 0); - memset(temp, '\0', sizeof(temp)); p = config_get_string(cat, "opl3_type", "dbopl"); strcpy(temp, p); @@ -1620,11 +1615,6 @@ save_sound(void) else config_set_int(cat, "mpu401_standalone", mpu401_standalone_enable); - if (GAMEBLASTER == 0) - config_delete_var(cat, "gameblaster"); - else - config_set_int(cat, "gameblaster", GAMEBLASTER); - if (opl3_type == 0) config_delete_var(cat, "opl3_type"); else diff --git a/src/emu.h b/src/emu.h index 7a6dd6b..ab7f5e2 100644 --- a/src/emu.h +++ b/src/emu.h @@ -8,7 +8,7 @@ * * Main include file for the application. * - * Version: @(#)emu.h 1.0.15 2018/04/08 + * Version: @(#)emu.h 1.0.16 2018/04/08 * * Author: Fred N. van Kempen, * @@ -115,7 +115,8 @@ extern int romdos_enabled; /* (C) enable ROM DOS */ #endif extern int hdc_type; /* (C) HDC type */ extern int sound_is_float, /* (C) sound uses FP values */ - GAMEBLASTER, /* (C) sound option */ + mpu401_standalone_enable, /* (C) sound option */ + opl3_type, /* (C) sound option */ voodoo_enabled; /* (C) video option */ extern int joystick_type; /* (C) joystick type */ extern int mem_size; /* (C) memory size */ diff --git a/src/pc.c b/src/pc.c index 04e9bb3..afeda89 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.21 2018/04/08 + * Version: @(#)pc.c 1.0.22 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -130,7 +130,8 @@ int romdos_enabled = 0; /* (C) enable ROM DOS */ #endif int hdc_type = 0; /* (C) HDC type */ int sound_is_float = 1, /* (C) sound uses FP values */ - GAMEBLASTER = 0, /* (C) sound option */ + mpu401_standalone_enable = 0, /* (C) sound option */ + opl3_type = 0, /* (C) sound option */ voodoo_enabled = 0; /* (C) video option */ int joystick_type = 0; /* (C) joystick type */ int mem_size = 0; /* (C) memory size */ diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 0b26d9f..803deb6 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -6,9 +6,9 @@ * * This file is part of the VARCem Project. * - * Implementation of the Create CMS/GameBlaster sound device. + * Implementation of the Creative CMS/GameBlaster sound device. * - * Version: @(#)snd_cms.c 1.0.3 2018/04/08 + * Version: @(#)snd_cms.c 1.0.4 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -47,194 +47,228 @@ #include "sound.h" -#define MASTER_CLOCK 7159090 +#define MASTER_CLOCK 7159090 -typedef struct cms_t -{ - int addrs[2]; - uint8_t regs[2][32]; - uint16_t latch[2][6]; - int freq[2][6]; - float count[2][6]; - int vol[2][6][2]; - int stat[2][6]; - uint16_t noise[2][2]; - uint16_t noisefreq[2][2]; - int noisecount[2][2]; - int noisetype[2][2]; - - uint8_t latched_data; +typedef struct { + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; - int16_t buffer[SOUNDBUFLEN * 2]; + uint8_t latched_data; - int pos; + int pos; + int16_t buffer[SOUNDBUFLEN * 2]; } cms_t; -void cms_update(cms_t *cms) -{ - for (; cms->pos < sound_pos_global; cms->pos++) - { - int c, d; - int16_t out_l = 0, out_r = 0; - for (c = 0; c < 4; c++) - { - switch (cms->noisetype[c >> 1][c & 1]) - { - case 0: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/256; break; - case 1: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/512; break; - case 2: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/1024; break; - case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; - } - } - for (c = 0; c < 2; c ++) - { - if (cms->regs[c][0x1C] & 1) - { - for (d = 0; d < 6; d++) - { - if (cms->regs[c][0x14] & (1 << d)) - { - if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90); - if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90); - cms->count[c][d] += cms->freq[c][d]; - if (cms->count[c][d] >= 24000) - { - cms->count[c][d] -= 24000; - cms->stat[c][d] ^= 1; - } - } - else if (cms->regs[c][0x15] & (1 << d)) - { - if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90); - if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90); - } - } - for (d = 0; d < 2; d++) - { - cms->noisecount[c][d] += cms->noisefreq[c][d]; - while (cms->noisecount[c][d] >= 24000) - { - cms->noisecount[c][d] -= 24000; - cms->noise[c][d] <<= 1; - if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) - cms->noise[c][d] |= 1; - } - } - } - } - cms->buffer[(cms->pos << 1)] = out_l; - cms->buffer[(cms->pos << 1) + 1] = out_r; - } +static void +cms_update(cms_t *dev) +{ + int16_t out_l = 0, out_r = 0; + int c, d; + + for (; dev->pos < sound_pos_global; dev->pos++) { + for (c = 0; c < 4; c++) { + switch (dev->noisetype[c>>1][c&1]) { + case 0: + dev->noisefreq[c>>1][c&1] = MASTER_CLOCK/256; + break; + case 1: + dev->noisefreq[c>>1][c&1] = MASTER_CLOCK/512; + break; + case 2: + dev->noisefreq[c>>1][c&1] = MASTER_CLOCK/1024; + break; + case 3: + dev->noisefreq[c>>1][c&1] = dev->freq[c>>1][(c&1) * 3]; + break; + } + } + + for (c = 0; c < 2; c ++) { + if (dev->regs[c][0x1C] & 1) { + for (d = 0; d < 6; d++) { + if (dev->regs[c][0x14] & (1 << d)) { + if (dev->stat[c][d]) + out_l += (dev->vol[c][d][0] * 90); + if (dev->stat[c][d]) + out_r += (dev->vol[c][d][1] * 90); + dev->count[c][d] += dev->freq[c][d]; + if (dev->count[c][d] >= 24000) { + dev->count[c][d] -= 24000; + dev->stat[c][d] ^= 1; + } + } else if (dev->regs[c][0x15] & (1 << d)) { + if (dev->noise[c][d / 3] & 1) + out_l += (dev->vol[c][d][0] * 90); + if (dev->noise[c][d / 3] & 1) + out_r += (dev->vol[c][d][0] * 90); + } + } + + for (d = 0; d < 2; d++) { + dev->noisecount[c][d] += dev->noisefreq[c][d]; + while (dev->noisecount[c][d] >= 24000) { + dev->noisecount[c][d] -= 24000; + dev->noise[c][d] <<= 1; + if (!(((dev->noise[c][d] & 0x4000) >> 8) ^ (dev->noise[c][d] & 0x40))) + dev->noise[c][d] |= 1; + } + } + } + } + + dev->buffer[(dev->pos << 1)] = out_l; + dev->buffer[(dev->pos << 1) + 1] = out_r; + } } -void cms_get_buffer(int32_t *buffer, int len, void *p) + +static void +get_buffer(int32_t *buffer, int len, void *priv) { - cms_t *cms = (cms_t *)p; - - int c; + cms_t *dev = (cms_t *)priv; + int c; - cms_update(cms); - - for (c = 0; c < len * 2; c++) - buffer[c] += cms->buffer[c]; + cms_update(dev); - cms->pos = 0; + for (c = 0; c < len * 2; c++) + buffer[c] += dev->buffer[c]; + + dev->pos = 0; } -void cms_write(uint16_t addr, uint8_t val, void *p) + +static void +cms_write(uint16_t addr, uint8_t val, void *priv) { - cms_t *cms = (cms_t *)p; - int voice; - int chip = (addr & 2) >> 1; - - switch (addr & 0xf) - { - case 1: - cms->addrs[0] = val & 31; - break; - case 3: - cms->addrs[1] = val & 31; - break; - - case 0: case 2: - cms_update(cms); - cms->regs[chip][cms->addrs[chip] & 31] = val; - switch (cms->addrs[chip] & 31) - { - case 0x00: case 0x01: case 0x02: /*Volume*/ - case 0x03: case 0x04: case 0x05: - voice = cms->addrs[chip] & 7; - cms->vol[chip][voice][0] = val & 0xf; - cms->vol[chip][voice][1] = val >> 4; - break; - case 0x08: case 0x09: case 0x0A: /*Frequency*/ - case 0x0B: case 0x0C: case 0x0D: - voice = cms->addrs[chip] & 7; - cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; - cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - break; - case 0x10: case 0x11: case 0x12: /*Octave*/ - voice = (cms->addrs[chip] & 3) << 1; - cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); - cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); - cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - cms->freq[chip][voice + 1] = (MASTER_CLOCK/512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); - break; - case 0x16: /*Noise*/ - cms->noisetype[chip][0] = val & 3; - cms->noisetype[chip][1] = (val >> 4) & 3; - break; - } - break; - case 0x6: case 0x7: - cms->latched_data = val; - break; - } + cms_t *dev = (cms_t *)priv; + int voice; + int chip = (addr & 2) >> 1; + + switch (addr & 0xf) { + case 1: + dev->addrs[0] = val & 31; + break; + + case 3: + dev->addrs[1] = val & 31; + break; + + case 0: + case 2: + cms_update(dev); + dev->regs[chip][dev->addrs[chip] & 31] = val; + + switch (dev->addrs[chip] & 31) { + case 0x00: case 0x01: case 0x02: /*Volume*/ + case 0x03: case 0x04: case 0x05: + voice = dev->addrs[chip] & 7; + dev->vol[chip][voice][0] = val & 0xf; + dev->vol[chip][voice][1] = val >> 4; + break; + + case 0x08: case 0x09: case 0x0A: /*Frequency*/ + case 0x0B: case 0x0C: case 0x0D: + voice = dev->addrs[chip] & 7; + dev->latch[chip][voice] = (dev->latch[chip][voice] & 0x700) | val; + dev->freq[chip][voice] = (MASTER_CLOCK/512 << (dev->latch[chip][voice] >> 8)) / (511 - (dev->latch[chip][voice] & 255)); + break; + + case 0x10: case 0x11: case 0x12: /*Octave*/ + voice = (dev->addrs[chip] & 3) << 1; + dev->latch[chip][voice] = (dev->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + dev->latch[chip][voice + 1] = (dev->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + dev->freq[chip][voice] = (MASTER_CLOCK/512 << (dev->latch[chip][voice] >> 8)) / (511 - (dev->latch[chip][voice] & 255)); + dev->freq[chip][voice + 1] = (MASTER_CLOCK/512 << (dev->latch[chip][voice + 1] >> 8)) / (511 - (dev->latch[chip][voice + 1] & 255)); + break; + + case 0x16: /*Noise*/ + dev->noisetype[chip][0] = val & 3; + dev->noisetype[chip][1] = (val >> 4) & 3; + break; + } + break; + + case 0x6: case 0x7: + dev->latched_data = val; + break; + } } -uint8_t cms_read(uint16_t addr, void *p) -{ - cms_t *cms = (cms_t *)p; - switch (addr & 0xf) - { - case 0x1: - return cms->addrs[0]; - case 0x3: - return cms->addrs[1]; - case 0x4: - return 0x7f; - case 0xa: case 0xb: - return cms->latched_data; - } - return 0xff; +static uint8_t +cms_read(uint16_t addr, void *priv) +{ + cms_t *dev = (cms_t *)priv; + uint8_t ret = 0xff; + + switch (addr & 0xf) { + case 0x1: + ret = dev->addrs[0]; + break; + + case 0x3: + ret = dev->addrs[1]; + break; + + case 0x4: + ret = 0x7f; + break; + + case 0xa: + case 0xb: + ret = dev->latched_data; + break; + + default: + break; + } + + return(ret); } -void *cms_init(const device_t *info) -{ - cms_t *cms = malloc(sizeof(cms_t)); - memset(cms, 0, sizeof(cms_t)); - pclog("cms_init\n"); - io_sethandler(0x0220, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); - sound_add_handler(cms_get_buffer, cms); - return cms; +static void * +cms_init(const device_t *info) +{ + cms_t *dev; + + dev = (cms_t *)malloc(sizeof(cms_t)); + memset(dev, 0x00, sizeof(cms_t)); + + io_sethandler(0x0220, 16, + cms_read,NULL,NULL, cms_write,NULL,NULL, dev); + + sound_add_handler(get_buffer, dev); + + return(dev); } -void cms_close(void *p) + +static void +cms_close(void *priv) { - cms_t *cms = (cms_t *)p; - - free(cms); + cms_t *dev = (cms_t *)priv; + + free(dev); } -const device_t cms_device = -{ - "Creative Music System / Game Blaster", - 0, 0, - cms_init, cms_close, NULL, - NULL, NULL, NULL, NULL, - NULL + +const device_t cms_device = { + "Creative Music System / Game Blaster", + DEVICE_ISA, + 0, + cms_init, cms_close, NULL, + NULL, NULL, NULL, NULL, + NULL }; diff --git a/src/sound/snd_dbopl.cpp b/src/sound/snd_dbopl.cpp index 95141fa..49b512f 100644 --- a/src/sound/snd_dbopl.cpp +++ b/src/sound/snd_dbopl.cpp @@ -10,7 +10,7 @@ * * NOTE: See MSC_ macros for allocation on stack. --FvK * - * Version: @(#)snd_dbopl.cpp 1.0.3 2018/02/22 + * Version: @(#)snd_dbopl.cpp 1.0.4 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -51,9 +51,6 @@ #include "snd_dbopl.h" -int opl3_type = 0; - - static struct { DBOPL::Chip chip; diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index afdab3e..1a2e78e 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -51,1055 +51,1128 @@ #include "sound.h" -typedef struct gus_t -{ - int reset; - - int global; - uint32_t addr,dmaaddr; - int voice; - uint32_t start[32],end[32],cur[32]; - uint32_t startx[32],endx[32],curx[32]; - int rstart[32],rend[32]; - int rcur[32]; - uint16_t freq[32]; - uint16_t rfreq[32]; - uint8_t ctrl[32]; - uint8_t rctrl[32]; - int curvol[32]; - int pan_l[32], pan_r[32]; - int t1on,t2on; - uint8_t tctrl; - uint16_t t1,t2,t1l,t2l; - uint8_t irqstatus,irqstatus2; - uint8_t adcommand; - int waveirqs[32],rampirqs[32]; - int voices; - uint8_t dmactrl; +typedef struct { + int reset; - int32_t out_l, out_r; - - int16_t buffer[2][SOUNDBUFLEN]; - int pos; - - int64_t samp_timer, samp_latch; - - uint8_t *ram; - - int irqnext; - - int64_t timer_1, timer_2; - - int irq, dma, irq_midi; - int latch_enable; - - uint8_t sb_2xa, sb_2xc, sb_2xe; - uint8_t sb_ctrl; - int sb_nmi; - - uint8_t reg_ctrl; - - uint8_t ad_status, ad_data; - uint8_t ad_timer_ctrl; - - uint8_t midi_ctrl, midi_status; - uint8_t midi_data; - int midi_loopback; - - uint8_t gp1, gp2; - uint16_t gp1_addr, gp2_addr; - - uint8_t usrr; + int global; + uint32_t addr, + dmaaddr; + int voice; + uint32_t start[32], + end[32], + cur[32]; + uint32_t startx[32], + endx[32], + curx[32]; + int rstart[32], + rend[32]; + int rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int pan_l[32], + pan_r[32]; + int t1on, + t2on; + uint8_t tctrl; + uint16_t t1, + t2, + t1l, + t2l; + uint8_t irqstatus, + irqstatus2; + uint8_t adcommand; + int waveirqs[32], + rampirqs[32]; + int voices; + uint8_t dmactrl; + + int32_t out_l, + out_r; + + int64_t samp_timer, + samp_latch; + + uint8_t *ram; + + int pos; + int16_t buffer[2][SOUNDBUFLEN]; + + int irqnext; + + int64_t timer_1, + timer_2; + + int irq, + dma, + irq_midi; + int latch_enable; + + uint8_t sb_2xa, + sb_2xc, + sb_2xe; + uint8_t sb_ctrl; + int sb_nmi; + + uint8_t reg_ctrl; + + uint8_t ad_status, + ad_data; + uint8_t ad_timer_ctrl; + + uint8_t midi_ctrl, + midi_status; + uint8_t midi_data; + int midi_loopback; + + uint8_t gp1, + gp2; + uint16_t gp1_addr, + gp2_addr; + + uint8_t usrr; } gus_t; -static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; -static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; -static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; -int gusfreqs[]= -{ - 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, - 23746,22866,22050,21289,20580,19916,19293 +static const int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static const int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static const int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; +static const int gusfreqs[] = { + 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, + 28063, 26843, 25725, 24696, 23746, 22866, 22050, 21289, + 20580, 19916, 19293 }; -double vol16bit[4096]; -void pollgusirqs(gus_t *gus) +static double vol16bit[4096]; + + +static void +poll_irqs(gus_t *dev) { - int c; + int c; - gus->irqstatus&=~0x60; - for (c=0;c<32;c++) - { - if (gus->waveirqs[c]) - { - gus->irqstatus2=0x60|c; - if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; - gus->irqstatus|=0x20; - if (gus->irq != -1) - picint(1 << gus->irq); - return; - } - if (gus->rampirqs[c]) - { - gus->irqstatus2=0xA0|c; - gus->irqstatus|=0x40; - if (gus->irq != -1) - picint(1 << gus->irq); - return; - } - } - gus->irqstatus2=0xE0; - if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); -} - -enum -{ - MIDI_INT_RECEIVE = 0x01, - MIDI_INT_TRANSMIT = 0x02, - MIDI_INT_MASTER = 0x80 -}; - -enum -{ - MIDI_CTRL_TRANSMIT_MASK = 0x60, - MIDI_CTRL_TRANSMIT = 0x20, - MIDI_CTRL_RECEIVE = 0x80 -}; - -enum -{ - GUS_INT_MIDI_TRANSMIT = 0x01, - GUS_INT_MIDI_RECEIVE = 0x02 -}; - -enum -{ - GUS_TIMER_CTRL_AUTO = 0x01 -}; - -void gus_midi_update_int_status(gus_t *gus) -{ - gus->midi_status &= ~MIDI_INT_MASTER; - if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) - { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; - } - else - gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; - - if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) - { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_RECEIVE; - } - else - gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; - - if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) - { - picint(1 << gus->irq_midi); - } -} - -void writegus(uint16_t addr, uint8_t val, void *p) -{ - gus_t *gus = (gus_t *)p; - int c, d; - int old; - if (gus->latch_enable && addr != 0x24b) - gus->latch_enable = 0; - switch (addr) - { - case 0x340: /*MIDI control*/ - old = gus->midi_ctrl; - gus->midi_ctrl = val; - - if ((val & 3) == 3) - gus->midi_status = 0; - else if ((old & 3) == 3) - { - gus->midi_status |= MIDI_INT_TRANSMIT; - } - gus_midi_update_int_status(gus); - break; - - case 0x341: /*MIDI data*/ - if (gus->midi_loopback) - { - gus->midi_status |= MIDI_INT_RECEIVE; - gus->midi_data = val; - } - else - gus->midi_status |= MIDI_INT_TRANSMIT; - break; - - case 0x342: /*Voice select*/ - gus->voice=val&31; - break; - case 0x343: /*Global select*/ - gus->global=val; - break; - case 0x344: /*Global low*/ - switch (gus->global) - { - case 0: /*Voice control*/ - gus->ctrl[gus->voice]=val; - break; - case 1: /*Frequency control*/ - gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val; - break; - case 2: /*Start addr high*/ - gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); - gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); - break; - case 3: /*Start addr low*/ - gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; - break; - case 4: /*End addr high*/ - gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); - gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); - break; - case 5: /*End addr low*/ - gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; - break; - - case 0x6: /*Ramp frequency*/ - gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); - break; - - case 0x9: /*Current volume*/ - gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); - break; - - case 0xA: /*Current addr high*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); -gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); - break; - case 0xB: /*Current addr low*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; - break; - - case 0x42: /*DMA address low*/ - gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4); - break; - - case 0x43: /*Address low*/ - gus->addr=(gus->addr&0xFFF00)|val; - break; - case 0x45: /*Timer control*/ - gus->tctrl=val; - break; - } - break; - case 0x345: /*Global high*/ - switch (gus->global) - { - case 0: /*Voice control*/ - if (!(val&1) && gus->ctrl[gus->voice]&1) - { - } - - gus->ctrl[gus->voice] = val & 0x7f; - - old = gus->waveirqs[gus->voice]; - gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; - if (gus->waveirqs[gus->voice] != old) - pollgusirqs(gus); - break; - case 1: /*Frequency control*/ - gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); - break; - case 2: /*Start addr high*/ - gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); - gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); - break; - case 3: /*Start addr low*/ - gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); - gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); - break; - case 4: /*End addr high*/ - gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); - gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); - break; - case 5: /*End addr low*/ - gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); - gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); - break; - - case 0x6: /*Ramp frequency*/ - gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); - break; - case 0x7: /*Ramp start*/ - gus->rstart[gus->voice] = val << 14; - break; - case 0x8: /*Ramp end*/ - gus->rend[gus->voice] = val << 14; - break; - case 0x9: /*Current volume*/ - gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); - break; - - case 0xA: /*Current addr high*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); - gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); - break; - case 0xB: /*Current addr low*/ - gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); -gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); - break; - case 0xC: /*Pan*/ - gus->pan_l[gus->voice] = 15 - (val & 0xf); - gus->pan_r[gus->voice] = (val & 0xf); - break; - case 0xD: /*Ramp control*/ - old = gus->rampirqs[gus->voice]; - gus->rctrl[gus->voice] = val & 0x7F; - gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; - if (gus->rampirqs[gus->voice] != old) - pollgusirqs(gus); - break; - - case 0xE: - gus->voices=(val&63)+1; - if (gus->voices>32) gus->voices=32; - if (gus->voices<14) gus->voices=14; - gus->global=val; - if (gus->voices < 14) - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); - else - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); - break; - - case 0x41: /*DMA*/ - if (val&1 && gus->dma != -1) - { - if (val & 2) - { - c=0; - while (c<65536) - { - int dma_result; - if (val & 0x04) - { - uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); - d = gus->ram[gus_addr] | (gus->ram[gus_addr + 1] << 8); - if (val & 0x80) - d ^= 0x8080; - dma_result = dma_channel_write(gus->dma, d); - if (dma_result == DMA_NODATA) - break; - } - else - { - d = gus->ram[gus->dmaaddr]; - if (val & 0x80) - d ^= 0x80; - dma_result = dma_channel_write(gus->dma, d); - if (dma_result == DMA_NODATA) - break; - } - gus->dmaaddr++; - gus->dmaaddr &= 0xFFFFF; - c++; - if (dma_result & DMA_OVER) - break; - } - gus->dmactrl=val&~0x40; - if (val&0x20) gus->irqnext=1; - } - else - { - c=0; - while (c<65536) - { - d = dma_channel_read(gus->dma); - if (d == DMA_NODATA) - break; - if (val & 0x04) - { - uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); - if (val & 0x80) - d ^= 0x8080; - gus->ram[gus_addr] = d & 0xff; - gus->ram[gus_addr +1] = (d >> 8) & 0xff; - } - else - { - if (val & 0x80) - d ^= 0x80; - gus->ram[gus->dmaaddr] = d; - } - gus->dmaaddr++; - gus->dmaaddr &= 0xFFFFF; - c++; - if (d & DMA_OVER) - break; - } - gus->dmactrl=val&~0x40; - if (val&0x20) gus->irqnext=1; - } - } - break; - - case 0x42: /*DMA address low*/ - gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12); - break; - - case 0x43: /*Address low*/ - gus->addr=(gus->addr&0xF00FF)|(val<<8); - break; - case 0x44: /*Address high*/ - gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000); - break; - case 0x45: /*Timer control*/ - if (!(val&4)) gus->irqstatus&=~4; - if (!(val&8)) gus->irqstatus&=~8; - if (!(val & 0x20)) - { - gus->ad_status &= ~0x18; - nmi = 0; - } - if (!(val & 0x02)) - { - gus->ad_status &= ~0x01; - nmi = 0; - } - gus->tctrl=val; - gus->sb_ctrl = val; - break; - case 0x46: /*Timer 1*/ - gus->t1 = gus->t1l = val; - gus->t1on = 1; - break; - case 0x47: /*Timer 2*/ - gus->t2 = gus->t2l = val; - gus->t2on = 1; - break; - - case 0x4c: /*Reset*/ - gus->reset = val; - break; - } - break; - case 0x347: /*DRAM access*/ - gus->ram[gus->addr]=val; - gus->addr&=0xFFFFF; - break; - case 0x248: case 0x388: - gus->adcommand = val; - break; - - case 0x389: - if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) - { - gus->ad_data = val; - gus->ad_status |= 0x01; - if (gus->sb_ctrl & 0x02) - { - if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); - } - } - else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) - { - if (val & 0x80) - { - gus->ad_status &= ~0x60; - } - else - { - gus->ad_timer_ctrl = val; - - if (val & 0x01) - gus->t1on = 1; - else - gus->t1 = gus->t1l; - - if (val & 0x02) - gus->t2on = 1; - else - gus->t2 = gus->t2l; - } - } - break; - - case 0x240: - gus->midi_loopback = val & 0x20; - gus->latch_enable = (val & 0x40) ? 2 : 1; - break; - - case 0x24b: - switch (gus->reg_ctrl & 0x07) - { - case 0: - if (gus->latch_enable == 1) - gus->dma = gus_dmas[val & 7]; - if (gus->latch_enable == 2) - { - gus->irq = gus_irqs[val & 7]; - - if (val & 0x40) - { - if (gus->irq == -1) - gus->irq = gus->irq_midi = gus_irqs[(val >> 3) & 7]; - else - gus->irq_midi = gus->irq; - } - else - gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; - - gus->sb_nmi = val & 0x80; - } - gus->latch_enable = 0; - break; - case 1: - gus->gp1 = val; - break; - case 2: - gus->gp2 = val; - break; - case 3: - gus->gp1_addr = val; - break; - case 4: - gus->gp2_addr = val; - break; - case 5: - gus->usrr = 0; - break; - case 6: - break; - } - break; - - case 0x246: - gus->ad_status |= 0x08; - if (gus->sb_ctrl & 0x20) - { - if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); - } - break; - case 0x24a: - gus->sb_2xa = val; - break; - case 0x24c: - gus->ad_status |= 0x10; - if (gus->sb_ctrl & 0x20) - { - if (gus->sb_nmi) - nmi = 1; - else if (gus->irq != -1) - picint(1 << gus->irq); - } - case 0x24d: - gus->sb_2xc = val; - break; - case 0x24e: - gus->sb_2xe = val; - break; - case 0x24f: - gus->reg_ctrl = val; - break; - } -} - -uint8_t readgus(uint16_t addr, void *p) -{ - gus_t *gus = (gus_t *)p; - uint8_t val = 0xff; - switch (addr) - { - case 0x340: /*MIDI status*/ - val = gus->midi_status; - break; - - case 0x341: /*MIDI data*/ - val = gus->midi_data; - gus->midi_status &= ~MIDI_INT_RECEIVE; - gus_midi_update_int_status(gus); - break; - - case 0x240: return 0; - case 0x246: /*IRQ status*/ - val = gus->irqstatus & ~0x10; - if (gus->ad_status & 0x19) - val |= 0x10; - return val; - - case 0x24F: return 0; - case 0x342: return gus->voice; - case 0x343: return gus->global; - case 0x344: /*Global low*/ - switch (gus->global) - { - case 0x82: /*Start addr high*/ - return gus->start[gus->voice]>>16; - case 0x83: /*Start addr low*/ - return gus->start[gus->voice]&0xFF; - - case 0x89: /*Current volume*/ - return gus->rcur[gus->voice]>>6; - case 0x8A: /*Current addr high*/ - return gus->cur[gus->voice]>>16; - case 0x8B: /*Current addr low*/ - return gus->cur[gus->voice]&0xFF; - - case 0x8F: /*IRQ status*/ - val=gus->irqstatus2; - gus->rampirqs[gus->irqstatus2&0x1F]=0; - gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); - return val; - - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - val = 0xff; - break; - } - break; - case 0x345: /*Global high*/ - switch (gus->global) - { - case 0x80: /*Voice control*/ - return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); - - case 0x82: /*Start addr high*/ - return gus->start[gus->voice]>>24; - case 0x83: /*Start addr low*/ - return gus->start[gus->voice]>>8; - - case 0x89: /*Current volume*/ - return gus->rcur[gus->voice]>>14; - - case 0x8A: /*Current addr high*/ - return gus->cur[gus->voice]>>24; - case 0x8B: /*Current addr low*/ - return gus->cur[gus->voice]>>8; - - case 0x8C: /*Pan*/ - return gus->pan_r[gus->voice]; - - case 0x8D: - return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); - - case 0x8F: /*IRQ status*/ - val=gus->irqstatus2; - gus->rampirqs[gus->irqstatus2&0x1F]=0; - gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); - return val; - - case 0x41: /*DMA control*/ - val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0); - gus->irqstatus&=~0x80; - return val; - case 0x45: /*Timer control*/ - return gus->tctrl; - case 0x49: /*Sampling control*/ - return 0; - - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - val = 0xff; - break; - } - break; - case 0x346: return 0xff; - case 0x347: /*DRAM access*/ - val=gus->ram[gus->addr]; - gus->addr&=0xFFFFF; - return val; - case 0x349: return 0; - case 0x746: /*Revision level*/ - return 0xff; /*Pre 3.7 - no mixer*/ - - case 0x24b: - switch (gus->reg_ctrl & 0x07) - { - case 1: - val = gus->gp1; - break; - case 2: - val = gus->gp2; - break; - case 3: - val = (uint8_t)(gus->gp1_addr & 0xff); - break; - case 4: - val = (uint8_t)(gus->gp2_addr & 0xff); - break; - } - break; - - case 0x24c: - val = gus->sb_2xc; - if (gus->reg_ctrl & 0x20) - gus->sb_2xc &= 0x80; - break; - case 0x24e: - return gus->sb_2xe; - - case 0x248: case 0x388: - if (gus->tctrl & GUS_TIMER_CTRL_AUTO) - val = gus->sb_2xa; - else - { - val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); - if (val & 0x60) - val |= 0x80; - } - break; - - case 0x249: - gus->ad_status &= ~0x01; - nmi = 0; - case 0x389: - val = gus->ad_data; - break; - - case 0x24A: - val = gus->adcommand; - break; - - } - return val; -} - -void gus_poll_timer_1(void *p) -{ - gus_t *gus = (gus_t *)p; - - gus->timer_1 += (TIMER_USEC * 80LL); - if (gus->t1on) - { - gus->t1++; - if (gus->t1 > 0xFF) - { - gus->t1=gus->t1l; - gus->ad_status |= 0x40; - if (gus->tctrl&4) - { - if (gus->irq != -1) - picint(1 << gus->irq); - gus->ad_status |= 0x04; - gus->irqstatus |= 0x04; - } - } - } - if (gus->irqnext) - { - gus->irqnext=0; - gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); - } - gus_midi_update_int_status(gus); -} - -void gus_poll_timer_2(void *p) -{ - gus_t *gus = (gus_t *)p; - - gus->timer_2 += (TIMER_USEC * 320LL); - if (gus->t2on) - { - gus->t2++; - if (gus->t2 > 0xFF) - { - gus->t2=gus->t2l; - gus->ad_status |= 0x20; - if (gus->tctrl&8) - { - if (gus->irq != -1) - picint(1 << gus->irq); - gus->ad_status |= 0x02; - gus->irqstatus |= 0x08; - } - } - } - if (gus->irqnext) - { - gus->irqnext=0; - gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); - } -} - -static void gus_update(gus_t *gus) -{ - for (; gus->pos < sound_pos_global; gus->pos++) - { - if (gus->out_l < -32768) - gus->buffer[0][gus->pos] = -32768; - else if (gus->out_l > 32767) - gus->buffer[0][gus->pos] = 32767; - else - gus->buffer[0][gus->pos] = gus->out_l; - if (gus->out_r < -32768) - gus->buffer[1][gus->pos] = -32768; - else if (gus->out_r > 32767) - gus->buffer[1][gus->pos] = 32767; - else - gus->buffer[1][gus->pos] = gus->out_r; - } -} - -void gus_poll_wave(void *p) -{ - gus_t *gus = (gus_t *)p; - uint32_t addr; - int d; - int16_t v; - int32_t vl; - int update_irqs = 0; - - gus_update(gus); - - gus->samp_timer += gus->samp_latch; - - gus->out_l = gus->out_r = 0; - - if ((gus->reset & 3) != 3) - return; - for (d=0;d<32;d++) - { - if (!(gus->ctrl[d] & 3)) - { - if (gus->ctrl[d] & 4) - { - addr = gus->cur[d] >> 9; - addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); - if (!(gus->freq[d] >> 10)) /*Interpolate*/ - { - vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); - vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); - v = vl >> 9; - } - else - v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); - } - else - { - if (!(gus->freq[d] >> 10)) /*Interpolate*/ - { - vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); - vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); - v = vl >> 9; - } - else - v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); - } - - if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)((float)v * 24.0 * vol16bit[4095]); - else v = (int16_t)((float)v * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]); - - gus->out_l += (v * gus->pan_l[d]) / 7; - gus->out_r += (v * gus->pan_r[d]) / 7; - - if (gus->ctrl[d]&0x40) - { - gus->cur[d] -= (gus->freq[d] >> 1); - if (gus->cur[d] <= gus->start[d]) - { - int diff = gus->start[d] - gus->cur[d]; - - if (gus->ctrl[d]&8) - { - if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); - } - else if (!(gus->rctrl[d]&4)) - { - gus->ctrl[d] |= 1; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; - } - - if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) - { - gus->waveirqs[d] = 1; - update_irqs = 1; - } - } - } - else - { - gus->cur[d] += (gus->freq[d] >> 1); - - if (gus->cur[d] >= gus->end[d]) - { - int diff = gus->cur[d] - gus->end[d]; - - if (gus->ctrl[d]&8) - { - if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); - } - else if (!(gus->rctrl[d]&4)) - { - gus->ctrl[d] |= 1; - gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; - } - - if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) - { - gus->waveirqs[d] = 1; - update_irqs = 1; - } - } - } - } - if (!(gus->rctrl[d] & 3)) - { - if (gus->rctrl[d] & 0x40) - { - gus->rcur[d] -= gus->rfreq[d]; - if (gus->rcur[d] <= gus->rstart[d]) - { - int diff = gus->rstart[d] - gus->rcur[d]; - if (!(gus->rctrl[d] & 8)) - { - gus->rctrl[d] |= 1; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; - } - else - { - if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); - } - - if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) - { - gus->rampirqs[d] = 1; - update_irqs = 1; - } - } - } - else - { - gus->rcur[d] += gus->rfreq[d]; - if (gus->rcur[d] >= gus->rend[d]) - { - int diff = gus->rcur[d] - gus->rend[d]; - if (!(gus->rctrl[d] & 8)) - { - gus->rctrl[d] |= 1; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; - } - else - { - if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; - gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); - } - - if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) - { - gus->rampirqs[d] = 1; - update_irqs = 1; - } - } - } - } - } - - if (update_irqs) - pollgusirqs(gus); -} - -static void gus_get_buffer(int32_t *buffer, int len, void *p) -{ - gus_t *gus = (gus_t *)p; - int c; - - gus_update(gus); - - for (c = 0; c < len * 2; c++) - { - buffer[c] += (int32_t)gus->buffer[c & 1][c >> 1]; - } - - gus->pos = 0; -} - - -void *gus_init(const device_t *info) -{ - int c; - double out = 1.0; - gus_t *gus = malloc(sizeof(gus_t)); - memset(gus, 0, sizeof(gus_t)); - - gus->ram = malloc(1 << 20); - memset(gus->ram, 0, 1 << 20); - - pclog("gus_init\n"); - - for (c=0;c<32;c++) - { - gus->ctrl[c]=1; - gus->rctrl[c]=1; - gus->rfreq[c]=63*512; - } - - for (c=4095;c>=0;c--) { - vol16bit[c]=out; - out/=1.002709201; /* 0.0235 dB Steps */ + dev->irqstatus &= ~0x60; + for (c = 0; c < 32; c++) { + if (dev->waveirqs[c]) { + dev->irqstatus2 = 0x60 | c; + if (dev->rampirqs[c]) + dev->irqstatus2 |= 0x80; + dev->irqstatus |= 0x20; + if (dev->irq != -1) + picint(1 << dev->irq); + return; } - pclog("GUS: top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); - gus->voices=14; + if (dev->rampirqs[c]) { + dev->irqstatus2 = 0xA0 | c; + dev->irqstatus |= 0x40; + if (dev->irq != -1) + picint(1 << dev->irq); + return; + } + } - gus->samp_timer = gus->samp_latch = (int64_t)(TIMER_USEC * (1000000.0 / 44100.0)); + dev->irqstatus2 = 0xE0; - gus->t1l = gus->t2l = 0xff; - - io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); - timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus); - timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus); - timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus); - - sound_add_handler(gus_get_buffer, gus); - - return gus; + if (!dev->irqstatus && dev->irq != -1) + picintc(1 << dev->irq); } -void gus_close(void *p) -{ - gus_t *gus = (gus_t *)p; - - free(gus->ram); - free(gus); -} -void gus_speed_changed(void *p) -{ - gus_t *gus = (gus_t *)p; - - if (gus->voices < 14) - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); - else - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); -} - -const device_t gus_device = -{ - "Gravis UltraSound", - 0, 0, - gus_init, gus_close, NULL, NULL, - gus_speed_changed, NULL, NULL, - NULL +enum { + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum { + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum { + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum { + GUS_TIMER_CTRL_AUTO = 0x01 +}; + + +static void +midi_update_int_status(gus_t *dev) +{ + dev->midi_status &= ~MIDI_INT_MASTER; + + if ((dev->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (dev->midi_status & MIDI_INT_TRANSMIT)) { + dev->midi_status |= MIDI_INT_MASTER; + dev->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } else + dev->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; + + if ((dev->midi_ctrl & MIDI_CTRL_RECEIVE) && (dev->midi_status & MIDI_INT_RECEIVE)) { + dev->midi_status |= MIDI_INT_MASTER; + dev->irqstatus |= GUS_INT_MIDI_RECEIVE; + } else + dev->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + if ((dev->midi_status & MIDI_INT_MASTER) && (dev->irq_midi != -1)) { + picint(1 << dev->irq_midi); + } +} + + +static void +gus_write(uint16_t addr, uint8_t val, void *priv) +{ + gus_t *dev = (gus_t *)priv; + int c, d; + int old; + + if (dev->latch_enable && addr != 0x24b) + dev->latch_enable = 0; + + switch (addr) { + case 0x340: /*MIDI control*/ + old = dev->midi_ctrl; + dev->midi_ctrl = val; + + if ((val & 3) == 3) + dev->midi_status = 0; + else if ((old & 3) == 3) + dev->midi_status |= MIDI_INT_TRANSMIT; + midi_update_int_status(dev); + break; + + case 0x341: /*MIDI data*/ + if (dev->midi_loopback) { + dev->midi_status |= MIDI_INT_RECEIVE; + dev->midi_data = val; + } else + dev->midi_status |= MIDI_INT_TRANSMIT; + break; + + case 0x342: /*Voice select*/ + dev->voice = val & 31; + break; + + case 0x343: /*Global select*/ + dev->global = val; + break; + + case 0x344: /*Global low*/ + switch (dev->global) { + case 0: /*Voice control*/ + dev->ctrl[dev->voice] = val; + break; + + case 1: /*Frequency control*/ + dev->freq[dev->voice] = (dev->freq[dev->voice]&0xFF00)|val; + break; + + case 2: /*Start addr high*/ + dev->startx[dev->voice] = (dev->startx[dev->voice]&0xF807F)|(val<<7); + dev->start[dev->voice] = (dev->start[dev->voice]&0x1F00FFFF)|(val<<16); + break; + + case 3: /*Start addr low*/ + dev->start[dev->voice] = (dev->start[dev->voice]&0x1FFFFF00)|val; + break; + + case 4: /*End addr high*/ + dev->endx[dev->voice] = (dev->endx[dev->voice]&0xF807F)|(val<<7); + dev->end[dev->voice] = (dev->end[dev->voice]&0x1F00FFFF)|(val<<16); + break; + + case 5: /*End addr low*/ + dev->end[dev->voice] = (dev->end[dev->voice]&0x1FFFFF00)|val; + break; + + case 0x6: /*Ramp frequency*/ + dev->rfreq[dev->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); + break; + + case 0x9: /*Current volume*/ + dev->curvol[dev->voice] = dev->rcur[dev->voice] = (dev->rcur[dev->voice] & ~(0xff << 6)) | (val << 6); + break; + + case 0xA: /*Current addr high*/ + dev->cur[dev->voice] = (dev->cur[dev->voice]&0x1F00FFFF)|(val<<16); + dev->curx[dev->voice] = (dev->curx[dev->voice]&0xF807F00)|((val<<7)<<8); + break; + + case 0xB: /*Current addr low*/ + dev->cur[dev->voice] = (dev->cur[dev->voice]&0x1FFFFF00)|val; + break; + + case 0x42: /*DMA address low*/ + dev->dmaaddr = (dev->dmaaddr&0xFF000)|(val<<4); + break; + + case 0x43: /*Address low*/ + dev->addr = (dev->addr&0xFFF00)|val; + break; + + case 0x45: /*Timer control*/ + dev->tctrl = val; + break; + } + break; + + case 0x345: /*Global high*/ + switch (dev->global) { + case 0: /*Voice control*/ + if (!(val&1) && dev->ctrl[dev->voice]&1) { + } + + dev->ctrl[dev->voice] = val & 0x7f; + + old = dev->waveirqs[dev->voice]; + dev->waveirqs[dev->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (dev->waveirqs[dev->voice] != old) + poll_irqs(dev); + break; + + case 1: /*Frequency control*/ + dev->freq[dev->voice] = (dev->freq[dev->voice]&0xFF)|(val<<8); + break; + + case 2: /*Start addr high*/ + dev->startx[dev->voice] = (dev->startx[dev->voice]&0x07FFF)|(val<<15); + dev->start[dev->voice] = (dev->start[dev->voice]&0x00FFFFFF)|((val&0x1F)<<24); + break; + + case 3: /*Start addr low*/ + dev->startx[dev->voice] = (dev->startx[dev->voice]&0xFFF80)|(val&0x7F); + dev->start[dev->voice] = (dev->start[dev->voice]&0x1FFF00FF)|(val<<8); + break; + + case 4: /*End addr high*/ + dev->endx[dev->voice] = (dev->endx[dev->voice]&0x07FFF)|(val<<15); + dev->end[dev->voice] = (dev->end[dev->voice]&0x00FFFFFF)|((val&0x1F)<<24); + break; + + case 5: /*End addr low*/ + dev->endx[dev->voice] = (dev->endx[dev->voice]&0xFFF80)|(val&0x7F); + dev->end[dev->voice] = (dev->end[dev->voice]&0x1FFF00FF)|(val<<8); + break; + + case 0x6: /*Ramp frequency*/ + dev->rfreq[dev->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); + break; + + case 0x7: /*Ramp start*/ + dev->rstart[dev->voice] = val << 14; + break; + + case 0x8: /*Ramp end*/ + dev->rend[dev->voice] = val << 14; + break; + + case 0x9: /*Current volume*/ + dev->curvol[dev->voice] = dev->rcur[dev->voice] = (dev->rcur[dev->voice] & ~(0xff << 14)) | (val << 14); + break; + + case 0xA: /*Current addr high*/ + dev->cur[dev->voice] = (dev->cur[dev->voice]&0x00FFFFFF)|((val&0x1F)<<24); + dev->curx[dev->voice] = (dev->curx[dev->voice]&0x07FFF00)|((val<<15)<<8); + break; + + case 0xB: /*Current addr low*/ + dev->cur[dev->voice] = (dev->cur[dev->voice]&0x1FFF00FF)|(val<<8); + dev->curx[dev->voice] = (dev->curx[dev->voice]&0xFFF8000)|((val&0x7F)<<8); + break; + + case 0xC: /*Pan*/ + dev->pan_l[dev->voice] = 15 - (val & 0xf); + dev->pan_r[dev->voice] = (val & 0xf); + break; + + case 0xD: /*Ramp control*/ + old = dev->rampirqs[dev->voice]; + dev->rctrl[dev->voice] = val & 0x7F; + dev->rampirqs[dev->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (dev->rampirqs[dev->voice] != old) + poll_irqs(dev); + break; + + case 0xE: + dev->voices = (val & 63) + 1; + if (dev->voices>32) dev->voices = 32; + if (dev->voices<14) dev->voices = 14; + dev->global = val; + if (dev->voices < 14) + dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[dev->voices - 14])); + break; + + case 0x41: /*DMA*/ + if (val&1 && dev->dma != -1) { + if (val & 2) { + c = 0; + while (c < 65536) { + int dma_result; + + if (val & 0x04) { + uint32_t gus_addr = (dev->dmaaddr & 0xc0000) | ((dev->dmaaddr & 0x1ffff) << 1); + d = dev->ram[gus_addr] | (dev->ram[gus_addr + 1] << 8); + if (val & 0x80) + d ^= 0x8080; + dma_result = dma_channel_write(dev->dma, d); + if (dma_result == DMA_NODATA) + break; + } else { + d = dev->ram[dev->dmaaddr]; + if (val & 0x80) + d ^= 0x80; + dma_result = dma_channel_write(dev->dma, d); + if (dma_result == DMA_NODATA) + break; + } + dev->dmaaddr++; + dev->dmaaddr &= 0xFFFFF; + c++; + if (dma_result & DMA_OVER) + break; + } + dev->dmactrl = val & ~0x40; + if (val & 0x20) + dev->irqnext = 1; + } else { + c = 0; + while (c < 65536) { + d = dma_channel_read(dev->dma); + if (d == DMA_NODATA) + break; + if (val & 0x04) { + uint32_t gus_addr = (dev->dmaaddr & 0xc0000) | ((dev->dmaaddr & 0x1ffff) << 1); + if (val & 0x80) + d ^= 0x8080; + dev->ram[gus_addr] = d & 0xff; + dev->ram[gus_addr +1] = (d >> 8) & 0xff; + } else { + if (val & 0x80) + d ^= 0x80; + dev->ram[dev->dmaaddr] = d; + } + dev->dmaaddr++; + dev->dmaaddr &= 0xFFFFF; + c++; + if (d & DMA_OVER) + break; + } + dev->dmactrl = val & ~0x40; + if (val & 0x20) + dev->irqnext = 1; + } + } + break; + + case 0x42: /*DMA address low*/ + dev->dmaaddr = (dev->dmaaddr&0xFF0)|(val<<12); + break; + + case 0x43: /*Address low*/ + dev->addr = (dev->addr&0xF00FF)|(val<<8); + break; + + case 0x44: /*Address high*/ + dev->addr = (dev->addr&0xFFFF)|((val<<16)&0xF0000); + break; + + case 0x45: /*Timer control*/ + if (! (val & 4)) dev->irqstatus &= ~4; + if (! (val & 8)) dev->irqstatus &= ~8; + if (! (val & 0x20)) { + dev->ad_status &= ~0x18; + nmi = 0; + } + if (! (val & 0x02)) { + dev->ad_status &= ~0x01; + nmi = 0; + } + dev->tctrl = val; + dev->sb_ctrl = val; + break; + + case 0x46: /*Timer 1*/ + dev->t1 = dev->t1l = val; + dev->t1on = 1; + break; + + case 0x47: /*Timer 2*/ + dev->t2 = dev->t2l = val; + dev->t2on = 1; + break; + + case 0x4c: /*Reset*/ + dev->reset = val; + break; + } + break; + + case 0x347: /*DRAM access*/ + dev->ram[dev->addr] = val; + dev->addr &= 0xFFFFF; + break; + + case 0x248: + case 0x388: + dev->adcommand = val; + break; + + case 0x389: + if ((dev->tctrl & GUS_TIMER_CTRL_AUTO) || dev->adcommand != 4) { + dev->ad_data = val; + dev->ad_status |= 0x01; + if (dev->sb_ctrl & 0x02) { + if (dev->sb_nmi) + nmi = 1; + else if (dev->irq != -1) + picint(1 << dev->irq); + } + } else if (!(dev->tctrl & GUS_TIMER_CTRL_AUTO) && dev->adcommand == 4) { + if (val & 0x80) { + dev->ad_status &= ~0x60; + } else { + dev->ad_timer_ctrl = val; + + if (val & 0x01) + dev->t1on = 1; + else + dev->t1 = dev->t1l; + + if (val & 0x02) + dev->t2on = 1; + else + dev->t2 = dev->t2l; + } + } + break; + + case 0x240: + dev->midi_loopback = val & 0x20; + dev->latch_enable = (val & 0x40) ? 2 : 1; + break; + + case 0x24b: + switch (dev->reg_ctrl & 0x07) { + case 0: + if (dev->latch_enable == 1) + dev->dma = gus_dmas[val & 7]; + if (dev->latch_enable == 2) { + dev->irq = gus_irqs[val & 7]; + + if (val & 0x40) { + if (dev->irq == -1) + dev->irq = dev->irq_midi = gus_irqs[(val >> 3) & 7]; + else + dev->irq_midi = dev->irq; + } else + dev->irq_midi = gus_irqs_midi[(val >> 3) & 7]; + + dev->sb_nmi = val & 0x80; + } + dev->latch_enable = 0; + break; + + case 1: + dev->gp1 = val; + break; + + case 2: + dev->gp2 = val; + break; + + case 3: + dev->gp1_addr = val; + break; + + case 4: + dev->gp2_addr = val; + break; + + case 5: + dev->usrr = 0; + break; + + case 6: + break; + } + break; + + case 0x246: + dev->ad_status |= 0x08; + if (dev->sb_ctrl & 0x20) { + if (dev->sb_nmi) + nmi = 1; + else if (dev->irq != -1) + picint(1 << dev->irq); + } + break; + + case 0x24a: + dev->sb_2xa = val; + break; + + case 0x24c: + dev->ad_status |= 0x10; + if (dev->sb_ctrl & 0x20) { + if (dev->sb_nmi) + nmi = 1; + else if (dev->irq != -1) + picint(1 << dev->irq); + } + /*FALLTHOUGH*/ + + case 0x24d: + dev->sb_2xc = val; + break; + + case 0x24e: + dev->sb_2xe = val; + break; + + case 0x24f: + dev->reg_ctrl = val; + break; + } +} + + +static uint8_t +gus_read(uint16_t addr, void *priv) +{ + gus_t *dev = (gus_t *)priv; + uint8_t val = 0xff; + + switch (addr) { + case 0x340: /*MIDI status*/ + val = dev->midi_status; + break; + + case 0x341: /*MIDI data*/ + val = dev->midi_data; + dev->midi_status &= ~MIDI_INT_RECEIVE; + midi_update_int_status(dev); + break; + + case 0x240: + val = 0x00; + break; + + case 0x246: /*IRQ status*/ + val = dev->irqstatus & ~0x10; + if (dev->ad_status & 0x19) + val |= 0x10; + break; + + case 0x24F: + val = 0x00; + break; + + case 0x342: + val = dev->voice; + break; + + case 0x343: + val = dev->global; + break; + + case 0x344: /*Global low*/ + switch (dev->global) { + case 0x82: /*Start addr high*/ + val = dev->start[dev->voice]>>16; + break; + + case 0x83: /*Start addr low*/ + val = dev->start[dev->voice]&0xFF; + break; + + case 0x89: /*Current volume*/ + val = dev->rcur[dev->voice]>>6; + break; + + case 0x8A: /*Current addr high*/ + val = dev->cur[dev->voice]>>16; + break; + + case 0x8B: /*Current addr low*/ + val = dev->cur[dev->voice]&0xFF; + break; + + case 0x8F: /*IRQ status*/ + val = dev->irqstatus2; + dev->rampirqs[dev->irqstatus2 & 0x1F] = 0; + dev->waveirqs[dev->irqstatus2 & 0x1F] = 0; + poll_irqs(dev); + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + } + break; + + case 0x345: /*Global high*/ + switch (dev->global) { + case 0x80: /*Voice control*/ + val = dev->ctrl[dev->voice]|(dev->waveirqs[dev->voice]?0x80:0); + break; + + case 0x82: /*Start addr high*/ + val = dev->start[dev->voice]>>24; + break; + + case 0x83: /*Start addr low*/ + val = dev->start[dev->voice]>>8; + break; + + case 0x89: /*Current volume*/ + val = dev->rcur[dev->voice]>>14; + break; + + case 0x8A: /*Current addr high*/ + val = dev->cur[dev->voice]>>24; + break; + + case 0x8B: /*Current addr low*/ + val = dev->cur[dev->voice]>>8; + break; + + case 0x8C: /*Pan*/ + val = dev->pan_r[dev->voice]; + break; + + case 0x8D: + val = dev->rctrl[dev->voice]|(dev->rampirqs[dev->voice]?0x80:0); + break; + + case 0x8F: /*IRQ status*/ + val = dev->irqstatus2; + dev->rampirqs[dev->irqstatus2&0x1F] = 0; + dev->waveirqs[dev->irqstatus2&0x1F] = 0; + poll_irqs(dev); + break; + + case 0x41: /*DMA control*/ + val = dev->dmactrl|((dev->irqstatus&0x80)?0x40:0); + dev->irqstatus &= ~0x80; + break; + + case 0x45: /*Timer control*/ + val = dev->tctrl; + break; + + case 0x49: /*Sampling control*/ + val = 0x00; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + } + break; + + case 0x346: + val = 0xff; + break; + + case 0x347: /*DRAM access*/ + val = dev->ram[dev->addr]; + dev->addr &= 0xFFFFF; + break; + + case 0x349: + val = 0x00; + break; + + case 0x746: /*Revision level*/ + val = 0xff; /*Pre 3.7 - no mixer*/ + break; + + case 0x24b: + switch (dev->reg_ctrl & 0x07) { + case 1: + val = dev->gp1; + break; + + case 2: + val = dev->gp2; + break; + + case 3: + val = (uint8_t)(dev->gp1_addr & 0xff); + break; + + case 4: + val = (uint8_t)(dev->gp2_addr & 0xff); + break; + } + break; + + case 0x24c: + val = dev->sb_2xc; + if (dev->reg_ctrl & 0x20) + dev->sb_2xc &= 0x80; + break; + + case 0x24e: + val = dev->sb_2xe; + break; + + case 0x248: + case 0x388: + if (dev->tctrl & GUS_TIMER_CTRL_AUTO) + val = dev->sb_2xa; + else { + val = dev->ad_status & ~(dev->ad_timer_ctrl & 0x60); + if (val & 0x60) + val |= 0x80; + } + break; + + case 0x249: + dev->ad_status &= ~0x01; + nmi = 0; + /*FALLTHROUGH?*/ + + case 0x389: + val = dev->ad_data; + break; + + case 0x24A: + val = dev->adcommand; + break; + + } + + return(val); +} + + +static void +poll_timer_1(void *priv) +{ + gus_t *dev = (gus_t *)priv; + + dev->timer_1 += (TIMER_USEC * 80LL); + if (dev->t1on) { + dev->t1++; + if (dev->t1 > 0xFF) { + dev->t1 = dev->t1l; + dev->ad_status |= 0x40; + if (dev->tctrl & 4) { + if (dev->irq != -1) + picint(1 << dev->irq); + dev->ad_status |= 0x04; + dev->irqstatus |= 0x04; + } + } + } + + if (dev->irqnext) { + dev->irqnext = 0; + dev->irqstatus |= 0x80; + if (dev->irq != -1) + picint(1 << dev->irq); + } + + midi_update_int_status(dev); +} + + +static void +poll_timer_2(void *priv) +{ + gus_t *dev = (gus_t *)priv; + + dev->timer_2 += (TIMER_USEC * 320LL); + if (dev->t2on) { + dev->t2++; + if (dev->t2 > 0xFF) { + dev->t2 = dev->t2l; + dev->ad_status |= 0x20; + if (dev->tctrl & 8) { + if (dev->irq != -1) + picint(1 << dev->irq); + dev->ad_status |= 0x02; + dev->irqstatus |= 0x08; + } + } + } + + if (dev->irqnext) { + dev->irqnext = 0; + dev->irqstatus |= 0x80; + if (dev->irq != -1) + picint(1 << dev->irq); + } +} + + +static void +gus_update(gus_t *dev) +{ + for (; dev->pos < sound_pos_global; dev->pos++) { + if (dev->out_l < -32768) + dev->buffer[0][dev->pos] = -32768; + else if (dev->out_l > 32767) + dev->buffer[0][dev->pos] = 32767; + else + dev->buffer[0][dev->pos] = dev->out_l; + if (dev->out_r < -32768) + dev->buffer[1][dev->pos] = -32768; + else if (dev->out_r > 32767) + dev->buffer[1][dev->pos] = 32767; + else + dev->buffer[1][dev->pos] = dev->out_r; + } +} + + +static void +poll_wave(void *priv) +{ + gus_t *dev = (gus_t *)priv; + uint32_t addr; + int d; + int16_t v; + int32_t vl; + int update_irqs = 0; + + gus_update(dev); + + dev->samp_timer += dev->samp_latch; + + dev->out_l = dev->out_r = 0; + + if ((dev->reset & 3) != 3) + return; + + for (d = 0; d < 32; d++) { + if (! (dev->ctrl[d] & 3)) { + if (dev->ctrl[d] & 4) { + addr = dev->cur[d] >> 9; + addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); + + if (! (dev->freq[d] >> 10)) { /*Interpolate*/ + vl = (int16_t)(int8_t)((dev->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (dev->cur[d] & 511)); + vl += (int16_t)(int8_t)((dev->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (dev->cur[d] & 511); + v = vl >> 9; + } else + v = (int16_t)(int8_t)((dev->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); + } else { + if (! (dev->freq[d] >> 10)) { /*Interpolate*/ + vl = ((int8_t)((dev->ram[(dev->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (dev->cur[d] & 511)); + vl += ((int8_t)((dev->ram[((dev->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (dev->cur[d] & 511); + v = vl >> 9; + } else + v = (int16_t)(int8_t)((dev->ram[(dev->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); + } + + if ((dev->rcur[d] >> 14) > 4095) + v = (int16_t)((float)v * 24.0 * vol16bit[4095]); + else + v = (int16_t)((float)v * 24.0 * vol16bit[(dev->rcur[d]>>10) & 4095]); + + dev->out_l += (v * dev->pan_l[d]) / 7; + dev->out_r += (v * dev->pan_r[d]) / 7; + + if (dev->ctrl[d] & 0x40) { + dev->cur[d] -= (dev->freq[d] >> 1); + if (dev->cur[d] <= dev->start[d]) { + int diff = dev->start[d] - dev->cur[d]; + + if (dev->ctrl[d] & 8) { + if (dev->ctrl[d]&0x10) + dev->ctrl[d]^=0x40; + dev->cur[d] = (dev->ctrl[d] & 0x40) ? (dev->end[d] - diff) : (dev->start[d] + diff); + } else if (! (dev->rctrl[d] & 4)) { + dev->ctrl[d] |= 1; + dev->cur[d] = (dev->ctrl[d] & 0x40) ? dev->end[d] : dev->start[d]; + } + + if ((dev->ctrl[d] & 0x20) && !dev->waveirqs[d]) { + dev->waveirqs[d] = 1; + update_irqs = 1; + } + } + } else { + dev->cur[d] += (dev->freq[d] >> 1); + + if (dev->cur[d] >= dev->end[d]) { + int diff = dev->cur[d] - dev->end[d]; + + if (dev->ctrl[d] & 8) { + if (dev->ctrl[d]&0x10) + dev->ctrl[d]^=0x40; + dev->cur[d] = (dev->ctrl[d] & 0x40) ? (dev->end[d] - diff) : (dev->start[d] + diff); + } else if (! (dev->rctrl[d] & 4)) { + dev->ctrl[d] |= 1; + dev->cur[d] = (dev->ctrl[d] & 0x40) ? dev->end[d] : dev->start[d]; + } + + if ((dev->ctrl[d] & 0x20) && !dev->waveirqs[d]) { + dev->waveirqs[d] = 1; + update_irqs = 1; + } + } + } + } + + if (! (dev->rctrl[d] & 3)) { + if (dev->rctrl[d] & 0x40) { + dev->rcur[d] -= dev->rfreq[d]; + if (dev->rcur[d] <= dev->rstart[d]) { + int diff = dev->rstart[d] - dev->rcur[d]; + + if (! (dev->rctrl[d] & 8)) { + dev->rctrl[d] |= 1; + dev->rcur[d] = (dev->rctrl[d] & 0x40) ? dev->rstart[d] : dev->rend[d]; + } else { + if (dev->rctrl[d] & 0x10) + dev->rctrl[d] ^= 0x40; + dev->rcur[d] = (dev->rctrl[d] & 0x40) ? (dev->rend[d] - diff) : (dev->rstart[d] + diff); + } + + if ((dev->rctrl[d] & 0x20) && !dev->rampirqs[d]) { + dev->rampirqs[d] = 1; + update_irqs = 1; + } + } + } else { + dev->rcur[d] += dev->rfreq[d]; + if (dev->rcur[d] >= dev->rend[d]) { + int diff = dev->rcur[d] - dev->rend[d]; + + if (! (dev->rctrl[d] & 8)) { + dev->rctrl[d] |= 1; + dev->rcur[d] = (dev->rctrl[d] & 0x40) ? dev->rstart[d] : dev->rend[d]; + } else { + if (dev->rctrl[d] & 0x10) + dev->rctrl[d] ^= 0x40; + dev->rcur[d] = (dev->rctrl[d] & 0x40) ? (dev->rend[d] - diff) : (dev->rstart[d] + diff); + } + + if ((dev->rctrl[d] & 0x20) && !dev->rampirqs[d]) { + dev->rampirqs[d] = 1; + update_irqs = 1; + } + } + } + } + } + + if (update_irqs) + poll_irqs(dev); +} + + +static void +get_buffer(int32_t *buffer, int len, void *priv) +{ + gus_t *dev = (gus_t *)priv; + int c; + + gus_update(dev); + + for (c = 0; c < len * 2; c++) + buffer[c] += (int32_t)dev->buffer[c & 1][c >> 1]; + + dev->pos = 0; +} + + +static void * +gus_init(const device_t *info) +{ + int c; + double out = 1.0; + gus_t *dev = malloc(sizeof(gus_t)); + + memset(dev, 0x00, sizeof(gus_t)); + + dev->ram = malloc(1 << 20); + memset(dev->ram, 0x00, 1 << 20); + + for (c = 0; c < 32; c++) { + dev->ctrl[c] = 1; + dev->rctrl[c] = 1; + dev->rfreq[c] = 63*512; + } + + for (c = 4095; c >= 0; c--) { + vol16bit[c] = out; + out /= 1.002709201; /* 0.0235 dB Steps */ + } + +// pclog("GUS: top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); + dev->voices=14; + + dev->samp_timer = dev->samp_latch = (int64_t)(TIMER_USEC * (1000000.0 / 44100.0)); + + dev->t1l = dev->t2l = 0xff; + + io_sethandler(0x0240, 16, + gus_read,NULL,NULL, gus_write,NULL,NULL, dev); + io_sethandler(0x0340, 16, + gus_read,NULL,NULL, gus_write,NULL,NULL, dev); + io_sethandler(0x0746, 1, + gus_read,NULL,NULL, gus_write,NULL,NULL, dev); + io_sethandler(0x0388, 2, + gus_read,NULL,NULL, gus_write,NULL,NULL, dev); + + timer_add(poll_wave, &dev->samp_timer, TIMER_ALWAYS_ENABLED, dev); + timer_add(poll_timer_1, &dev->timer_1, TIMER_ALWAYS_ENABLED, dev); + timer_add(poll_timer_2, &dev->timer_2, TIMER_ALWAYS_ENABLED, dev); + + sound_add_handler(get_buffer, dev); + + return(dev); +} + + +static void +gus_close(void *priv) +{ + gus_t *dev = (gus_t *)priv; + + free(dev->ram); + + free(dev); +} + + +static void +speed_changed(void *priv) +{ + gus_t *dev = (gus_t *)priv; + + if (dev->voices < 14) + dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[dev->voices - 14])); +} + + +const device_t gus_device = { + "Gravis UltraSound", + DEVICE_ISA, + 0, + gus_init, gus_close, NULL, NULL, + speed_changed, NULL, NULL, + NULL }; diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 93a406d..fcfadfa 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -8,7 +8,7 @@ * * Roland MPU-401 emulation. * - * Version: @(#)snd_mpu401.c 1.0.4 2018/04/02 + * Version: @(#)snd_mpu401.c 1.0.5 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -62,16 +62,15 @@ enum { }; -int mpu401_standalone_enable = 0; +#ifdef ENABLE_SOUND_MPU401_LOG +int sound_mpu401_do_log = ENABLE_SOUND_MPU401_LOG; +#endif + static int64_t mpu401_event_callback = 0LL; static int64_t mpu401_eoi_callback = 0LL; static int64_t mpu401_reset_callback = 0LL; -#ifdef ENABLE_SOUND_MPU401_LOG -int sound_mpu401_do_log = ENABLE_SOUND_MPU401_LOG; -#endif - static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); static void MPU401_EOIHandlerDispatch(void *p); diff --git a/src/sound/snd_mpu401.h b/src/sound/snd_mpu401.h index 3295361..46cdf6c 100644 --- a/src/sound/snd_mpu401.h +++ b/src/sound/snd_mpu401.h @@ -8,7 +8,7 @@ * * Roland MPU-401 emulation. * - * Version: @(#)snd_mpu401.h 1.0.2 2018/03/15 + * Version: @(#)snd_mpu401.h 1.0.3 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -43,14 +43,25 @@ # define SOUND_MPU401_H -#define MPU401_VERSION 0x15 -#define MPU401_REVISION 0x01 -#define MPU401_QUEUE 32 -#define MPU401_TIMECONSTANT (60000000/1000.0f) -#define MPU401_RESETBUSY 27.0f +#define MPU401_VERSION 0x15 +#define MPU401_REVISION 0x01 +#define MPU401_QUEUE 32 +#define MPU401_TIMECONSTANT (60000000/1000.0f) +#define MPU401_RESETBUSY 27.0f + +typedef enum { + M_UART, + M_INTELLIGENT +} MpuMode; + +typedef enum { + T_OVERFLOW, + T_MARK, + T_MIDI_SYS, + T_MIDI_NORM, + T_COMMAND +} MpuDataType; -typedef enum MpuMode { M_UART,M_INTELLIGENT } MpuMode; -typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} MpuDataType; /* Messages sent to MPU-401 from host */ #define MSG_EOX 0xf7 @@ -64,57 +75,61 @@ typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} Mp #define MSG_MPU_CLOCK 0xfd #define MSG_MPU_ACK 0xfe -typedef struct mpu_t -{ - int uart_mode; - uint8_t rx_data; - int intelligent; - MpuMode mode; - int irq; - uint8_t status; - uint8_t queue[MPU401_QUEUE]; - int queue_pos,queue_used; - struct track - { - int counter; - uint8_t value[8],sys_val; - uint8_t vlength,length; - MpuDataType type; - } playbuf[8],condbuf; - struct { - int conductor,cond_req,cond_set, block_ack; - int playing,reset; - int wsd,wsm,wsd_start; - int run_irq,irq_pending; - int send_now; - int eoi_scheduled; - int data_onoff; - uint32_t command_byte,cmd_pending; - uint8_t tmask,cmask,amask; - uint16_t midi_mask; - uint16_t req_mask; - uint8_t channel,old_chan; - } state; - struct { - uint8_t timebase,old_timebase; - uint8_t tempo,old_tempo; - uint8_t tempo_rel,old_tempo_rel; - uint8_t tempo_grad; - uint8_t cth_rate,cth_counter; - int clock_to_host,cth_active; - } clock; + +typedef struct { + int uart_mode; + uint8_t rx_data; + int intelligent; + MpuMode mode; + int irq; + uint8_t status; + uint8_t queue[MPU401_QUEUE]; + int queue_pos, + queue_used; + + struct track { + int counter; + uint8_t value[8], + sys_val; + uint8_t vlength, + length; + MpuDataType type; + } playbuf[8], + condbuf; + + struct { + int conductor,cond_req,cond_set, block_ack; + int playing,reset; + int wsd,wsm,wsd_start; + int run_irq,irq_pending; + int send_now; + int eoi_scheduled; + int data_onoff; + uint32_t command_byte,cmd_pending; + uint8_t tmask,cmask,amask; + uint16_t midi_mask; + uint16_t req_mask; + uint8_t channel,old_chan; + } state; + + struct { + uint8_t timebase,old_timebase; + uint8_t tempo,old_tempo; + uint8_t tempo_rel,old_tempo_rel; + uint8_t tempo_grad; + uint8_t cth_rate,cth_counter; + int clock_to_host,cth_active; + } clock; } mpu_t; -uint8_t MPU401_ReadData(mpu_t *mpu); -void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); - -extern int mpu401_standalone_enable; - -void mpu401_device_add(void); extern const device_t mpu401_device; -void mpu401_uart_init(mpu_t *mpu, uint16_t addr); + +extern uint8_t MPU401_ReadData(mpu_t *mpu); +extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); +extern void mpu401_device_add(void); +extern void mpu401_uart_init(mpu_t *mpu, uint16_t addr); #endif /*SOUND_MPU401_H*/ diff --git a/src/sound/sound.c b/src/sound/sound.c index 1ab2764..74d4415 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.7 2018/04/08 + * Version: @(#)sound.c 1.0.8 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -74,7 +74,6 @@ int sound_gain = 0; volatile int soundon = 1; -//static int card_last = 0; static sndhnd_t handlers[8]; static sndhnd_t process_handlers[8]; static int handlers_num; @@ -333,15 +332,9 @@ sound_reset(void) /* Initialize the currently selected sound card. */ snddev_reset(); -// card_last = sound_card_current; if (mpu401_standalone_enable) mpu401_device_add(); - -#if 0 - if (GAMEBLASTER) - device_add(&cms_device); -#endif } diff --git a/src/sound/sound_dev.c b/src/sound/sound_dev.c index de01fbb..733ed10 100644 --- a/src/sound/sound_dev.c +++ b/src/sound/sound_dev.c @@ -8,7 +8,7 @@ * * Sound devices support module. * - * Version: @(#)sound_dev.c 1.0.1 2018/04/08 + * Version: @(#)sound_dev.c 1.0.2 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -89,6 +89,7 @@ static const sound_t sound_cards[] = { {"Disabled", "none", NULL }, {"[ISA] Adlib", "adlib", &adlib_device }, {"[ISA] Adlib Gold", "adlibgold", &adgold_device }, + {"[ISA] Creative Music System", "cms", &cms_device }, {"[ISA] Gravis Ultra Sound", "gus", &gus_device }, {"[ISA] Innovation SSI-2001", "ssi2001", &ssi2001_device }, {"[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, diff --git a/src/win/VARCem.rc b/src/win/VARCem.rc index b2972c5..d996193 100644 --- a/src/win/VARCem.rc +++ b/src/win/VARCem.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)VARCem.rc 1.0.15 2018/04/08 + * Version: @(#)VARCem.rc 1.0.16 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -488,9 +488,6 @@ BEGIN CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 - - CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 END DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 diff --git a/src/win/resource.h b/src/win/resource.h index 34cf7bd..6dfc76c 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -160,7 +160,6 @@ #define IDC_CHECK_FLOAT 1074 #define IDC_CHECK_MPU401 1075 #define IDC_CONFIGURE_MPU401 1076 -#define IDC_CHECK_CMS 1077 #define IDC_COMBO_NET_TYPE 1090 /* network config */ #define IDC_COMBO_PCAP 1091 diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 2060152..df6c559 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Implementation of the Settings dialog. * - * Version: @(#)win_settings.c 1.0.19 2018/04/08 + * Version: @(#)win_settings.c 1.0.20 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -67,7 +67,6 @@ #include "../network/network.h" #include "../sound/sound.h" #include "../sound/midi.h" -#include "../sound/snd_dbopl.h" #include "../sound/snd_mpu401.h" #include "../video/video.h" #include "../video/vid_voodoo.h" @@ -92,7 +91,7 @@ static int temp_mouse, temp_joystick; /* Sound category. */ static int temp_sound_card, temp_midi_device, temp_mpu401, - temp_GAMEBLASTER, temp_opl3_type, temp_float; + temp_opl3_type, temp_float; /* Network category. */ static int temp_net_type, temp_net_card; @@ -192,7 +191,6 @@ settings_init(void) temp_sound_card = sound_card_current; temp_midi_device = midi_device_current; temp_mpu401 = mpu401_standalone_enable; - temp_GAMEBLASTER = GAMEBLASTER; temp_opl3_type = opl3_type; temp_float = sound_is_float; @@ -268,7 +266,6 @@ settings_changed(void) i = i || (sound_card_current != temp_sound_card); i = i || (midi_device_current != temp_midi_device); i = i || (mpu401_standalone_enable != temp_mpu401); - i = i || (GAMEBLASTER != temp_GAMEBLASTER); i = i || (opl3_type != temp_opl3_type); i = i || (sound_is_float != temp_float); @@ -370,7 +367,6 @@ settings_save(void) sound_card_current = temp_sound_card; midi_device_current = temp_midi_device; mpu401_standalone_enable = temp_mpu401; - GAMEBLASTER = temp_GAMEBLASTER; opl3_type = temp_opl3_type; sound_is_float = temp_float; diff --git a/src/win/win_settings_sound.h b/src/win/win_settings_sound.h index 16a5520..859a46b 100644 --- a/src/win/win_settings_sound.h +++ b/src/win/win_settings_sound.h @@ -8,7 +8,7 @@ * * Implementation of the Settings dialog. * - * Version: @(#)win_settings_sound.h 1.0.3 2018/04/08 + * Version: @(#)win_settings_sound.h 1.0.4 2018/04/08 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -162,9 +162,6 @@ sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_CHECK_CMS); - SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); - h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); SendMessage(h, BM_SETCHECK, temp_opl3_type, 0); @@ -249,9 +246,6 @@ sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_CHECK_MPU401); temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CHECK_CMS); - temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); temp_opl3_type = SendMessage(h, BM_GETCHECK, 0, 0);