Merge pull request #6154 from lemondrops/gus

Gravis UltraSound: additions, improvements and fixes
This commit is contained in:
Miran Grča
2025-09-11 19:06:31 +02:00
committed by GitHub
32 changed files with 588 additions and 55 deletions

View File

@@ -32,6 +32,14 @@ enum {
AD1848_TYPE_CS4235 = 6
};
enum {
AD1848_AUX1 = 2,
AD1848_AUX2 = 4,
AD1848_OUT = 6,
AD1848_LINE_IN = 18,
AD1848_MONO = 26
};
typedef struct ad1848_t {
uint8_t type;
uint8_t index;
@@ -47,6 +55,7 @@ typedef struct ad1848_t {
int16_t out_l;
int16_t out_r;
int8_t cd_vol_reg;
double cd_vol_l;
double cd_vol_r;
int fm_vol_l;
@@ -86,8 +95,9 @@ extern void ad1848_write(uint16_t addr, uint8_t val, void *priv);
extern void ad1848_update(ad1848_t *ad1848);
extern void ad1848_speed_changed(ad1848_t *ad1848);
extern void ad1848_set_cd_audio_channel(void *priv, int channel);
extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv);
extern void ad1848_filter_aux2(void* priv, double* out_l, double* out_r);
extern void ad1848_filter_channel(void* priv, int channel, double* out_l, double* out_r);
extern void ad1848_init(ad1848_t *ad1848, uint8_t type);

View File

@@ -203,9 +203,11 @@ extern const device_t es1373_onboard_device;
extern const device_t ct5880_device;
extern const device_t ct5880_onboard_device;
/* Gravis UltraSound and UltraSound Max */
/* Gravis UltraSound family */
extern const device_t gus_device;
extern const device_t gus_v37_device;
extern const device_t gus_max_device;
extern const device_t gus_ace_device;
/* IBM PS/1 Audio Card */
extern const device_t ps1snd_device;

View File

@@ -2136,6 +2136,9 @@ msgstr ""
msgid "Enable Game port"
msgstr ""
msgid "Enable Adlib ports"
msgstr ""
msgid "SID Model"
msgstr ""

View File

@@ -2136,6 +2136,9 @@ msgstr "Nízký DMA kanál"
msgid "Enable Game port"
msgstr "Povolit herní port"
msgid "Enable Adlib ports"
msgstr "Povolit porty Adlib"
msgid "SID Model"
msgstr "Model SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Niedrige DMA"
msgid "Enable Game port"
msgstr "Game-Port einschalten"
msgid "Enable Adlib ports"
msgstr "Adlib-Ports einschalten"
msgid "SID Model"
msgstr "SID-Modell"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA bajo"
msgid "Enable Game port"
msgstr "Habilitar puerto de juegos"
msgid "Enable Adlib ports"
msgstr "Habilitar puertos Adlib"
msgid "SID Model"
msgstr "Modelo de SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Matala DMA"
msgid "Enable Game port"
msgstr "Peliportti"
msgid "Enable Adlib ports"
msgstr "Adlib-portit"
msgid "SID Model"
msgstr "SID-malli"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA bas"
msgid "Enable Game port"
msgstr "Activer le port de jeu"
msgid "Enable Adlib ports"
msgstr "Activer les ports Adlib"
msgid "SID Model"
msgstr "Modèle SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Niski DMA"
msgid "Enable Game port"
msgstr "Omogoći vrata za igru"
msgid "Enable Adlib ports"
msgstr "Omogući Adlib portove"
msgid "SID Model"
msgstr "Model SID-a"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA basso"
msgid "Enable Game port"
msgstr "Abilita la porta giochi"
msgid "Enable Adlib ports"
msgstr "Abilita porte Adlib"
msgid "SID Model"
msgstr "Modello SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "低DMA"
msgid "Enable Game port"
msgstr "ゲームポートを有効にする"
msgid "Enable Adlib ports"
msgstr "Adlibポートを有効にする"
msgid "SID Model"
msgstr "SIDモデル"

View File

@@ -2136,6 +2136,9 @@ msgstr "낮은 DMA"
msgid "Enable Game port"
msgstr "게임 포트 사용"
msgid "Enable Adlib ports"
msgstr "Adlib 포트 활성화"
msgid "SID Model"
msgstr "SID 모델"

View File

@@ -2136,6 +2136,9 @@ msgstr "Lav DMA"
msgid "Enable Game port"
msgstr "Aktiver spillport"
msgid "Enable Adlib ports"
msgstr "Aktiver Adlib-porter"
msgid "SID Model"
msgstr "SID-modell"

View File

@@ -2136,6 +2136,9 @@ msgstr "Lage DMA"
msgid "Enable Game port"
msgstr "Game-poort inschakelen"
msgid "Enable Adlib ports"
msgstr "Adlib-poorten inschakelen"
msgid "SID Model"
msgstr "SID-model"

View File

@@ -2136,6 +2136,9 @@ msgstr "Niski poziom DMA"
msgid "Enable Game port"
msgstr "Włącz port gier"
msgid "Enable Adlib ports"
msgstr "Włącz porty Adlib"
msgid "SID Model"
msgstr "Model SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA baixo"
msgid "Enable Game port"
msgstr "Ativar a porta do jogo"
msgid "Enable Adlib ports"
msgstr "Ativar portas Adlib"
msgid "SID Model"
msgstr "Modelo do SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA baixo"
msgid "Enable Game port"
msgstr "Ativar a porta de jogos"
msgid "Enable Adlib ports"
msgstr "Ativar portas Adlib"
msgid "SID Model"
msgstr "Modelo do SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Низкий DMA"
msgid "Enable Game port"
msgstr "Включить игровой порт"
msgid "Enable Adlib ports"
msgstr "Включить порты Adlib"
msgid "SID Model"
msgstr "Модель SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Nízka hodnota DMA"
msgid "Enable Game port"
msgstr "Povolenie herného portu"
msgid "Enable Adlib ports"
msgstr "Povoliť porty Adlib"
msgid "SID Model"
msgstr "Model SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Nizki DMA"
msgid "Enable Game port"
msgstr "Omogočanje igralnih vrat"
msgid "Enable Adlib ports"
msgstr "Omogoči vrata Adlib"
msgid "SID Model"
msgstr "Model SID-a"

View File

@@ -2136,6 +2136,9 @@ msgstr "Låg DMA"
msgid "Enable Game port"
msgstr "Aktivera spelport"
msgid "Enable Adlib ports"
msgstr "Aktivera Adlib-portar"
msgid "SID Model"
msgstr "SID-modell"

View File

@@ -2136,6 +2136,9 @@ msgstr "Düşük DMA"
msgid "Enable Game port"
msgstr "Gameport'ı etkinleştir"
msgid "Enable Adlib ports"
msgstr "Adlib bağlantı noktalarını etkinleştir"
msgid "SID Model"
msgstr "SID Modeli"

View File

@@ -2136,6 +2136,9 @@ msgstr "Низький рівень DMA"
msgid "Enable Game port"
msgstr "Увімкнути ігровий порт"
msgid "Enable Adlib ports"
msgstr "Увімкнути порти Adlib"
msgid "SID Model"
msgstr "Модель SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA thấp"
msgid "Enable Game port"
msgstr "Bật cổng trò chơi"
msgid "Enable Adlib ports"
msgstr "Bật cổng Adlib"
msgid "SID Model"
msgstr "Mẫu SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "低 DMA"
msgid "Enable Game port"
msgstr "启用游戏端口"
msgid "Enable Adlib ports"
msgstr "启用 Adlib 端口"
msgid "SID Model"
msgstr "SID 芯片型号"

View File

@@ -2136,6 +2136,9 @@ msgstr "低 DMA"
msgid "Enable Game port"
msgstr "啟用遊戲埠"
msgid "Enable Adlib ports"
msgstr "啟用 Adlib 連接埠"
msgid "SID Model"
msgstr "SID 型號"

View File

@@ -501,16 +501,16 @@ readonly_x:
if (updatefreq)
ad1848_updatefreq(ad1848);
temp = (ad1848->type < AD1848_TYPE_CS4231) ? 2 : ((ad1848->type == AD1848_TYPE_CS4231) ? 18 : 4);
if (ad1848->regs[temp] & 0x80)
ad1848->cd_vol_l = 0;
else
ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f];
temp++;
if (ad1848->regs[temp] & 0x80)
ad1848->cd_vol_r = 0;
else
ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f];
if (ad1848->cd_vol_reg > -1) {
if (ad1848->regs[ad1848->cd_vol_reg] & 0x80)
ad1848->cd_vol_l = 0;
else
ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[ad1848->cd_vol_reg] & 0x1f];
if (ad1848->regs[ad1848->cd_vol_reg + 1] & 0x80)
ad1848->cd_vol_r = 0;
else
ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[ad1848->cd_vol_reg + 1] & 0x1f];
}
readonly_i:
ad1848_log("AD1848: write(I%d, %02X)\n", ad1848->index, val);
@@ -746,6 +746,18 @@ ad1848_poll(void *priv)
}
}
void
ad1848_set_cd_audio_channel(void *priv, int channel)
{
ad1848_t *ad1848 = (ad1848_t *) priv;
const int max_channel = (ad1848->type >= AD1848_TYPE_CS4231) ? 31 : 15;
if (channel > max_channel)
channel = max_channel;
ad1848->cd_vol_reg = channel;
}
void
ad1848_filter_cd_audio(int channel, double *buffer, void *priv)
{
@@ -758,20 +770,24 @@ ad1848_filter_cd_audio(int channel, double *buffer, void *priv)
}
void
ad1848_filter_aux2(void *priv, double *out_l, double *out_r)
ad1848_filter_channel(void *priv, int channel, double *out_l, double *out_r)
{
const ad1848_t *ad1848 = (ad1848_t *) priv;
if (ad1848->regs[4] & 0x80) {
const int max_channel = (ad1848->type >= AD1848_TYPE_CS4231) ? 31 : 15;
if (channel > max_channel)
channel = max_channel;
if (ad1848->regs[channel] & 0x80) {
*out_l = 0.0;
} else {
*out_l = ((*out_l) * ad1848_vols_5bits_aux_gain[ad1848->regs[4] & 0x1f]) / 65536.0;
*out_l = ((*out_l) * ad1848_vols_5bits_aux_gain[ad1848->regs[channel] & 0x1f]) / 65536.0;
}
if (ad1848->regs[5] & 0x80) {
if (ad1848->regs[channel + 1] & 0x80) {
*out_r = 0.0;
} else {
*out_r = ((*out_r) * ad1848_vols_5bits_aux_gain[ad1848->regs[5] & 0x1f]) / 65536.0;
*out_r = ((*out_r) * ad1848_vols_5bits_aux_gain[ad1848->regs[channel + 1] & 0x1f]) / 65536.0;
}
}
@@ -837,6 +853,8 @@ ad1848_init(ad1848_t *ad1848, uint8_t type)
ad1848->out_l = ad1848->out_r = 0;
ad1848->fm_vol_l = ad1848->fm_vol_r = 65536;
ad1848->cd_vol_l = ad1848->cd_vol_r = 65536;
ad1848->cd_vol_reg = -1;
ad1848_updatevolmask(ad1848);
if (type >= AD1848_TYPE_CS4235)
ad1848->fmt_mask = 0x50;

View File

@@ -1211,6 +1211,7 @@ azt_init(const device_t *info)
/* wss part */
ad1848_init(&azt2316a->ad1848, device_get_config_int("codec"));
ad1848_set_cd_audio_channel(&azt2316a->ad1848, (device_get_config_int("codec") == AD1848_TYPE_CS4248) ? AD1848_AUX1 : AD1848_LINE_IN);
ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq);
ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma);

