diff --git a/src/include/86box/snd_ac97.h b/src/include/86box/snd_ac97.h index d8f165dbd..a72a874d9 100644 --- a/src/include/86box/snd_ac97.h +++ b/src/include/86box/snd_ac97.h @@ -27,6 +27,7 @@ typedef struct { extern uint8_t ac97_codec_read(ac97_codec_t *dev, uint8_t reg); extern void ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val); extern void ac97_codec_reset(void *priv); +extern void ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r); extern void ac97_via_set_slot(void *priv, int slot, int irq_pin); extern uint8_t ac97_via_read_status(void *priv, uint8_t modem); diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 6a6d45f87..d215b8145 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -54,6 +54,11 @@ ac97_codec_log(const char *fmt, ...) #define ac97_codec_log(fmt, ...) #endif +static const int32_t codec_attn[] = { + 25, 32, 41, 51, 65, 82, 103, 130, 164, 206, 260, 327, 412, 519, 653, 822, + 1036, 1304, 1641, 2067, 2602, 3276, 4125, 5192, 6537, 8230, 10362, 13044, 16422, 20674, 26027, 32767 +}; + ac97_codec_t **ac97_codec = NULL, **ac97_modem_codec = NULL; int ac97_codec_count = 0, ac97_modem_codec_count = 0; @@ -182,6 +187,35 @@ ac97_codec_reset(void *priv) } +void +ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r) +{ + ac97_codec_t *dev = (ac97_codec_t *) priv; + uint8_t r_val = dev->regs[reg], + l_val = dev->regs[reg | 1]; + + if (l_val & 0x80) { /* mute */ + *l = 0; + *r = 0; + return; + } + + if (reg < 0x10) { /* 6-bit volume */ + if (l_val & 0x20) + *l = codec_attn[0]; + else + *l = codec_attn[0x1f - (l_val & 0x1f)]; + if (r_val & 0x20) + *r = codec_attn[0]; + else + *r = codec_attn[0x1f - (r_val & 0x1f)]; + } else { /* 5-bit gain */ + *l = codec_attn[0x1f - (l_val & 0x1f)]; + *r = codec_attn[0x1f - (r_val & 0x1f)]; + } +} + + static void * ac97_codec_init(const device_t *info) { diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 44b9ad825..bc2ec8ee9 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -59,12 +59,12 @@ typedef struct _ac97_via_ { pc_timer_t timer_count, timer_count_fm; uint64_t timer_latch, timer_fifo_latch; int16_t out_l, out_r, fm_out_l, fm_out_r; - double cd_vol_l, cd_vol_r; - int16_t buffer[SOUNDBUFLEN * 2], fm_buffer[SOUNDBUFLEN * 2]; + int master_vol_l, master_vol_r, pcm_vol_l, pcm_vol_r, cd_vol_l, cd_vol_r; + int32_t buffer[SOUNDBUFLEN * 2], fm_buffer[SOUNDBUFLEN * 2]; int pos, fm_pos; } ac97_via_t; -#define ENABLE_AC97_VIA_LOG 1 + #ifdef ENABLE_AC97_VIA_LOG int ac97_via_do_log = ENABLE_AC97_VIA_LOG; @@ -85,6 +85,7 @@ ac97_via_log(const char *fmt, ...) static void ac97_via_sgd_process(void *priv); +static void ac97_via_update_volumes(ac97_via_t *dev, ac97_codec_t *codec); void @@ -125,11 +126,15 @@ ac97_via_write_control(void *priv, uint8_t modem, uint8_t val) ac97_via_log("AC97 VIA %d: write_control(%02X)\n", modem, val); - /* Reset codecs if requested. */ - if (val & 0x40) { - for (i = 0; i <= 1; i++) { - if (dev->codec[modem][i]) + /* Reset and/or update volumes on all codecs. */ + for (i = 0; i <= 1; i++) { + if (dev->codec[modem][i]) { + /* Reset codec if requested. */ + if (val & 0x40) ac97_codec_reset(dev->codec[modem][i]); + + /* Update volumes. */ + ac97_via_update_volumes(dev, dev->codec[modem][i]); } } @@ -168,6 +173,16 @@ ac97_via_update_irqs(ac97_via_t *dev) } +static void +ac97_via_update_volumes(ac97_via_t *dev, ac97_codec_t *codec) { + ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); + ac97_codec_getattn(codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r); + ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); + + pclog("master %d %d\npcm %d %d\ncd %d %d\n", dev->master_vol_l, dev->master_vol_r, dev->pcm_vol_l, dev->pcm_vol_r, dev->cd_vol_l, dev->cd_vol_r); +} + + uint8_t ac97_via_sgd_read(uint16_t addr, void *priv) { @@ -361,6 +376,9 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x80]); val |= 1; ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x81]); + + /* Update volumes. */ + ac97_via_update_volumes(dev, codec); } /* Flag data/status/index for this codec as valid. */ @@ -479,9 +497,12 @@ ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable) static void ac97_via_update(ac97_via_t *dev) { + int32_t l = (((dev->out_l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15, + r = (((dev->out_r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15; + for (; dev->pos < sound_pos_global; dev->pos++) { - dev->buffer[dev->pos*2] = dev->out_l; - dev->buffer[dev->pos*2 + 1] = dev->out_r; + dev->buffer[dev->pos*2] = l; + dev->buffer[dev->pos*2 + 1] = r; } } @@ -701,10 +722,9 @@ ac97_via_get_buffer(int32_t *buffer, int len, void *priv) for (int c = 0; c < len * 2; c++) { buffer[c] += dev->buffer[c] / 2; - buffer[c] += dev->fm_buffer[c]; + buffer[c] += dev->fm_buffer[c] / 2; } - /* Feed silence if the FIFO is empty. */ dev->pos = dev->fm_pos = 0; } diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index d64066ccc..cd8288d4d 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -148,12 +148,6 @@ typedef struct { #define FORMAT_MONO_16 2 #define FORMAT_STEREO_16 3 -const int32_t codec_attn[]= { - 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, - 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, - 16422,20674,26027,32767 -}; - static void es1371_fetch(es1371_t *es1371, int dac_nr); static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl); @@ -595,35 +589,16 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0x14: if (val & CODEC_READ) { es1371->codec_ctrl &= 0x00ff0000; - es1371->codec_ctrl |= ac97_codec_read(es1371->codec, (val >> 16) & 0x7f); - es1371->codec_ctrl |= ac97_codec_read(es1371->codec, ((val >> 16) & 0x7f) + 1) << 8; + val = (val >> 16) & 0x7e; + es1371->codec_ctrl |= ac97_codec_read(es1371->codec, val); + es1371->codec_ctrl |= ac97_codec_read(es1371->codec, val | 1) << 8; } else { - es1371->codec_ctrl &= 0x00ffffff; - ac97_codec_write(es1371->codec, (val >> 16) & 0x7f, val & 0xff); - ac97_codec_write(es1371->codec, ((val >> 16) & 0x7f) + 1, val >> 8); + es1371->codec_ctrl = val & 0x00ffffff; + ac97_codec_write(es1371->codec, (val >> 16) & 0x7e, val & 0xff); + ac97_codec_write(es1371->codec, ((val >> 16) & 0x7e) | 1, val >> 8); - val = *((uint16_t *) &es1371->codec->regs[0x02]); /* Master Volume */ - if (val & 0x8000) { - es1371->master_vol_l = es1371->master_vol_r = 0; - } else { - if (val & 0x2000) - es1371->master_vol_l = codec_attn[0]; - else - es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)]; - if (val & 0x20) - es1371->master_vol_r = codec_attn[0]; - else - es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)]; - } - - val = *((uint16_t *) &es1371->codec->regs[0x12]); /* CD Volume */ - if (val & 0x8000) { - es1371->cd_vol_l = es1371->cd_vol_r = 0; - } else { - es1371->cd_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)]; - es1371->cd_vol_r = codec_attn[0x1f - (val & 0x1f)]; - } - break; + ac97_codec_getattn(es1371->codec, 0x02, &es1371->master_vol_l, &es1371->master_vol_r); + ac97_codec_getattn(es1371->codec, 0x12, &es1371->cd_vol_l, &es1371->cd_vol_r); } break;