Skip to content

Commit

Permalink
Finish DSP part of ESS
Browse files Browse the repository at this point in the history
  • Loading branch information
Cacodemon345 committed Mar 3, 2024
1 parent cfdf57d commit 4bb839a
Show file tree
Hide file tree
Showing 4 changed files with 453 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/include/86box/snd_sb_dsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ typedef struct sb_dsp_t {
uint8_t ess_regs[256]; /* ESS registers. */
uint8_t ess_playback_mode;
uint8_t ess_extended_mode;
uint8_t ess_reload_len;

mpu_t *mpu;
} sb_dsp_t;
Expand Down
2 changes: 1 addition & 1 deletion src/sound/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_re
snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c
snd_optimc.c esfmu/esfm.c esfmu/esfm_registers.c snd_opl_esfm.c)
snd_optimc.c esfmu/esfm.c esfmu/esfm_registers.c snd_opl_esfm.c snd_ess.c)

if(OPENAL)
if(VCPKG_TOOLCHAIN)
Expand Down
258 changes: 258 additions & 0 deletions src/sound/snd_ess.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Sound Blaster emulation.
*
*
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <[email protected]>
* TheCollector1995, <[email protected]>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H

#include <86box/86box.h>
#include <86box/device.h>
#include <86box/filters.h>
#include <86box/gameport.h>
#include <86box/hdc.h>
#include <86box/isapnp.h>
#include <86box/hdc_ide.h>
#include <86box/io.h>
#include <86box/mca.h>
#include <86box/mem.h>
#include <86box/midi.h>
#include <86box/pic.h>
#include <86box/rom.h>
#include <86box/sound.h>
#include <86box/timer.h>
#include <86box/snd_sb.h>
#include <86box/plat_unused.h>

static const double sb_att_4dbstep_3bits[] = {
164.0, 2067.0, 3276.0, 5193.0, 8230.0, 13045.0, 20675.0, 32767.0
};

static const double sb_att_7dbstep_2bits[] = {
164.0, 6537.0, 14637.0, 32767.0
};

/* SB PRO */
typedef struct ess_mixer_t {
double master_l;
double master_r;
double voice_l;
double voice_r;
double fm_l;
double fm_r;
double cd_l;
double cd_r;
double line_l;
double line_r;
double mic;
/*see sb_ct1745_mixer for values for input selector*/
int32_t input_selector;

int input_filter;
int in_filter_freq;
int output_filter;

int stereo;
int stereo_isleft;

uint8_t index;
uint8_t regs[256];
} ess_mixer_t;

typedef struct ess_t {
uint8_t mixer_enabled;
fm_drv_t opl;
sb_dsp_t dsp;
union {
ess_mixer_t mixer_sbpro;
};
mpu_t *mpu;
emu8k_t emu8k;
void *gameport;

int pnp;

uint8_t pos_regs[8];
uint8_t pnp_rom[512];

uint16_t opl_pnp_addr;
uint16_t gameport_addr;

void *opl_mixer;
void (*opl_mix)(void*, double*, double*);
} ess_t;

static inline uint8_t expand16to32(const uint8_t t) {
/* 4-bit -> 5-bit expansion.
*
* 0 -> 0
* 1 -> 2
* 2 -> 4
* 3 -> 6
* ....
* 7 -> 14
* 8 -> 17
* 9 -> 19
* 10 -> 21
* 11 -> 23
* ....
* 15 -> 31 */
return (t << 1) | (t >> 3);
}

void
ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
{
ess_t *ess = (ess_t *) priv;
ess_mixer_t *mixer = &ess->mixer_sbpro;

if (!(addr & 1)) {
mixer->index = val;
mixer->regs[0x01] = val;
} else {
if (mixer->index == 0) {
/* Reset */
mixer->regs[0x0a] = mixer->regs[0x0c] = 0x00;
mixer->regs[0x0e] = 0x00;
/* Changed default from -11dB to 0dB */
mixer->regs[0x04] = mixer->regs[0x22] = 0xee;
mixer->regs[0x26] = mixer->regs[0x28] = 0xee;
mixer->regs[0x2e] = 0x00;
sb_dsp_set_stereo(&ess->dsp, mixer->regs[0x0e] & 2);
} else {
mixer->regs[mixer->index] = val;

switch (mixer->index) {
/* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */
case 0x02:
case 0x06:
case 0x08:
mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe);
break;

case 0x22:
case 0x26:
case 0x28:
mixer->regs[mixer->index - 0x20] = (val & 0xe);
break;

/* More compatibility:
SoundBlaster Pro selects register 020h for 030h, 022h for 032h,
026h for 036h, and 028h for 038h. */
case 0x30:
case 0x32:
case 0x36:
case 0x38:
mixer->regs[mixer->index - 0x10] = (val & 0xee);
break;

case 0x00:
case 0x04:
case 0x0a:
case 0x0c:
case 0x0e:
case 0x2e:
break;

default:
//sb_log("ess: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
break;
}
}

mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5) & 0x7] / 32768.0;
mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1) & 0x7] / 32768.0;
mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5) & 0x7] / 32768.0;
mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1) & 0x7] / 32768.0;
mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5) & 0x7] / 32768.0;
mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1) & 0x7] / 32768.0;
mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5) & 0x7] / 32768.0;
mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1) & 0x7] / 32768.0;
mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 5) & 0x7] / 32768.0;
mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 1) & 0x7] / 32768.0;

mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0;

mixer->output_filter = !(mixer->regs[0xe] & 0x20);
mixer->input_filter = !(mixer->regs[0xc] & 0x20);
mixer->in_filter_freq = ((mixer->regs[0xc] & 0x8) == 0) ? 3200 : 8800;
mixer->stereo = mixer->regs[0xe] & 2;
if (mixer->index == 0xe)
sb_dsp_set_stereo(&ess->dsp, val & 2);

switch (mixer->regs[0xc] & 6) {
case 2:
mixer->input_selector = INPUT_CD_L | INPUT_CD_R;
break;
case 6:
mixer->input_selector = INPUT_LINE_L | INPUT_LINE_R;
break;
default:
mixer->input_selector = INPUT_MIC;
break;
}

/* TODO: pcspeaker volume? Or is it not worth? */
}
}

uint8_t
ess_mixer_read(uint16_t addr, void *priv)
{
const ess_t *ess = (ess_t *) priv;
const ess_mixer_t *mixer = &ess->mixer_sbpro;

if (!(addr & 1))
return mixer->index;

switch (mixer->index) {
case 0x00:
case 0x04:
case 0x0a:
case 0x0c:
case 0x0e:
case 0x22:
case 0x26:
case 0x28:
case 0x2e:
case 0x02:
case 0x06:
case 0x30:
case 0x32:
case 0x36:
case 0x38:
return mixer->regs[mixer->index];

default:
//sb_log("ess: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
break;
}

return 0xff;
}

void
ess_mixer_reset(ess_t *ess)
{
ess_mixer_write(4, 0, ess);
ess_mixer_write(5, 0, ess);
}
Loading

0 comments on commit 4bb839a

Please sign in to comment.