View File

@@ -273,8 +273,10 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
}
switch (dev->regs[3] & 0x0f) {
case 0: /* WSS Master Control */
if ((dev->type < CRYSTAL_CS4235) && (val & 0x80))
if ((dev->type < CRYSTAL_CS4235) && (val & 0x80)) {
ad1848_init(&dev->ad1848, dev->ad1848_type);
ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2);
}
val = 0x00;
break;
@@ -865,6 +867,7 @@ cs423x_reset(void *priv)
/* Reset WSS codec. */
ad1848_init(&dev->ad1848, dev->ad1848_type);
ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2);
/* Reset PnP resource data, state and logical devices. */
dev->pnp_enable = 1;

View File

@@ -13,6 +13,7 @@
#include <86box/io.h>
#include <86box/midi.h>
#include <86box/nmi.h>
#include <86box/gameport.h>
#include <86box/pic.h>
#include <86box/sound.h>
#include "cpu.h"
@@ -43,10 +44,33 @@ enum {
};
enum {
GUS_CLASSIC = 0,
GUS_MAX = 1,
GUS_CLASSIC = 0,
GUS_CLASSIC_37 = 1,
GUS_MAX = 2,
GUS_ACE = 3
};
enum {
GUS_ICS2101_MIC_IN = 0,
GUS_ICS2101_LINE_IN = 1,
GUS_ICS2101_CD_IN = 2,
GUS_ICS2101_GF1_OUT = 3,
GUS_ICS2101_UNUSED = 4,
GUS_ICS2101_MASTER = 5,
GUS_ICS2101_MAX = 6
};
typedef struct ics2101_chan_t {
uint8_t ctrl[2];
double level[2];
uint8_t pan;
} ics2101_chan_t;
typedef struct ics2101_t {
uint8_t addr;
ics2101_chan_t channels[GUS_ICS2101_MAX];
} ics2101_t;
typedef struct gus_t {
int reset;
@@ -120,7 +144,9 @@ typedef struct gus_t {
uint8_t sb_ctrl;
int sb_nmi;
uint8_t joy_trim;
uint8_t reg_ctrl;
uint8_t jumper;
uint8_t ad_status;
uint8_t ad_data;
@@ -143,9 +169,13 @@ typedef struct gus_t {
uint8_t usrr;
void *gameport;
uint8_t max_ctrl;
ad1848_t ad1848;
ics2101_t ics2101;
} gus_t;
static int gus_gf1_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 };
@@ -159,6 +189,15 @@ int gusfreqs[] = {
double vol16bit[4096];
double ics2101_att[128];
double ics2101_pan[] = { 0.35481, 0.35481, 0.35481, 0.37584, 0.47315, 0.53088, 0.59566, 0.66834,
0.70795,
0.74989, 0.79433, 0.84140, 0.89125, 0.94406, 1.00000, 1.00000, 1.00000 };
void gus_write(uint16_t addr, uint8_t val, void *priv);
uint8_t gus_read(uint16_t addr, void *priv);
void
gus_update_int_status(gus_t *gus)
{
@@ -255,6 +294,10 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
uint16_t port;
uint16_t csioport;
ics2101_t *ics2101 = &gus->ics2101;
uint8_t mixer_ch;
uint8_t mixer_lr;
if ((addr == 0x388) || (addr == 0x389))
port = addr;
else
@@ -537,6 +580,10 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus->t2on = 1;
break;
case 0x4B: /*Joystick trim DAC*/
gus->joy_trim = val;
break;
case 0x4c: /*Reset*/
gus->reset = val;
break;
@@ -634,9 +681,25 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus->gp2_addr = val;
break;
case 5:
gus->usrr = 0;
if (gus->type > GUS_CLASSIC)
gus->usrr = 0;
break;
case 6:
if (gus->type > GUS_CLASSIC) {
if (gus->type != GUS_ACE) {
if (!(val & 0x2) && (gus->jumper & 0x2))
io_removehandler(0x0100 + gus->base, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
else if ((val & 0x2) && !(gus->jumper & 0x2))
io_sethandler(0x0100 + gus->base, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
if (!(val & 0x4) && (gus->jumper & 0x4))
gameport_remap(gus->gameport, 0x0);
else if ((val & 0x4) && !(gus->jumper & 0x4))
gameport_remap(gus->gameport, 0x201);
}
gus->jumper = val;
}
break;
default:
@@ -672,11 +735,47 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus->sb_2xe = val;
break;
case 0x20f:
gus->reg_ctrl = val;
if (gus->type > GUS_CLASSIC)
gus->reg_ctrl = val;
break;
case 0x306:
if (gus->type == GUS_CLASSIC_37) {
mixer_ch = (ics2101->addr >> 3) & 0x7; /* current attenuator */
mixer_lr = ics2101->addr & 1; /* left or right channel */
switch (ics2101->addr & 0x6) {
case 0: /* Set control */
ics2101->channels[mixer_ch].ctrl[mixer_lr] = val & 0xF;
if ((mixer_lr == 0) && (val & 0xC)) /* copy to right channel if not normal mode */
ics2101->channels[mixer_ch].ctrl[1] = val & 0xF;
break;
case 2: /* Set attenuator */
switch (ics2101->channels[mixer_ch].ctrl[mixer_lr] & 0xC) {
case 0: /* Normal mode */
ics2101->channels[mixer_ch].level[mixer_lr] = ics2101_att[val & 0x7F];
break;
case 4: /* Stereo mode */
ics2101->channels[mixer_ch].level[0] = ics2101_att[val & 0x7F];
ics2101->channels[mixer_ch].level[1] = ics2101_att[val & 0x7F];
break;
case 8: /* Balance/Pan mode */
ics2101->channels[mixer_ch].level[0] = ics2101_att[val & 0x7F] * ics2101_pan[ics2101->channels[mixer_ch].pan + 1];
ics2101->channels[mixer_ch].level[1] = ics2101_att[val & 0x7F] * ics2101_pan[16 - ics2101->channels[mixer_ch].pan];
break;
}
break;
case 4: /* Set panning */
ics2101->channels[mixer_ch].pan = val & 0xF;
break;
default:
break;
}
break;
}
fallthrough;
case 0x706:
if (gus->type == GUS_MAX) {
if (gus->type == GUS_CLASSIC_37) {
gus->ics2101.addr = val & 0x3F;
} else if (gus->type == GUS_MAX) {
if (gus->dma >= 4)
val |= 0x10;
if (gus->dma2 >= 4)
@@ -746,10 +845,10 @@ gus_read(uint16_t addr, void *priv)
return val;
case 0x20F:
if (gus->type == GUS_MAX)
val = 0x02;
if (gus->type > GUS_CLASSIC)
val = gus->jumper;
else
val = 0x00;
val = 0xff;
break;
case 0x302:
@@ -842,6 +941,9 @@ gus_read(uint16_t addr, void *priv)
case 0x49: /*Sampling control*/
return 0;
case 0x4B: /*Joystick trim DAC*/
return gus->joy_trim;
case 0x00:
case 0x01:
case 0x02:
@@ -867,10 +969,14 @@ gus_read(uint16_t addr, void *priv)
break;
case 0x306:
case 0x706:
if (gus->type == GUS_MAX)
if (gus->type == GUS_CLASSIC_37)
val = 0x06; /* 3.7x - mixer, no reverse channels bug */
else if (gus->type == GUS_MAX)
val = 0x0a; /* GUS MAX */
else if (gus->type == GUS_ACE)
val = 0x30; /* GUS ACE */
else
val = 0xff; /*Pre 3.7 - no mixer*/
val = 0xff; /* Pre 3.7 - no mixer */
break;
case 0x307: /*DRAM access*/
@@ -884,22 +990,24 @@ gus_read(uint16_t addr, void *priv)
return 0;
case 0x20b:
switch (gus->reg_ctrl & 0x07) {
case 1:
val = gus->gp1;
break;
case 2:
val = gus->gp2;
break;
case 3:
val = gus->gp1_addr;
break;
case 4:
val = gus->gp2_addr;
break;
if (gus->type > GUS_CLASSIC) {
switch (gus->reg_ctrl & 0x07) {
case 1:
val = gus->gp1;
break;
case 2:
val = gus->gp2;
break;
case 3:
val = gus->gp1_addr;
break;
case 4:
val = gus->gp2_addr;
break;
default:
break;
default:
break;
}
}
break;
@@ -911,8 +1019,11 @@ gus_read(uint16_t addr, void *priv)
case 0x20e:
return gus->sb_2xe;
case 0x208:
case 0x388:
if ((gus->type == GUS_ACE) && !device_get_config_int("adlib_ports"))
break;
fallthrough;
case 0x208:
if (gus->tctrl & GUS_TIMER_CTRL_AUTO)
val = gus->sb_2xa;
else {
@@ -927,10 +1038,12 @@ gus_read(uint16_t addr, void *priv)
#ifdef OLD_NMI_BEHAVIOR
nmi = 0;
#endif /* OLD_NMI_BEHAVIOR */
fallthrough;
case 0x389:
val = gus->ad_data;
break;
case 0x389:
if ((gus->type != GUS_ACE) || device_get_config_int("adlib_ports"))
val = gus->ad_data;
break;
case 0x20A:
val = gus->adcommand;
@@ -1164,6 +1277,58 @@ gus_poll_wave(void *priv)
gus_update_int_status(gus);
}
void
gus_ics2101_filter(void *priv, int channel, double *out_l, double *out_r)
{
ics2101_t *ics2101 = (ics2101_t *) priv;
double temp_l = 0.0;
double temp_r = 0.0;
double master_l = 0.0;
double master_r = 0.0;
uint8_t ctrl_l = ics2101->channels[channel].ctrl[0];
uint8_t ctrl_r = ics2101->channels[channel].ctrl[1];
if (!(ctrl_l & 0xC)) { /* Normal mode */
if (ctrl_l & 1)
temp_l += *out_l * ics2101->channels[channel].level[0];
if (ctrl_l & 2)
temp_r += *out_l * ics2101->channels[channel].level[0];
if (ctrl_r & 1)
temp_l += *out_r * ics2101->channels[channel].level[1];
if (ctrl_r & 2)
temp_r += *out_r * ics2101->channels[channel].level[1];
} else { /* Stereo or Balance/Pan mode */
if (ctrl_l & 2) { /* Mono/Pan */
temp_l = (*out_l + *out_r) * 0.5 * ics2101->channels[channel].level[(ctrl_l & 1)];
temp_r = (*out_r + *out_l) * 0.5 * ics2101->channels[channel].level[!(ctrl_l & 1)];
} else { /* Stereo/Balance */
temp_l = ((ctrl_l & 1) ? *out_l : *out_r) * ics2101->channels[channel].level[(ctrl_l & 1)];
temp_r = ((ctrl_l & 1) ? *out_r : *out_l) * ics2101->channels[channel].level[!(ctrl_l & 1)];
}
}
/* Master */
ctrl_l = ics2101->channels[GUS_ICS2101_MASTER].ctrl[0];
ctrl_r = ics2101->channels[GUS_ICS2101_MASTER].ctrl[1];
if (!(ctrl_l & 0xC)) { /* Normal mode */
if (ctrl_l & 1)
master_l += temp_l * ics2101->channels[GUS_ICS2101_MASTER].level[0];
if (ctrl_l & 2)
master_r += temp_l * ics2101->channels[GUS_ICS2101_MASTER].level[0];
if (ctrl_r & 1)
master_l += temp_r * ics2101->channels[GUS_ICS2101_MASTER].level[1];
if (ctrl_r & 2)
master_r += temp_r * ics2101->channels[GUS_ICS2101_MASTER].level[1];
} else { /* Stereo or Balance mode - no mono/pan for master */
master_l = ((ctrl_l & 1) ? temp_l : temp_r) * ics2101->channels[GUS_ICS2101_MASTER].level[(ctrl_l & 1)];
master_r = ((ctrl_l & 1) ? temp_r : temp_l) * ics2101->channels[GUS_ICS2101_MASTER].level[!(ctrl_l & 1)];
}
*out_l = master_l;
*out_r = master_r;
}
static void
gus_get_buffer(int32_t *buffer, int len, void *priv)
{
@@ -1173,11 +1338,26 @@ gus_get_buffer(int32_t *buffer, int len, void *priv)
ad1848_update(&gus->ad1848);
gus_update(gus);
for (int c = 0; c < len * 2; c++) {
if ((gus->type == GUS_MAX) && (gus->max_ctrl))
buffer[c] += (int32_t) (gus->ad1848.buffer[c] / 2);
buffer[c] += (int32_t) gus->buffer[c & 1][c >> 1];
for (int c = 0; c < len * 2; c += 2) {
double temp_l = 0.0;
double temp_r = 0.0;
if ((gus->type == GUS_CLASSIC_37) || (gus->type == GUS_MAX)) {
temp_l = (double) gus->buffer[0][c >> 1];
temp_r = (double) gus->buffer[1][c >> 1];
if (gus->type == GUS_MAX) {
if (gus->max_ctrl) {
buffer[c] += (int32_t) (gus->ad1848.buffer[c] / 2);
buffer[c + 1] += (int32_t) (gus->ad1848.buffer[c + 1] / 2);
}
ad1848_filter_channel(&gus->ad1848, AD1848_AUX1, &temp_l, &temp_r);
} else
gus_ics2101_filter(&gus->ics2101, GUS_ICS2101_GF1_OUT, &temp_l, &temp_r);
buffer[c] += (int32_t) temp_l;
buffer[c + 1] += (int32_t) temp_r;
} else {
buffer[c] += (int32_t) gus->buffer[0][c >> 1];
buffer[c + 1] += (int32_t) gus->buffer[1][c >> 1];
}
}
if ((gus->type == GUS_MAX) && (gus->max_ctrl))
@@ -1186,6 +1366,17 @@ gus_get_buffer(int32_t *buffer, int len, void *priv)
gus->pos = 0;
}
void
gus_filter_cd_audio(int channel, double *buffer, void *priv)
{
const gus_t *gus = (gus_t *) priv;
/* FIXME: No channel remapping possible with the current architecture */
if (gus->ics2101.channels[GUS_ICS2101_CD_IN].ctrl[channel] && gus->ics2101.channels[GUS_ICS2101_MASTER].ctrl[channel])
*buffer *= gus->ics2101.channels[GUS_ICS2101_CD_IN].level[channel] * gus->ics2101.channels[GUS_ICS2101_MASTER].level[channel];
else
*buffer *= 0.0;
}
static void
gus_input_msg(void *priv, uint8_t *msg, uint32_t len)
{
@@ -1292,6 +1483,7 @@ gus_reset(void *priv)
gus->sb_ctrl = 0;
gus->sb_nmi = 0;
gus->joy_trim = 29;
gus->reg_ctrl = 0;
gus->ad_status = 0;
@@ -1320,6 +1512,13 @@ gus_reset(void *priv)
gus->irq_state = 0;
gus->midi_irq_state = 0;
for (int i = 0; i < GUS_ICS2101_MAX; i++) {
gus->ics2101.channels[i].level[0] = gus->ics2101.channels[i].level[1] = 1.0;
gus->ics2101.channels[i].ctrl[0] = 1;
gus->ics2101.channels[i].ctrl[1] = 2;
gus->ics2101.channels[i].pan = 7;
}
gus_update_int_status(gus);
}
@@ -1328,6 +1527,7 @@ gus_init(UNUSED(const device_t *info))
{
int c;
double out = 1.0;
double gain;
uint8_t gus_ram = device_get_config_int("gus_ram");
gus_t *gus = calloc(1, sizeof(gus_t));
@@ -1355,15 +1555,46 @@ gus_init(UNUSED(const device_t *info))
gus->type = info->local;
gus->jumper = 0x06;
for (int i = 0; i < GUS_ICS2101_MAX; i++) {
gus->ics2101.channels[i].level[0] = gus->ics2101.channels[i].level[1] = 1.0;
gus->ics2101.channels[i].ctrl[0] = 1;
gus->ics2101.channels[i].ctrl[1] = 2;
gus->ics2101.channels[i].pan = 7;
}
gus->base = device_get_config_hex16("base");
io_sethandler(gus->base, 0x0010, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0100 + gus->base, 0x0010, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
if (gus->type != GUS_ACE)
io_sethandler(0x0100 + gus->base, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0102 + gus->base, 0x000e, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0506 + gus->base, 0x0001, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0388, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
if (gus->type == GUS_CLASSIC && device_get_config_int("gameport"))
gus->gameport = gameport_add(&gameport_201_device);
else if (gus->type != GUS_ACE) {
gus->gameport = gameport_add(&gameport_pnp_1io_device);
gameport_remap(gus->gameport, 0x201);
}
if (gus->type == GUS_CLASSIC_37) {
/* Precalculate the attenuation table for ICS2101 */
for (int i = 0; i < 128; i++) {
gain = (127 - i) * -0.5;
if (i < 16)
for (int j = 0; j < (16 - i); j++)
gain += -0.5 - 0.13603 * (j + 1);
ics2101_att[i] = pow(10.0, gain / 20.0);
}
sound_set_cd_audio_filter(gus_filter_cd_audio, gus);
}
if (gus->type == GUS_MAX) {
ad1848_init(&gus->ad1848, AD1848_TYPE_CS4231);
ad1848_set_cd_audio_channel(&gus->ad1848, AD1848_AUX2);
ad1848_setirq(&gus->ad1848, 5);
ad1848_setdma(&gus->ad1848, 3);
io_sethandler(0x10C + gus->base, 4,
@@ -1376,7 +1607,7 @@ gus_init(UNUSED(const device_t *info))
sound_add_handler(gus_get_buffer, gus);
if (device_get_config_int("receive_input"))
if ((gus->type != GUS_ACE) && (device_get_config_int("receive_input")))
midi_in_handler(1, gus_input_msg, gus_input_sysex, gus);
return gus;
@@ -1442,6 +1673,17 @@ static const device_config_t gus_config[] = {
},
.bios = { { 0 } }
},
{
.name = "gameport",
.description = "Enable Game port",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "receive_input",
.description = "Receive MIDI input",
@@ -1457,6 +1699,160 @@ static const device_config_t gus_config[] = {
// clang-format off
};
static const device_config_t gus_v37_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x220,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "210H", .value = 0x210 },
{ .description = "220H", .value = 0x220 },
{ .description = "230H", .value = 0x230 },
{ .description = "240H", .value = 0x240 },
{ .description = "250H", .value = 0x250 },
{ .description = "260H", .value = 0x260 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "gus_ram",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "256 KB", .value = 0 },
{ .description = "512 KB", .value = 1 },
{ .description = "1 MB", .value = 2 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "receive_input",
.description = "Receive MIDI input",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
static const device_config_t gus_max_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x220,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "210H", .value = 0x210 },
{ .description = "220H", .value = 0x220 },
{ .description = "230H", .value = 0x230 },
{ .description = "240H", .value = 0x240 },
{ .description = "250H", .value = 0x250 },
{ .description = "260H", .value = 0x260 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "gus_ram",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "512 KB", .value = 1 },
{ .description = "1 MB", .value = 2 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "receive_input",
.description = "Receive MIDI input",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
static const device_config_t gus_ace_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x260,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "210H", .value = 0x210 },
{ .description = "220H", .value = 0x220 },
{ .description = "230H", .value = 0x230 },
{ .description = "240H", .value = 0x240 },
{ .description = "250H", .value = 0x250 },
{ .description = "260H", .value = 0x260 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "gus_ram",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "512 KB", .value = 1 },
{ .description = "1 MB", .value = 2 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "adlib_ports",
.description = "Enable Adlib ports",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
const device_t gus_device = {
.name = "Gravis UltraSound",
.internal_name = "gus",
@@ -1471,6 +1867,20 @@ const device_t gus_device = {
.config = gus_config
};
const device_t gus_v37_device = {
.name = "Gravis UltraSound (rev 3.7)",
.internal_name = "gusv37",
.flags = DEVICE_ISA16,
.local = GUS_CLASSIC_37,
.init = gus_init,
.close = gus_close,
.reset = gus_reset,
.available = NULL,
.speed_changed = gus_speed_changed,
.force_redraw = NULL,
.config = gus_v37_config
};
const device_t gus_max_device = {
.name = "Gravis UltraSound MAX",
.internal_name = "gusmax",
@@ -1482,5 +1892,19 @@ const device_t gus_max_device = {
.available = NULL,
.speed_changed = gus_speed_changed,
.force_redraw = NULL,
.config = gus_config
.config = gus_max_config
};
const device_t gus_ace_device = {
.name = "Gravis UltraSound ACE",
.internal_name = "gusace",
.flags = DEVICE_ISA16,
.local = GUS_ACE,
.init = gus_init,
.close = gus_close,
.reset = gus_reset,
.available = NULL,
.speed_changed = gus_speed_changed,
.force_redraw = NULL,
.config = gus_ace_config
};

View File

@@ -85,7 +85,7 @@ optimc_filter_opl(void *priv, double *out_l, double *out_r)
if (optimc->cur_wss_enabled) {
*out_l /= optimc->sb->mixer_sbpro.fm_l;
*out_r /= optimc->sb->mixer_sbpro.fm_r;
ad1848_filter_aux2((void *) &optimc->ad1848, out_l, out_r);
ad1848_filter_channel((void *) &optimc->ad1848, AD1848_AUX2, out_l, out_r);
}
}
@@ -380,6 +380,7 @@ optimc_init(const device_t *info)
else
ad1848_init(&optimc->ad1848, AD1848_TYPE_DEFAULT);
ad1848_set_cd_audio_channel(&optimc->ad1848, (info->local & 0x100) ? AD1848_LINE_IN : AD1848_AUX1);
ad1848_setirq(&optimc->ad1848, optimc->cur_wss_irq);
ad1848_setdma(&optimc->ad1848, optimc->cur_wss_dma);

View File

@@ -138,7 +138,9 @@ static const SOUND_CARD sound_cards[] = {
{ &cs4235_device },
{ &cs4236b_device },
{ &gus_device },
{ &gus_v37_device },
{ &gus_max_device },
{ &gus_ace_device },
{ &mirosound_pcm10_device },
{ &pas16_device },
{ &pas16d_device },