From 012a450c9b5f3ded0110232b0cceb2e11ea97990 Mon Sep 17 00:00:00 2001 From: conan7123 Date: Thu, 2 Jan 2025 22:34:18 +0100 Subject: [PATCH 1/8] Add machine Compaq Presario 7100/7200 Series Machine (486) --- src/include/86box/machine.h | 1 + src/machine/m_at_386dx_486.c | 43 ++++++++++++++++++++++++++++++++++++ src/machine/machine_table.c | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c976d15a7..44a55d94f 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -593,6 +593,7 @@ extern int machine_at_pcm5330_init(const machine_t *); extern int machine_at_ecs486_init(const machine_t *); extern int machine_at_hot433a_init(const machine_t *); +extern int machine_at_pl4600c_init(const machine_t *); extern int machine_at_atc1415_init(const machine_t *); extern int machine_at_actionpc2600_init(const machine_t *); extern int machine_at_actiontower8400_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 253f7522a..1c35d7290 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -48,6 +48,7 @@ #include <86box/hwm.h> #include <86box/machine.h> #include <86box/plat_unused.h> +#include <86box/sound.h> int machine_at_acc386_init(const machine_t *model) @@ -1962,6 +1963,48 @@ machine_at_hot433a_init(const machine_t *model) return ret; } +int +machine_at_pl4600c_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/pl4600c/SST29EE010.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); /* Slot 01 */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); /* Slot 02 */ + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); /* Onboard */ + pci_register_slot(0x13, PCI_CARD_VIDEO, 0, 0, 0, 0); /* Onboard */ + + + device_add(&umc_hb4_device); + device_add(&umc_8886af_device); + device_add(&um8663af_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_ps2_ami_pci_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(&gd5430_onboard_pci_device); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(&ess_1688_device); + + if (fdc_current[0] == FDC_INTERNAL){ + fdd_set_turbo(0, 1); + fdd_set_turbo(1, 1); + } + + return ret; +} + int machine_at_atc1415_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ad0844cdc..a414bbd0d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8668,6 +8668,45 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[UMC 8881] Compaq Presario 7100/7200 Series 486", + .internal_name = "pl4600c", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_UMC_UM8881, + .init = machine_at_pl4600c_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_APM, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5430_onboard_pci_device, + .snd_device = &ess_1688_device, + .net_device = NULL + }, /* Has a VIA VT82C406 KBC+RTC that likely has identical commands to the VT82C42N. */ { .name = "[VIA VT82C496G] DFI G486VPA", From 45d952c8cf1e6dde31919e2ca882f8cf4a4166dd Mon Sep 17 00:00:00 2001 From: conan7123 Date: Thu, 2 Jan 2025 22:51:55 +0100 Subject: [PATCH 2/8] Add comment for pl4600c / Compaq Presario 7100 in machine table --- src/machine/machine_table.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index a414bbd0d..f5a0a9d1c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8668,6 +8668,8 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Compaq Presario 7100 / 7200 Series, using MiTAC/Trigon PL4600C (486). */ + /* Has a VIA VT82C42N KBC. */ { .name = "[UMC 8881] Compaq Presario 7100/7200 Series 486", .internal_name = "pl4600c", From cc73c0efe4b404af946041b9faf1f2c85afdca07 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 2 Jan 2025 23:49:50 +0100 Subject: [PATCH 3/8] Late day changes (January 2nd, 2025) Actually recognize the Trantor 228 MCA SCSI controller as such (bit 3 of status is for the PS/2 MCA bus type of the 128 controller) --- src/scsi/scsi_t128.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 3a49f599f..c878bbb91 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -509,6 +509,9 @@ t128_init(const device_t *info) if (!t128->bios_enabled && !(info->flags & DEVICE_MCA)) t128->status |= 0x80; + if (info->flags & DEVICE_MCA) + t128->status |= 0x08; + if (info->local == 0) timer_add(&t128->timer, t128_callback, t128, 0); From 06923a28007550bc8d060399382f513c7ffb850d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Jan 2025 00:15:28 +0100 Subject: [PATCH 4/8] Switched back to raw input - it appears it *does* work with the hook. --- src/86box.c | 10 ++++--- src/include/86box/86box.h | 2 +- src/qt/qt_main.cpp | 48 +++++++-------------------------- src/qt/qt_winrawinputfilter.cpp | 9 ++----- 4 files changed, 19 insertions(+), 50 deletions(-) diff --git a/src/86box.c b/src/86box.c index fc698a5ee..8fa74fd4b 100644 --- a/src/86box.c +++ b/src/86box.c @@ -206,7 +206,7 @@ int video_fullscreen_scale_maximized = 0; /* (C) Whether also apply when maximized. */ int do_auto_pause = 0; /* (C) Auto-pause the emulator on focus loss */ -int raw_input = 0; /* (C) Use raw input */ +int hook_enabled = 1; /* (C) Keyboard hook is enabled */ char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ int other_ide_present = 0; /* IDE controllers from non-IDE cards are @@ -453,6 +453,8 @@ delete_nvr_file(uint8_t flash) fn = NULL; } +extern void device_find_all_descs(void); + /* * Perform initial startup of the PC. * @@ -562,7 +564,7 @@ usage: printf("-S or --settings - show only the settings dialog\n"); #endif printf("-V or --vmname name - overrides the name of the running VM\n"); - printf("-W or --raw - uses raw input (compatibility-only outside Windows)\n"); + printf("-W or --nohook - disables keyboard hook (compatibility-only outside Windows)\n"); printf("-X or --clear what - clears the 'what' (cmos/flash/both)\n"); printf("-Y or --donothing - do not show any UI or run the emulation\n"); printf("-Z or --lastvmpath - the last parameter is VM path rather than config\n"); @@ -638,8 +640,8 @@ usage: dump_missing = 1; } else if (!strcasecmp(argv[c], "--donothing") || !strcasecmp(argv[c], "-Y")) { do_nothing = 1; - } else if (!strcasecmp(argv[c], "--raw") || !strcasecmp(argv[c], "-W")) { - raw_input = 1; + } else if (!strcasecmp(argv[c], "--nohook") || !strcasecmp(argv[c], "-W")) { + hook_enabled = 0; } else if (!strcasecmp(argv[c], "--keycodes") || !strcasecmp(argv[c], "-K")) { if ((c + 1) == argc) goto usage; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index fb4a182a0..ffa670b7e 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -165,7 +165,7 @@ extern _Atomic double mouse_y_error; /* Mouse error accumulator - Y */ #endif extern int pit_mode; /* (C) force setting PIT mode */ extern int fm_driver; /* (C) select FM sound driver */ -extern int raw_input; /* (C) Use raw input */ +extern int hook_enabled; /* (C) Keyboard hook is enabled */ /* Keyboard variables for future key combination redefinition. */ extern uint16_t key_prefix_1_1; diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index c602b9ea1..6da0b0285 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -43,6 +43,7 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin) #endif #ifdef Q_OS_WINDOWS +# include "qt_rendererstack.hpp" # include "qt_winrawinputfilter.hpp" # include "qt_winmanagerfilter.hpp" # include <86box/win.h> @@ -143,50 +144,20 @@ keyboard_getkeymap() } } -static void -kbd_handle(uint16_t scancode, uint16_t flags) -{ - if (flags & LLKHF_EXTENDED) - scancode |= 0x100; - - /* Translate the scan code to 9-bit */ - scancode = convert_scan_code(scancode); - - /* Remap it according to the list from the Registry */ - if ((scancode < (sizeof(scancode_map) / sizeof(scancode_map[0]))) && (scancode != scancode_map[scancode])) { - // pclog("Scan code remap: %03X -> %03X\n", scancode, scancode_map[scancode]); - scancode = scancode_map[scancode]; - } - - /* If it's not 0xFFFF, send it to the emulated - keyboard. - We use scan code 0xFFFF to mean a mapping that - has a prefix other than E0 and that is not E1 1D, - which is, for our purposes, invalid. */ - /* Translate right CTRL to left ALT if the user has so - chosen. */ - if ((scancode == 0x11d) && rctrl_is_lalt) - scancode = 0x038; - - /* Normal scan code pass through, pass it through as is if - it's not an invalid scan code. */ - if (scancode != 0xFFFF) - keyboard_input(!(flags & LLKHF_UP), scancode); - - main_window->checkFullscreenHotkey(); -} - static LRESULT CALLBACK emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { LPKBDLLHOOKSTRUCT lpKdhs = (LPKBDLLHOOKSTRUCT) lParam; /* Checks if CTRL was pressed. */ BOOL bCtrlDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1); + BOOL is_over_window = (GetForegroundWindow() == ((HWND) main_window->winId())); - if ((GetForegroundWindow() == ((HWND) main_window->winId())) && !(lpKdhs->scanCode & 0xff00)) - kbd_handle(lpKdhs->scanCode, lpKdhs->flags); + if (show_second_monitors) for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) { + const auto &secondaryRenderer = main_window->renderers[monitor_index]; + is_over_window = is_over_window && (GetForegroundWindow() == ((HWND) secondaryRenderer->winId())); + } - if ((nCode < 0) || (nCode != HC_ACTION) || (!mouse_capture && !video_fullscreen)) + if ((nCode < 0) || (nCode != HC_ACTION)/* || (!mouse_capture && !video_fullscreen)*/ || !is_over_window) return CallNextHookEx(NULL, nCode, wParam, lParam); else if ((lpKdhs->scanCode == 0x01) && (lpKdhs->flags & LLKHF_ALTDOWN) && !(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED))) @@ -480,7 +451,7 @@ main(int argc, char *argv[]) /* Force raw input if a debugger is present. */ if (IsDebuggerPresent()) { pclog("WARNING: Debugged detected, forcing raw input\n"); - raw_input = 1; + hook_enabled = 0; } /* Setup raw input */ @@ -547,7 +518,8 @@ main(int argc, char *argv[]) }); #ifdef Q_OS_WINDOWS - if (!raw_input) { + if (hook_enabled) { + /* Yes, low-level hooks *DO* work raw input, at least global ones. */ llhook = SetWindowsHookEx(WH_KEYBOARD_LL, emu_LowLevelKeyboardProc, NULL, 0); atexit([] () -> void { if (llhook) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 4ff515c49..2c11a068a 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -64,9 +64,7 @@ WindowsRawInputFilter::Register(MainWindow *window) .hwndTarget = nullptr} }; - if (raw_input && (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE)) - return std::unique_ptr(nullptr); - else if (!raw_input && RegisterRawInputDevices(&(rid[1]), 1, sizeof(rid[0])) == FALSE) + if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) return std::unique_ptr(nullptr); std::unique_ptr inputfilter(new WindowsRawInputFilter(window)); @@ -97,10 +95,7 @@ WindowsRawInputFilter::~WindowsRawInputFilter() .hwndTarget = NULL} }; - if (raw_input) - RegisterRawInputDevices(rid, 2, sizeof(rid[0])); - else - RegisterRawInputDevices(&(rid[1]), 1, sizeof(rid[0])); + RegisterRawInputDevices(rid, 2, sizeof(rid[0])); } bool From 509e1e596151d70eb5d52ab0c52a2def83485e05 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Jan 2025 00:27:21 +0100 Subject: [PATCH 5/8] cdrom/cdrom.c that I forgot to commit before. --- src/cdrom/cdrom.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index ac002ab65..4b01a109d 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1426,33 +1426,11 @@ cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf) buf[8] = 0x00; } +/* TODO: Actually implement this properly. */ void cdrom_get_q(cdrom_t *dev, uint8_t *buf, int *curtoctrk, uint8_t mode) { - track_info_t ti; - int first_track; - int last_track; - - if (dev != NULL) { - dev->ops->get_tracks(dev, &first_track, &last_track); - dev->ops->get_track_info(dev, *curtoctrk, 0, &ti); - buf[0] = (ti.attr << 4) & 0xf0; - buf[1] = ti.number; - buf[2] = bin2bcd(*curtoctrk + 1); - buf[3] = ti.m; - buf[4] = ti.s; - buf[5] = ti.f; - buf[6] = 0x00; - dev->ops->get_track_info(dev, 1, 0, &ti); - buf[7] = ti.m; - buf[8] = ti.s; - buf[9] = ti.f; - if (*curtoctrk >= (last_track + 1)) - *curtoctrk = 0; - else if (mode) - *curtoctrk = *curtoctrk + 1; - } else - memset(buf, 0x00, 10); + memset(buf, 0x00, 10); } uint8_t From 92e5ed6aaeaad4d665bce1f15d7e42067bc4ae53 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Jan 2025 00:47:35 +0100 Subject: [PATCH 6/8] Keyboard hook: Fixed segmentation fault when non-primary monitors are enabled but none is actually in use. --- src/qt/qt_main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 6da0b0285..20af6a13d 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -154,7 +154,8 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) if (show_second_monitors) for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) { const auto &secondaryRenderer = main_window->renderers[monitor_index]; - is_over_window = is_over_window && (GetForegroundWindow() == ((HWND) secondaryRenderer->winId())); + is_over_window = is_over_window && (secondaryRenderer != nullptr) && + (GetForegroundWindow() == ((HWND) secondaryRenderer->winId())); } if ((nCode < 0) || (nCode != HC_ACTION)/* || (!mouse_capture && !video_fullscreen)*/ || !is_over_window) From 370c560c3423d40747bd8051febb17a39bce2197 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Jan 2025 01:19:52 +0100 Subject: [PATCH 7/8] Only attempt Cue sheet parsing on files that end in .cue (in any letter case), fixes errors with some .ISO images. --- src/cdrom/cdrom.c | 4 ++-- src/cdrom/cdrom_image_backend.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 4b01a109d..6d993f24a 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2174,7 +2174,7 @@ cdrom_exit(uint8_t id) memset(dev->image_path, 0, sizeof(dev->image_path)); - pclog("cdrom_exit(%i): cdrom_insert(%i)\n", id, id); + cdrom_log("cdrom_exit(%i): cdrom_insert(%i)\n", id, id); cdrom_insert(id); } @@ -2252,7 +2252,7 @@ cdrom_reload(uint8_t id) #endif /* Signal media change to the emulated machine. */ - pclog("cdrom_reload(%i): cdrom_insert(%i)\n", id, id); + cdrom_log("cdrom_reload(%i): cdrom_insert(%i)\n", id, id); cdrom_insert(id); /* The drive was previously empty, transition directly to UNIT ATTENTION. */ diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c index 3c09cb56c..9d065a0cb 100644 --- a/src/cdrom/cdrom_image_backend.c +++ b/src/cdrom/cdrom_image_backend.c @@ -436,7 +436,7 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) const uint64_t seek = (sect + 150 - idx->start + idx->file_start) * trk->sector_size; cdrom_image_backend_log("cdrom_read_sector(%08X): track %02X, index %02X, %016" PRIX64 ", %016" PRIX64 ", %i\n", - sector, track, index, trk->start, trk->sector_size); + sector, track, index, idx->start, trk->sector_size); if (track_is_raw) raw_size = trk->sector_size; @@ -1477,12 +1477,18 @@ cdi_close(cd_img_t *cdi) int cdi_set_device(cd_img_t *cdi, const char *path) { - int ret; + uintptr_t ext = path + strlen(path) - strrchr(path, '.'); + int ret; - if ((ret = cdi_load_cue(cdi, path))) - return ret; + cdrom_image_backend_log("cdi_set_device(): %" PRIu64 ", %lli, %s\n", + ext, strlen(path), path + strlen(path) - ext + 1); - cdi_clear_tracks(cdi); + if ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE")) { + if ((ret = cdi_load_cue(cdi, path))) + return ret; + + cdi_clear_tracks(cdi); + } if ((ret = cdi_load_iso(cdi, path))) return ret; From 15715bbb79ad1b37cc00281a78c33422564343fd Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 7 Feb 2024 22:30:08 -0500 Subject: [PATCH 8/8] Add Ensoniq ES1370 Co-Authored-By: Cacodemon345 <38420290+Cacodemon345@users.noreply.github.com> --- src/include/86box/snd_akm4531.h | 22 + src/include/86box/sound.h | 1 + src/sound/snd_audiopci.c | 836 ++++++++++++++++++++++++-------- src/sound/sound.c | 1 + 4 files changed, 665 insertions(+), 195 deletions(-) create mode 100644 src/include/86box/snd_akm4531.h diff --git a/src/include/86box/snd_akm4531.h b/src/include/86box/snd_akm4531.h new file mode 100644 index 000000000..96f87b396 --- /dev/null +++ b/src/include/86box/snd_akm4531.h @@ -0,0 +1,22 @@ +/* + * 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. + * + * Ensoniq AudioPCI family emulation. + * + * Authors: Cacodemon345 + * + * Copyright 2024-2025 Cacodemon345. + */ +struct akm4531_t +{ + unsigned char registers[256]; +}; + +typedef struct akm4531_t akm4531_t; + +double akm4531_apply_master_vol(unsigned short sample); \ No newline at end of file diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index e5ae227fd..645d974dd 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -185,6 +185,7 @@ extern const device_t ess_soundpiper_32_mca_device; extern const device_t ess_chipchat_16_mca_device; /* Ensoniq AudioPCI */ +extern const device_t es1370_device; extern const device_t es1371_device; extern const device_t es1371_onboard_device; extern const device_t es1373_device; diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 7338a11fc..45b8d4c8c 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -8,15 +8,17 @@ * * Ensoniq AudioPCI family emulation. * - * - * * Authors: Sarah Walker, * RichardG, * Miran Grca, + * Jasmine Iwanek, + * Cacodemon345 * * Copyright 2008-2021 Sarah Walker. * Copyright 2021-2024 RichardG. - * Copyright 2021 Miran Grca. + * Copyright 2021 Miran Grca. + * Copyright 2024-2025 Jasmine Iwanek. + * Copyright 2024-2025 Cacodemon345. */ #include #include @@ -39,14 +41,15 @@ #include <86box/sound.h> #include <86box/timer.h> #include <86box/plat_unused.h> +#include <86box/snd_akm4531.h> #define N 16 -#define ES1371_NCoef 91 +#define ES137x_NCoef 91 -static float low_fir_es1371_coef[ES1371_NCoef]; +static float low_fir_es137x_coef[ES137x_NCoef]; -typedef struct es1371_t { +typedef struct es137x_t { uint8_t pci_command; uint8_t pci_serr; @@ -111,6 +114,9 @@ typedef struct es1371_t { int16_t out_l; int16_t out_r; + int16_t prev_out_l; + int16_t prev_out_r; + int32_t vol_l; int32_t vol_r; } dac[2], adc; @@ -130,11 +136,35 @@ typedef struct es1371_t { uint8_t pci_slot; int pos; - int16_t buffer[SOUNDBUFLEN * 2]; + int16_t buffer[WTBUFLEN * 2]; uint32_t type; -} es1371_t; + akm4531_t akm_codec; + + uint32_t calc_sample_rate; + uint32_t calc_sample_rate_synth; + + double interp_factor; + uint32_t interp_step; + + double interp_factor_synth; + uint32_t interp_step_synth; + + uint32_t step_pcm; + uint32_t step_synth; +} es137x_t; + +static const double akm4531_att_2dbstep_5bits[] = { + 25.0, 32.0, 41.0, 51.0, 65.0, 82.0, 103.0, 130.0, + 164.0, 206.0, 260.0, 327.0, 412.0, 519.0, 653.0, 822.0, + 1036.0, 1304.0, 1641.0, 2067.0, 2602.0, 3276.0, 4125.0, 5192.0, + 6537.0, 8230.0, 10362.0, 13044.0, 16422.0, 20674.0, 26027.0, 32767.0 +}; + +static double akm4531_gain_2dbstep_5bits[0x20]; + +#define AUDIOPCI_ES1370 0x50001271 #define AUDIOPCI_ES1371 0x13710200 #define AUDIOPCI_ES1373 0x13710400 #define AUDIOPCI_CT5880 0x58800400 @@ -204,8 +234,8 @@ typedef struct es1371_t { #define FORMAT_MONO_16 2 #define FORMAT_STEREO_16 3 -static void es1371_fetch(es1371_t *dev, int dac_nr); -static void update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl); +static void es137x_fetch(es137x_t *dev, int dac_nr); +static void update_legacy(es137x_t *dev, uint32_t old_legacy_ctrl); #ifdef ENABLE_AUDIOPCI_LOG int audiopci_do_log = ENABLE_AUDIOPCI_LOG; @@ -226,7 +256,7 @@ audiopci_log(const char *fmt, ...) #endif static void -es1371_update_irqs(es1371_t *dev) +es137x_update_irqs(es137x_t *dev) { int irq = 0; @@ -257,63 +287,63 @@ es1371_update_irqs(es1371_t *dev) } static void -es1371_update_tx_irq(es1371_t *dev) +es137x_update_tx_irq(es137x_t *dev) { dev->uart_status &= ~UART_STATUS_TXINT; if (((dev->uart_ctrl & UART_CTRL_TXINTEN) == 0x20) && (dev->uart_status & UART_STATUS_TXRDY)) dev->uart_status |= UART_STATUS_TXINT; - es1371_update_irqs(dev); + es137x_update_irqs(dev); } static void -es1371_set_tx_irq(es1371_t *dev, int set) +es137x_set_tx_irq(es137x_t *dev, int set) { dev->uart_status &= ~UART_STATUS_TXRDY; if (set) dev->uart_status |= UART_STATUS_TXRDY; - es1371_update_tx_irq(dev); + es137x_update_tx_irq(dev); } static void -es1371_update_rx_irq(es1371_t *dev) +es137x_update_rx_irq(es137x_t *dev) { dev->uart_status &= ~UART_STATUS_RXINT; if ((dev->uart_ctrl & UART_CTRL_RXINTEN) && (dev->uart_status & UART_STATUS_RXRDY)) dev->uart_status |= UART_STATUS_RXINT; - es1371_update_irqs(dev); + es137x_update_irqs(dev); } static void -es1371_set_rx_irq(es1371_t *dev, int set) +es137x_set_rx_irq(es137x_t *dev, int set) { dev->uart_status &= ~UART_STATUS_RXRDY; if (set) dev->uart_status |= UART_STATUS_RXRDY; - es1371_update_rx_irq(dev); + es137x_update_rx_irq(dev); } static void -es1371_scan_fifo(es1371_t *dev) +es137x_scan_fifo(es137x_t *dev) { if (dev->read_fifo_pos != dev->write_fifo_pos) { dev->uart_data = dev->uart_fifo[dev->read_fifo_pos]; dev->read_fifo_pos = (dev->read_fifo_pos + 1) & 7; - es1371_set_rx_irq(dev, 1); + es137x_set_rx_irq(dev, 1); } else - es1371_set_rx_irq(dev, 0); + es137x_set_rx_irq(dev, 0); } static void -es1371_write_fifo(es1371_t *dev, uint8_t val) +es137x_write_fifo(es137x_t *dev, uint8_t val) { if (dev->write_fifo_pos < 8) { dev->uart_fifo[dev->write_fifo_pos] = val | UART_FIFO_BYTE_VALID; @@ -322,27 +352,89 @@ es1371_write_fifo(es1371_t *dev, uint8_t val) } static void -es1371_reset_fifo(es1371_t *dev) +es137x_reset_fifo(es137x_t *dev) { for (uint8_t i = 0; i < 8; i++) dev->uart_fifo[i] = 0x00000000; dev->read_fifo_pos = dev->write_fifo_pos = 0; - es1371_set_rx_irq(dev, 0); + es137x_set_rx_irq(dev, 0); } static void -es1371_reset(void *priv) +akm4531_reset(es137x_t *dev) { - es1371_t *dev = (es1371_t *) priv; + akm4531_t* codec = &dev->akm_codec; + + memset(codec->registers, 0, sizeof(codec->registers)); + + codec->registers[0] = 0x80; + codec->registers[1] = 0x80; + + for (int i = 0x02; i <= 0x0E; i++) { + codec->registers[i] = 0b10000110; + } + + codec->registers[0xf] = 0x80; + + codec->registers[0x17] = 0x3; + codec->registers[0x16] = 0x3; +} + +static double lerp(double v0, double v1, double t) { + return (1. - t) * v0 + t * v1; +} + +static void +es1370_calc_sample_rate(es137x_t *dev) +{ + if (dev->type != AUDIOPCI_ES1370) + return; + + dev->calc_sample_rate = 1411200 / (((dev->int_ctrl >> 16) & 0x1fff) + 2); + + //pclog("ES1370 calc sample rate %u\n", dev->calc_sample_rate); + + dev->interp_factor = 1.0; + dev->interp_step = 1; + + if (dev->calc_sample_rate >= 44100 || dev->calc_sample_rate < 11025) { + dev->interp_factor = 1.0; + dev->interp_step = 1; + dev->calc_sample_rate = 44100; + } + if (dev->calc_sample_rate == 22050) { + dev->interp_factor = 0.5; + dev->interp_step = 2; + } + if (dev->calc_sample_rate == 11025) { + dev->interp_factor = 0.25; + dev->interp_step = 4; + } + if ((((dev->int_ctrl >> 16) & 0x1fff) + 2) == 256) { + /* 5512.5 Hz */ + dev->interp_factor = 0.125; + dev->interp_step = 8; + dev->calc_sample_rate = 5512; + } + + dev->calc_sample_rate_synth = 44100 / (1 << ((dev->int_ctrl >> 12) & 3)); + dev->interp_factor_synth = 1. / (double)(1 << ((dev->int_ctrl >> 12) & 3)); + dev->interp_step_synth = (1 << ((dev->int_ctrl >> 12) & 3)); +} + +static void +es137x_reset(void *priv) +{ + es137x_t *dev = (es137x_t *) priv; nmi = 0; /* Default subsystem ID. */ dev->subsys_lock = 0x00; - *((uint16_t *) &dev->subsys_id[0]) = 0x1274; - *((uint16_t *) &dev->subsys_id[2]) = 0x1371; + *((uint16_t *) &dev->subsys_id[0]) = (dev->type == AUDIOPCI_ES1370) ? 0x4942 : 0x1274; + *((uint16_t *) &dev->subsys_id[2]) = (dev->type == AUDIOPCI_ES1370) ? 0x4c4c : 0x1371; /* Interrupt/Chip Select Control Register, Address 00H Addressable as byte, word, longword */ @@ -352,7 +444,7 @@ es1371_reset(void *priv) Addressable as longword only */ if (dev->type >= AUDIOPCI_CT5880) dev->int_status = 0x52080ec0; - else if (dev->type >= AUDIOPCI_ES1373) + else if (dev->type >= AUDIOPCI_ES1373 && dev->type != AUDIOPCI_ES1370) dev->int_status = 0x7f080ec0; else dev->int_status = 0x7ffffec0; @@ -441,17 +533,20 @@ es1371_reset(void *priv) dev->uart_fifo[i] = 0xffff0000; /* Reset the UART TX. */ - es1371_set_tx_irq(dev, 0); + es137x_set_tx_irq(dev, 0); /* Reset the UART (RX) FIFO. */ - es1371_reset_fifo(dev); + es137x_reset_fifo(dev); /* Update interrupts to ensure they're all correctly cleared. */ - es1371_update_irqs(dev); + es137x_update_irqs(dev); + + /* Reset the codec. */ + akm4531_reset(dev); } static uint32_t -es1371_read_frame_reg(es1371_t *dev, int frame, int page) +es137x_read_frame_reg(es137x_t *dev, int frame, int page) { uint32_t ret = 0xffffffff; @@ -559,7 +654,7 @@ es1371_read_frame_reg(es1371_t *dev, int frame, int page) } static void -es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) +es137x_write_frame_reg(es137x_t *dev, int frame, int page, uint32_t val) { switch (frame) { case 0x30: @@ -666,9 +761,9 @@ es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) } static uint8_t -es1371_inb(uint16_t port, void *priv) +es137x_inb(uint16_t port, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint8_t ret = 0xff; switch (port & 0x3f) { @@ -685,7 +780,7 @@ es1371_inb(uint16_t port, void *priv) break; case 0x03: ret = dev->int_ctrl >> 24; - if (dev->type < AUDIOPCI_ES1373) + if (dev->type < AUDIOPCI_ES1373 && dev->type != AUDIOPCI_ES1370) ret |= 0xfc; break; @@ -713,7 +808,7 @@ es1371_inb(uint16_t port, void *priv) Addressable as byte only */ case 0x08: ret = dev->uart_data; - es1371_set_rx_irq(dev, 0); + es137x_set_rx_irq(dev, 0); audiopci_log("[R] UART DATA = %02X\n", ret); break; @@ -758,19 +853,19 @@ es1371_inb(uint16_t port, void *priv) /* S/PDIF Channel Status Control Register, Address 1CH Addressable as byte, word, longword */ case 0x1c: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) ret = dev->spdif_chstatus & 0xff; break; case 0x1d: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) ret = dev->spdif_chstatus >> 8; break; case 0x1e: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) ret = dev->spdif_chstatus >> 16; break; case 0x1f: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) ret = dev->spdif_chstatus >> 24; break; @@ -790,17 +885,17 @@ es1371_inb(uint16_t port, void *priv) break; default: - audiopci_log("Bad es1371_inb: port=%04x\n", port); + audiopci_log("Bad es137x_inb: port=%04x\n", port); } - audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); + audiopci_log("es137x_inb: port=%04x ret=%02x\n", port, ret); return ret; } static uint16_t -es1371_inw(uint16_t port, void *priv) +es137x_inw(uint16_t port, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint16_t ret = 0xffff; switch (port & 0x3e) { @@ -811,7 +906,7 @@ es1371_inw(uint16_t port, void *priv) break; case 0x02: ret = (dev->int_ctrl >> 16) & 0xff0f; - if (dev->type < AUDIOPCI_ES1373) + if (dev->type < AUDIOPCI_ES1373 && dev->type != AUDIOPCI_ES1370) ret |= 0xfc00; break; @@ -836,11 +931,11 @@ es1371_inw(uint16_t port, void *priv) /* S/PDIF Channel Status Control Register, Address 1CH Addressable as byte, word, longword */ case 0x1c: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) ret = dev->spdif_chstatus & 0xffff; break; case 0x1e: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) ret = dev->spdif_chstatus >> 16; break; @@ -884,36 +979,39 @@ es1371_inw(uint16_t port, void *priv) case 0x34: case 0x38: case 0x3c: - ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page) & 0xffff; + ret = es137x_read_frame_reg(dev, port & 0x3c, dev->mem_page) & 0xffff; break; case 0x32: case 0x36: case 0x3a: case 0x3e: - ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page) >> 16; + ret = es137x_read_frame_reg(dev, port & 0x3c, dev->mem_page) >> 16; break; default: break; } - audiopci_log("es1371_inw: port=%04x ret=%04x\n", port, ret); + audiopci_log("es137x_inw: port=%04x ret=%04x\n", port, ret); return ret; } static uint32_t -es1371_inl(uint16_t port, void *priv) +es137x_inl(uint16_t port, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint32_t ret = 0xffffffff; + if (dev->type == AUDIOPCI_ES1370 && (port & 0x3c) == 0x14) + port = 0x10; + switch (port & 0x3c) { /* Interrupt/Chip Select Control Register, Address 00H Addressable as byte, word, longword */ case 0x00: ret = dev->int_ctrl & 0xff0fffff; - if (ret < AUDIOPCI_ES1373) + if (ret < AUDIOPCI_ES1373 && ret != AUDIOPCI_ES1370) ret |= 0xfc000000; break; @@ -940,6 +1038,8 @@ es1371_inl(uint16_t port, void *priv) /* CODEC Read Register, Address 14H Addressable as longword only */ case 0x14: + if (dev->type == AUDIOPCI_ES1370) + break; ret = dev->codec_ctrl | CODEC_READY; break; @@ -952,7 +1052,7 @@ es1371_inl(uint16_t port, void *priv) /* S/PDIF Channel Status Control Register, Address 1CH Addressable as byte, word, longword */ case 0x1c: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 || dev->type == AUDIOPCI_ES1370) ret = dev->spdif_chstatus; break; @@ -984,24 +1084,24 @@ es1371_inl(uint16_t port, void *priv) case 0x34: case 0x38: case 0x3c: - ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page); + ret = es137x_read_frame_reg(dev, port & 0x3c, dev->mem_page); break; default: break; } - audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret); + audiopci_log("es137x_inl: port=%04x ret=%08x\n", port, ret); return ret; } static void -es1371_outb(uint16_t port, uint8_t val, void *priv) +es137x_outb(uint16_t port, uint8_t val, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint32_t old_legacy_ctrl; - audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val); + audiopci_log("es137x_outb: port=%04x val=%02x\n", port, val); switch (port & 0x3f) { /* Interrupt/Chip Select Control Register, Address 00H @@ -1011,36 +1111,44 @@ es1371_outb(uint16_t port, uint8_t val, void *priv) dev->dac[0].addr = dev->dac[0].addr_latch; dev->dac[0].buffer_pos = 0; dev->dac[0].buffer_pos_end = 0; - es1371_fetch(dev, 0); + dev->dac[0].prev_out_l = 0; + dev->dac[0].prev_out_r = 0; + es137x_fetch(dev, 0); } if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) { dev->dac[1].addr = dev->dac[1].addr_latch; dev->dac[1].buffer_pos = 0; dev->dac[1].buffer_pos_end = 0; - es1371_fetch(dev, 1); + dev->dac[1].prev_out_l = 0; + dev->dac[1].prev_out_r = 0; + es137x_fetch(dev, 1); } + //pclog("INTCTRL 0x%02X\n", val & 0xff); dev->int_ctrl = (dev->int_ctrl & 0xffffff00) | val; break; case 0x01: dev->int_ctrl = (dev->int_ctrl & 0xffff00ff) | (val << 8); + es1370_calc_sample_rate(dev); break; case 0x02: dev->int_ctrl = (dev->int_ctrl & 0xff00ffff) | (val << 16); + es1370_calc_sample_rate(dev); break; case 0x03: dev->int_ctrl = (dev->int_ctrl & 0x00ffffff) | (val << 24); gameport_remap(dev->gameport, 0x200 | ((val & 0x03) << 3)); + es1370_calc_sample_rate(dev); break; /* Interrupt/Chip Select Status Register, Address 04H Addressable as longword only, but PCem implements byte access, which must be for a reason */ case 0x06: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 || dev->type == AUDIOPCI_ES1370) dev->int_status = (dev->int_status & 0xff08ffff) | (val << 16); break; case 0x07: - if (dev->type >= AUDIOPCI_CT5880) + if (dev->type >= AUDIOPCI_CT5880 || dev->type == AUDIOPCI_ES1370) dev->int_status = (dev->int_status & 0xd2ffffff) | (val << 24); break; @@ -1050,7 +1158,7 @@ es1371_outb(uint16_t port, uint8_t val, void *priv) audiopci_log("MIDI data = %02x\n", val); /* TX does not use FIFO. */ midi_raw_out_byte(val); - es1371_set_tx_irq(dev, 1); + es137x_set_tx_irq(dev, 1); break; /* UART Control Register, Address 09H @@ -1061,15 +1169,15 @@ es1371_outb(uint16_t port, uint8_t val, void *priv) if ((val & 0x03) == 0x03) { /* Reset TX */ - es1371_set_tx_irq(dev, 1); + es137x_set_tx_irq(dev, 1); /* Software reset */ - es1371_reset_fifo(dev); + es137x_reset_fifo(dev); } else { - es1371_set_tx_irq(dev, 1); + es137x_set_tx_irq(dev, 1); - es1371_update_tx_irq(dev); - es1371_update_rx_irq(dev); + es137x_update_tx_irq(dev); + es137x_update_rx_irq(dev); } break; @@ -1101,7 +1209,7 @@ es1371_outb(uint16_t port, uint8_t val, void *priv) case 0x1b: old_legacy_ctrl = dev->legacy_ctrl; dev->legacy_ctrl = (dev->legacy_ctrl & 0x00ffffff) | (val << 24); - es1371_update_irqs(dev); + es137x_update_irqs(dev); update_legacy(dev, old_legacy_ctrl); break; @@ -1131,21 +1239,21 @@ es1371_outb(uint16_t port, uint8_t val, void *priv) dev->int_status &= ~INT_STATUS_DAC1; if (!(dev->si_cr & SI_P2_INTR_EN)) dev->int_status &= ~INT_STATUS_DAC2; - es1371_update_irqs(dev); + es137x_update_irqs(dev); break; case 0x22: dev->si_cr = (dev->si_cr & 0xff80ffff) | ((val & 0x7f) << 16); break; default: - audiopci_log("Bad es1371_outb: port=%04x val=%02x\n", port, val); + audiopci_log("Bad es137x_outb: port=%04x val=%02x\n", port, val); } } static void -es1371_outw(uint16_t port, uint16_t val, void *priv) +es137x_outw(uint16_t port, uint16_t val, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint32_t old_legacy_ctrl; switch (port & 0x3f) { @@ -1156,19 +1264,27 @@ es1371_outw(uint16_t port, uint16_t val, void *priv) dev->dac[0].addr = dev->dac[0].addr_latch; dev->dac[0].buffer_pos = 0; dev->dac[0].buffer_pos_end = 0; - es1371_fetch(dev, 0); + dev->dac[0].prev_out_l = 0; + dev->dac[0].prev_out_r = 0; + dev->step_synth = dev->interp_step_synth; + es137x_fetch(dev, 0); } if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) { dev->dac[1].addr = dev->dac[1].addr_latch; dev->dac[1].buffer_pos = 0; dev->dac[1].buffer_pos_end = 0; - es1371_fetch(dev, 1); + dev->dac[1].prev_out_l = 0; + dev->dac[1].prev_out_r = 0; + dev->step_pcm = dev->interp_step; + es137x_fetch(dev, 1); } + //pclog("INTCTRL 0x%02X\n", val & 0xff); dev->int_ctrl = (dev->int_ctrl & 0xffff0000) | val; break; case 0x02: dev->int_ctrl = (dev->int_ctrl & 0x0000ffff) | (val << 16); gameport_remap(dev->gameport, 0x200 | ((val & 0x0300) >> 5)); + es1370_calc_sample_rate(dev); break; /* Memory Page Register, Address 0CH @@ -1179,6 +1295,17 @@ es1371_outw(uint16_t port, uint16_t val, void *priv) case 0x0e: break; + /* CODEC Write Register, Address 10H + Addressable as word, longword */ + case 0x10: + if (dev->type != AUDIOPCI_ES1370) + break; + + dev->akm_codec.registers[(val >> 8) & 0xFF] = val & 0xFF; + if ((val >> 8) == 0x16 && !(val & 1)) + akm4531_reset(dev); + break; + /* Legacy Control/Status Register, Address 18H Addressable as byte, word, longword */ case 0x18: @@ -1187,7 +1314,7 @@ es1371_outw(uint16_t port, uint16_t val, void *priv) case 0x1a: old_legacy_ctrl = dev->legacy_ctrl; dev->legacy_ctrl = (dev->legacy_ctrl & 0x0000ffff) | (val << 16); - es1371_update_irqs(dev); + es137x_update_irqs(dev); update_legacy(dev, old_legacy_ctrl); break; @@ -1208,7 +1335,7 @@ es1371_outw(uint16_t port, uint16_t val, void *priv) dev->int_status &= ~INT_STATUS_DAC1; if (!(dev->si_cr & SI_P2_INTR_EN)) dev->int_status &= ~INT_STATUS_DAC2; - es1371_update_irqs(dev); + es137x_update_irqs(dev); break; case 0x22: dev->si_cr = (dev->si_cr & 0xff80ffff) | ((val & 0x007f) << 16); @@ -1238,32 +1365,47 @@ es1371_outw(uint16_t port, uint16_t val, void *priv) } static void -es1371_outl(uint16_t port, uint32_t val, void *priv) +es137x_outl(uint16_t port, uint32_t val, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint32_t old_legacy_ctrl; - audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val); + audiopci_log("es137x_outl: port=%04x val=%08x\n", port, val); switch (port & 0x3f) { /* Interrupt/Chip Select Control Register, Address 00H Addressable as byte, word, longword */ case 0x00: + { + uint8_t dac1start = 0, dac2start = 0; if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) { dev->dac[0].addr = dev->dac[0].addr_latch; dev->dac[0].buffer_pos = 0; dev->dac[0].buffer_pos_end = 0; - es1371_fetch(dev, 0); + dev->dac[0].prev_out_l = 0; + dev->dac[0].prev_out_r = 0; + dac1start = 1; + es137x_fetch(dev, 0); } if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) { dev->dac[1].addr = dev->dac[1].addr_latch; dev->dac[1].buffer_pos = 0; dev->dac[1].buffer_pos_end = 0; - es1371_fetch(dev, 1); + dev->dac[1].prev_out_l = 0; + dev->dac[1].prev_out_r = 0; + dac2start = 1; + es137x_fetch(dev, 1); } + //pclog("INTCTRL 0x%02X\n", val & 0xff); dev->int_ctrl = val; gameport_remap(dev->gameport, 0x200 | ((val & 0x03000000) >> 21)); + es1370_calc_sample_rate(dev); + if (dac1start) + dev->step_synth = dev->interp_step_synth; + if (dac2start) + dev->step_pcm = dev->interp_step; break; + } /* Interrupt/Chip Select Status Register, Address 04H Addressable as longword only */ @@ -1271,7 +1413,7 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) audiopci_log("[W] STATUS = %08X\n", val); if (dev->type >= AUDIOPCI_CT5880) dev->int_status = (dev->int_status & 0xd208ffff) | (val & 0x2df70000); - else if (dev->type >= AUDIOPCI_ES1373) + else if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) dev->int_status = (dev->int_status & 0xff08ffff) | (val & 0x00f70000); break; @@ -1284,6 +1426,13 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) /* Sample Rate Converter Interface Register, Address 10H Addressable as longword only */ case 0x10: + if (dev->type == AUDIOPCI_ES1370) + { + dev->akm_codec.registers[(val >> 8) & 0xFF] = val & 0xFF; + if ((val >> 8) == 0x16 && !(val & 1)) + akm4531_reset(dev); + break; + } dev->sr_cir = val & 0xfff8ffff; /*Bits 16 to 18 are undefined*/ if (dev->sr_cir & SRC_RAM_WE) { dev->sr_ram[dev->sr_cir >> 25] = val & 0xffff; @@ -1334,6 +1483,8 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) /* CODEC Write Register, Address 14H Addressable as longword only */ case 0x14: + if (dev->type == AUDIOPCI_ES1370) + break; if (val & CODEC_READ) { dev->codec_ctrl &= 0x00ff0000; dev->codec_ctrl |= ac97_codec_readw(dev->codec, val >> 16); @@ -1354,7 +1505,7 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) old_legacy_ctrl = dev->legacy_ctrl; dev->legacy_ctrl = (dev->legacy_ctrl & 0x0000ffff) | (val & 0xffff0000); dev->legacy_ctrl |= LEGACY_INT; - es1371_update_irqs(dev); + es137x_update_irqs(dev); update_legacy(dev, old_legacy_ctrl); break; @@ -1372,7 +1523,7 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) dev->int_status &= ~INT_STATUS_DAC1; if (!(dev->si_cr & SI_P2_INTR_EN)) dev->int_status &= ~INT_STATUS_DAC2; - es1371_update_irqs(dev); + es137x_update_irqs(dev); break; /* DAC1 Channel Sample Count Register, Address 24H @@ -1397,7 +1548,7 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) case 0x34: case 0x38: case 0x3c: - es1371_write_frame_reg(dev, port & 0x3c, dev->mem_page, val); + es137x_write_frame_reg(dev, port & 0x3c, dev->mem_page, val); break; default: @@ -1406,7 +1557,7 @@ es1371_outl(uint16_t port, uint32_t val, void *priv) } static void -capture_event(es1371_t *dev, int type, int rw, uint16_t port) +capture_event(es137x_t *dev, int type, int rw, uint16_t port) { dev->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK); dev->legacy_ctrl |= type; @@ -1524,7 +1675,7 @@ capture_read_slave_dma(uint16_t port, void *priv) } static void -update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl) +update_legacy(es137x_t *dev, uint32_t old_legacy_ctrl) { if (old_legacy_ctrl & LEGACY_CAPTURE_SSCAPE) { switch ((old_legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) { @@ -1713,10 +1864,112 @@ update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl) } } +static uint8_t +es1370_pci_read(int func, int addr, void *priv) +{ + const es137x_t *dev = (es137x_t *) priv; + + if (func > 0) + return 0xff; + + if ((addr > 0x3f) && ((addr < 0xdc) || (addr > 0xe1))) + return 0x00; + + switch (addr) { + case 0x00: /* Vendor ID */ + return 0x74; /* Ensoniq */ + case 0x01: + return 0x12; + + case 0x02: /* Device ID */ + return 0x00; /* ES1370 */ + case 0x03: + return 0x50; + + case 0x04: /* Command TODO */ + return dev->pci_command; + case 0x05: + return dev->pci_serr; + + case 0x06: /* Status TODO */ + return 0x10; /* Supports ACPI */ + case 0x07: + return 0x00; + + case 0x08: /* Class Code & Revision ID */ + return 0x00; /* Revision ID - 0x00 is actual Ensoniq-branded ES1370 */ + case 0x09: + return 0x00; /* Multimedia audio device */ + case 0x0a: + return 0x01; + case 0x0b: + return 0x04; + +// case 0x0c: /* Cache Line Size TODO */ +// case 0x0d: /* Latency Timer TODO */ +// case 0x0e: /* Header Type TODO */ +// case 0x0f: /* BIST TODO */ + + case 0x10: /* Base Address TODO */ + return 0x01 | (dev->base_addr & 0xc0); /* memBaseAddr */ + case 0x11: + return dev->base_addr >> 8; + case 0x12: + return dev->base_addr >> 16; + case 0x13: + return dev->base_addr >> 24; + + case 0x2c: + return 0x42; /* Subsystem vendor ID */ + case 0x2d: + return 0x49; + case 0x2e: + return 0x4c; /* Subsystem product ID */ + case 0x2f: + return 0x4c; + +#if 0 + case 0x34: // TODO + return 0xdc; /* Capabilites pointer */ +#endif + + case 0x3c: + return dev->int_line; + case 0x3d: + return 0x01; /* INTA */ + + case 0x3e: + return 0xc; /* Minimum grant */ + case 0x3f: + return 0x80; /* Maximum latency */ + +#if 0 + case 0xdc: + return 0x01; /* Capabilities identifier */ + case 0xdd: + return 0x00; /* Next item pointer */ + case 0xde: + return 0x31; /* Power management capabilities */ + case 0xdf: + return 0x6c; + + case 0xe0: + return dev->pmcsr & 0xff; + case 0xe1: + return dev->pmcsr >> 8; +#endif + + default: + break; + } + + return 0x00; +} + static uint8_t es1371_pci_read(int func, int addr, void *priv) { - const es1371_t *dev = (es1371_t *) priv; + const es137x_t *dev = (es137x_t *) priv; if (func > 0) return 0xff; @@ -1780,7 +2033,7 @@ es1371_pci_read(int func, int addr, void *priv) return 0x80; /* Maximum latency */ case 0x40: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) return dev->subsys_lock; break; @@ -1806,42 +2059,93 @@ es1371_pci_read(int func, int addr, void *priv) } static void -es1371_io_set(es1371_t *dev, int set) +es137x_io_set(es137x_t *dev, int set) { if (dev->pci_command & PCI_COMMAND_IO) { io_handler(set, dev->base_addr, 0x0040, - es1371_inb, es1371_inw, es1371_inl, - es1371_outb, es1371_outw, es1371_outl, dev); + es137x_inb, es137x_inw, es137x_inl, + es137x_outb, es137x_outw, es137x_outl, dev); } } static void -es1371_pci_write(int func, int addr, uint8_t val, void *priv) +es1370_pci_write(int func, int addr, uint8_t val, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; if (func) return; switch (addr) { case 0x04: - es1371_io_set(dev, 0); + es137x_io_set(dev, 0); dev->pci_command = val & 0x05; - es1371_io_set(dev, 1); + es137x_io_set(dev, 1); break; case 0x05: dev->pci_serr = val & 1; break; case 0x10: - es1371_io_set(dev, 0); + es137x_io_set(dev, 0); dev->base_addr = (dev->base_addr & 0xffffff00) | (val & 0xc0); - es1371_io_set(dev, 1); + es137x_io_set(dev, 1); break; case 0x11: - es1371_io_set(dev, 0); + es137x_io_set(dev, 0); dev->base_addr = (dev->base_addr & 0xffff00c0) | (val << 8); - es1371_io_set(dev, 1); + es137x_io_set(dev, 1); + break; + case 0x12: + dev->base_addr = (dev->base_addr & 0xff00ffc0) | (val << 16); + break; + case 0x13: + dev->base_addr = (dev->base_addr & 0x00ffffc0) | (val << 24); + break; + + case 0x3c: + dev->int_line = val; + break; + + case 0xe0: + dev->pmcsr = (dev->pmcsr & 0xff00) | (val & 0x03); + break; + case 0xe1: + dev->pmcsr = (dev->pmcsr & 0x00ff) | ((val & 0x01) << 8); + break; + + default: + break; + } +} + +static void +es1371_pci_write(int func, int addr, uint8_t val, void *priv) +{ + es137x_t *dev = (es137x_t *) priv; + + if (func) + return; + + switch (addr) { + case 0x04: + es137x_io_set(dev, 0); + dev->pci_command = val & 0x05; + es137x_io_set(dev, 1); + break; + case 0x05: + dev->pci_serr = val & 1; + break; + + case 0x10: + es137x_io_set(dev, 0); + dev->base_addr = (dev->base_addr & 0xffffff00) | (val & 0xc0); + es137x_io_set(dev, 1); + break; + case 0x11: + es137x_io_set(dev, 0); + dev->base_addr = (dev->base_addr & 0xffff00c0) | (val << 8); + es137x_io_set(dev, 1); break; case 0x12: dev->base_addr = (dev->base_addr & 0xff00ffc0) | (val << 16); @@ -1860,7 +2164,7 @@ es1371_pci_write(int func, int addr, uint8_t val, void *priv) break; case 0x40: - if (dev->type >= AUDIOPCI_ES1373) + if (dev->type >= AUDIOPCI_ES1373 && dev->type < AUDIOPCI_ES1370) dev->subsys_lock = val; break; @@ -1877,7 +2181,7 @@ es1371_pci_write(int func, int addr, uint8_t val, void *priv) } static void -es1371_fetch(es1371_t *dev, int dac_nr) +es137x_fetch(es137x_t *dev, int dac_nr) { if (dev->si_cr & (dac_nr ? SI_P2_PAUSE : SI_P1_PAUSE)) return; @@ -1981,8 +2285,8 @@ low_fir_es1371(int dac_nr, int i, float NewSample) read_pos = (pos + 15) & (127 & ~15); n_coef = (16 - pos) & 15; - while (n_coef < ES1371_NCoef) { - out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos]; + while (n_coef < ES137x_NCoef) { + out += low_fir_es137x_coef[n_coef] * x[dac_nr][i][read_pos]; read_pos = (read_pos + 16) & (127 & ~15); n_coef += 16; } @@ -1997,13 +2301,13 @@ low_fir_es1371(int dac_nr, int i, float NewSample) } static void -es1371_next_sample_filtered(es1371_t *dev, int dac_nr, int out_idx) +es137x_next_sample_filtered(es137x_t *dev, int dac_nr, int out_idx) { int out_l; int out_r; if ((dev->dac[dac_nr].buffer_pos - dev->dac[dac_nr].buffer_pos_end) >= 0) - es1371_fetch(dev, dac_nr); + es137x_fetch(dev, dac_nr); out_l = dev->dac[dac_nr].buffer_l[dev->dac[dac_nr].buffer_pos & 63]; out_r = dev->dac[dac_nr].buffer_r[dev->dac[dac_nr].buffer_pos & 63]; @@ -2020,21 +2324,35 @@ es1371_next_sample_filtered(es1371_t *dev, int dac_nr, int out_idx) } static void -es1371_update(es1371_t *dev) +es137x_update(es137x_t *dev) { int32_t l; int32_t r; - l = (dev->dac[0].out_l * dev->dac[0].vol_l) >> 12; - l += ((dev->dac[1].out_l * dev->dac[1].vol_l) >> 12); - r = (dev->dac[0].out_r * dev->dac[0].vol_r) >> 12; - r += ((dev->dac[1].out_r * dev->dac[1].vol_r) >> 12); + if (dev->type == AUDIOPCI_ES1370) { + l = dev->dac[0].out_l * (((dev->akm_codec.registers[0x4] & 0x80) ? 0 : akm4531_gain_2dbstep_5bits[(dev->akm_codec.registers[0x4] & 0x1f)]) / 32767.0); + r = dev->dac[0].out_r * (((dev->akm_codec.registers[0x5] & 0x80) ? 0 : akm4531_gain_2dbstep_5bits[(dev->akm_codec.registers[0x5] & 0x1f)]) / 32767.0); - l >>= 1; - r >>= 1; + l += dev->dac[1].out_l * (((dev->akm_codec.registers[0x2] & 0x80) ? 0 : akm4531_gain_2dbstep_5bits[(dev->akm_codec.registers[0x2] & 0x1f)]) / 32767.0); + r += dev->dac[1].out_r * (((dev->akm_codec.registers[0x3] & 0x80) ? 0 : akm4531_gain_2dbstep_5bits[(dev->akm_codec.registers[0x3] & 0x1f)]) / 32767.0); - l = (((l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15; - r = (((r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15; + l >>= 1; + r >>= 1; + + l *= (((dev->akm_codec.registers[0x0] & 0x80) ? 0 : akm4531_att_2dbstep_5bits[(dev->akm_codec.registers[0x0] & 0x1f) ^ 0x1f]) / 32767.0); + r *= (((dev->akm_codec.registers[0x1] & 0x80) ? 0 : akm4531_att_2dbstep_5bits[(dev->akm_codec.registers[0x1] & 0x1f) ^ 0x1f]) / 32767.0); + } else { + l = (dev->dac[0].out_l * dev->dac[0].vol_l) >> 12; + l += ((dev->dac[1].out_l * dev->dac[1].vol_l) >> 12); + r = (dev->dac[0].out_r * dev->dac[0].vol_r) >> 12; + r += ((dev->dac[1].out_r * dev->dac[1].vol_r) >> 12); + + l >>= 1; + r >>= 1; + + l = (((l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15; + r = (((r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15; + } if (l < -32768) l = -32768; @@ -2045,16 +2363,16 @@ es1371_update(es1371_t *dev) else if (r > 32767) r = 32767; - for (; dev->pos < sound_pos_global; dev->pos++) { + for (; dev->pos < ((dev->type == AUDIOPCI_ES1370) ? wavetable_pos_global : sound_pos_global); dev->pos++) { dev->buffer[dev->pos * 2] = l; dev->buffer[dev->pos * 2 + 1] = r; } } static void -es1371_poll(void *priv) +es137x_poll(void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; int frac; int idx; int samp1_l; @@ -2064,21 +2382,42 @@ es1371_poll(void *priv) timer_advance_u64(&dev->dac[1].timer, dev->dac[1].latch); - es1371_scan_fifo(dev); + es137x_scan_fifo(dev); - es1371_update(dev); + es137x_update(dev); if (dev->int_ctrl & INT_DAC1_EN) { - if ((dev->type >= AUDIOPCI_ES1373) && (dev->int_ctrl & INT_DAC1_BYPASS)) { - /* SRC bypass. */ - if ((dev->dac[0].buffer_pos - dev->dac[0].buffer_pos_end) >= 0) - es1371_fetch(dev, 0); + if (((dev->type >= AUDIOPCI_ES1373) && (dev->int_ctrl & INT_DAC1_BYPASS)) || dev->type == AUDIOPCI_ES1370) { + if (dev->calc_sample_rate_synth != 44100 && dev->type == AUDIOPCI_ES1370) + { + if ((dev->dac[0].buffer_pos - dev->dac[0].buffer_pos_end) >= 0 && dev->step_synth >= dev->interp_step_synth) + es137x_fetch(dev, 0); - dev->dac[0].out_l = dev->dac[0].buffer_l[dev->dac[0].buffer_pos & 63]; - dev->dac[0].out_r = dev->dac[0].buffer_r[dev->dac[0].buffer_pos & 63]; - dev->dac[0].buffer_pos++; + if (dev->step_synth >= dev->interp_step_synth) { + dev->step_synth = 0; + } - goto dac0_count; + dev->dac[0].out_l = lerp(dev->dac[0].prev_out_l, dev->dac[0].buffer_l[(dev->dac[0].buffer_pos) & 63], (dev->step_synth + 1) * dev->interp_factor_synth); + dev->dac[0].out_r = lerp(dev->dac[0].prev_out_r, dev->dac[0].buffer_r[(dev->dac[0].buffer_pos) & 63], (dev->step_synth + 1) * dev->interp_factor_synth); + + dev->step_synth++; + if (dev->step_synth >= dev->interp_step_synth) { + dev->dac[0].prev_out_l = dev->dac[0].out_l; + dev->dac[0].prev_out_r = dev->dac[0].out_r; + dev->dac[0].buffer_pos++; + goto dac0_count; + } + } else { + /* SRC bypass. */ + if ((dev->dac[0].buffer_pos - dev->dac[0].buffer_pos_end) >= 0) + es137x_fetch(dev, 0); + + dev->dac[0].out_l = dev->dac[0].buffer_l[dev->dac[0].buffer_pos & 63]; + dev->dac[0].out_r = dev->dac[0].buffer_r[dev->dac[0].buffer_pos & 63]; + dev->dac[0].buffer_pos++; + + goto dac0_count; + } } else { frac = dev->dac[0].ac & 0x7fff; idx = dev->dac[0].ac >> 15; @@ -2092,14 +2431,14 @@ es1371_poll(void *priv) dev->dac[0].ac += dev->dac[0].vf; dev->dac[0].ac &= ((32 << 15) - 1); if ((dev->dac[0].ac >> (15 + 4)) != dev->dac[0].f_pos) { - es1371_next_sample_filtered(dev, 0, dev->dac[0].f_pos ? 16 : 0); + es137x_next_sample_filtered(dev, 0, dev->dac[0].f_pos ? 16 : 0); dev->dac[0].f_pos = (dev->dac[0].f_pos + 1) & 1; dac0_count: dev->dac[0].curr_samp_ct--; if (dev->dac[0].curr_samp_ct < 0) { dev->int_status |= INT_STATUS_DAC1; - es1371_update_irqs(dev); + es137x_update_irqs(dev); dev->dac[0].curr_samp_ct = dev->dac[0].samp_ct; } } @@ -2107,16 +2446,37 @@ dac0_count: } if (dev->int_ctrl & INT_DAC2_EN) { - if ((dev->type >= AUDIOPCI_ES1373) && (dev->int_ctrl & INT_DAC2_BYPASS)) { - /* SRC bypass. */ - if ((dev->dac[1].buffer_pos - dev->dac[1].buffer_pos_end) >= 0) - es1371_fetch(dev, 1); + if (((dev->type >= AUDIOPCI_ES1373) && (dev->int_ctrl & INT_DAC2_BYPASS)) || dev->type == AUDIOPCI_ES1370) { + if (dev->calc_sample_rate != 44100 && dev->type == AUDIOPCI_ES1370) + { + if ((dev->dac[1].buffer_pos - dev->dac[1].buffer_pos_end) >= 0 && dev->step_pcm >= dev->interp_step) + es137x_fetch(dev, 1); - dev->dac[1].out_l = dev->dac[1].buffer_l[dev->dac[1].buffer_pos & 63]; - dev->dac[1].out_r = dev->dac[1].buffer_r[dev->dac[1].buffer_pos & 63]; - dev->dac[1].buffer_pos++; + if (dev->step_pcm >= dev->interp_step) { + dev->step_pcm = 0; + } - goto dac1_count; + dev->dac[1].out_l = lerp(dev->dac[1].prev_out_l, dev->dac[1].buffer_l[(dev->dac[1].buffer_pos) & 63], (dev->step_pcm + 1) * dev->interp_factor); + dev->dac[1].out_r = lerp(dev->dac[1].prev_out_r, dev->dac[1].buffer_r[(dev->dac[1].buffer_pos) & 63], (dev->step_pcm + 1) * dev->interp_factor); + + dev->step_pcm++; + if (dev->step_pcm >= dev->interp_step) { + dev->dac[1].prev_out_l = dev->dac[1].out_l; + dev->dac[1].prev_out_r = dev->dac[1].out_r; + dev->dac[1].buffer_pos++; + goto dac1_count; + } + } else { + /* SRC bypass. */ + if ((dev->dac[1].buffer_pos - dev->dac[1].buffer_pos_end) >= 0) + es137x_fetch(dev, 1); + + dev->dac[1].out_l = dev->dac[1].buffer_l[dev->dac[1].buffer_pos & 63]; + dev->dac[1].out_r = dev->dac[1].buffer_r[dev->dac[1].buffer_pos & 63]; + dev->dac[1].buffer_pos++; + + goto dac1_count; + } } else { frac = dev->dac[1].ac & 0x7fff; idx = dev->dac[1].ac >> 15; @@ -2130,14 +2490,14 @@ dac0_count: dev->dac[1].ac += dev->dac[1].vf; dev->dac[1].ac &= ((32 << 15) - 1); if ((dev->dac[1].ac >> (15 + 4)) != dev->dac[1].f_pos) { - es1371_next_sample_filtered(dev, 1, dev->dac[1].f_pos ? 16 : 0); + es137x_next_sample_filtered(dev, 1, dev->dac[1].f_pos ? 16 : 0); dev->dac[1].f_pos = (dev->dac[1].f_pos + 1) & 1; dac1_count: dev->dac[1].curr_samp_ct--; if (dev->dac[1].curr_samp_ct < 0) { dev->int_status |= INT_STATUS_DAC2; - es1371_update_irqs(dev); + es137x_update_irqs(dev); dev->dac[1].curr_samp_ct = dev->dac[1].samp_ct; } } @@ -2146,11 +2506,11 @@ dac1_count: } static void -es1371_get_buffer(int32_t *buffer, int len, void *priv) +es137x_get_buffer(int32_t *buffer, int len, void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; - es1371_update(dev); + es137x_update(dev); for (int c = 0; c < len * 2; c++) buffer[c] += (dev->buffer[c] / 2); @@ -2158,10 +2518,22 @@ es1371_get_buffer(int32_t *buffer, int len, void *priv) dev->pos = 0; } +static void +es1370_filter_cd_audio(int channel, double *buffer, void *priv) +{ + const es137x_t *dev = (es137x_t *) priv; + double c = 0.0; + double mastervol = ((dev->akm_codec.registers[channel] & 0x80) ? 0 : akm4531_att_2dbstep_5bits[(dev->akm_codec.registers[channel] & 0x1f) ^ 0x1f]) / 32767.0; + double cdvol = ((dev->akm_codec.registers[channel + 0x6] & 0x80) ? 0 : akm4531_gain_2dbstep_5bits[(dev->akm_codec.registers[channel + 0x6] & 0x1f)]) / 32767.0; + + c = *buffer * mastervol * cdvol; + *buffer = c; +} + static void es1371_filter_cd_audio(int channel, double *buffer, void *priv) { - const es1371_t *dev = (es1371_t *) priv; + const es137x_t *dev = (es137x_t *) priv; double c; int cd = channel ? dev->cd_vol_r : dev->cd_vol_l; int master = channel ? dev->master_vol_r : dev->master_vol_l; @@ -2177,49 +2549,49 @@ sinc(double x) } static void -generate_es1371_filter(void) +generate_es137x_filter(void) { /* Cutoff frequency = 1 / 32 */ float fC = 1.0 / 32.0; float gain; int n; - for (n = 0; n < ES1371_NCoef; n++) { + for (n = 0; n < ES137x_NCoef; n++) { /* Blackman window */ - double w = 0.42 - (0.5 * cos((2.0 * n * M_PI) / (double) (ES1371_NCoef - 1))) + (0.08 * cos((4.0 * n * M_PI) / (double) (ES1371_NCoef - 1))); + double w = 0.42 - (0.5 * cos((2.0 * n * M_PI) / (double) (ES137x_NCoef - 1))) + (0.08 * cos((4.0 * n * M_PI) / (double) (ES137x_NCoef - 1))); /* Sinc filter */ - double h = sinc(2.0 * fC * ((double) n - ((double) (ES1371_NCoef - 1) / 2.0))); + double h = sinc(2.0 * fC * ((double) n - ((double) (ES137x_NCoef - 1) / 2.0))); /* Create windowed-sinc filter */ - low_fir_es1371_coef[n] = w * h; + low_fir_es137x_coef[n] = w * h; } - low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0; + low_fir_es137x_coef[(ES137x_NCoef - 1) / 2] = 1.0; gain = 0.0; - for (n = 0; n < ES1371_NCoef; n++) - gain += low_fir_es1371_coef[n] / (float) N; + for (n = 0; n < ES137x_NCoef; n++) + gain += low_fir_es137x_coef[n] / (float) N; gain /= 0.65; /* Normalise filter, to produce unity gain */ - for (n = 0; n < ES1371_NCoef; n++) - low_fir_es1371_coef[n] /= gain; + for (n = 0; n < ES137x_NCoef; n++) + low_fir_es137x_coef[n] /= gain; } static void -es1371_input_msg(void *priv, uint8_t *msg, uint32_t len) +es137x_input_msg(void *priv, uint8_t *msg, uint32_t len) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; for (uint32_t i = 0; i < len; i++) - es1371_write_fifo(dev, msg[i]); + es137x_write_fifo(dev, msg[i]); } static int -es1371_input_sysex(void *priv, uint8_t *buffer, uint32_t len, int abort) +es137x_input_sysex(void *priv, uint8_t *buffer, uint32_t len, int abort) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; uint32_t i = -1; audiopci_log("Abort = %i\n", abort); @@ -2229,7 +2601,7 @@ es1371_input_sysex(void *priv, uint8_t *buffer, uint32_t len, int abort) if (!abort) { for (i = 0; i < len; i++) { - es1371_write_fifo(dev, buffer[i]); + es137x_write_fifo(dev, buffer[i]); if (dev->uart_status & UART_STATUS_RXRDY) break; } @@ -2240,17 +2612,64 @@ es1371_input_sysex(void *priv, uint8_t *buffer, uint32_t len, int abort) return 7 - i; } +static void es137x_speed_changed(void *priv); + +static void * +es1370_init(const device_t *info) +{ + es137x_t *dev = malloc(sizeof(es137x_t)); + memset(dev, 0x00, sizeof(es137x_t)); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, es137x_input_msg, es137x_input_sysex, dev); + + wavetable_add_handler(es137x_get_buffer, dev); + sound_set_cd_audio_filter(es1370_filter_cd_audio, dev); + + dev->gameport = gameport_add(&gameport_pnp_device); + gameport_remap(dev->gameport, 0x200); + + pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1370_pci_read, es1370_pci_write, dev, &dev->pci_slot); + + timer_add(&dev->dac[1].timer, es137x_poll, dev, 1); + + generate_es137x_filter(); + + dev->dac[0].vol_l = 1 << 12; + dev->dac[0].vol_r = 1 << 12; + dev->dac[1].vol_l = 1 << 12; + dev->dac[1].vol_r = 1 << 12; + + dev->pcm_vol_l = 1 << 15; + dev->pcm_vol_r = 1 << 15; + dev->master_vol_l = 1 << 15; + dev->master_vol_r = 1 << 15; + + dev->type = AUDIOPCI_ES1370; + + es137x_reset(dev); + + es137x_speed_changed(dev); + + for (int i = 0; i < 0x20; i++) { + double attn = (12.0 - (i * 2.0)); + akm4531_gain_2dbstep_5bits[i] = pow(10, attn / 10.) * 32767.0; + } + + return dev; +} + static void * es1371_init(const device_t *info) { - es1371_t *dev = malloc(sizeof(es1371_t)); - memset(dev, 0x00, sizeof(es1371_t)); + es137x_t *dev = malloc(sizeof(es137x_t)); + memset(dev, 0x00, sizeof(es137x_t)); dev->type = info->local & 0xffffff00; if (device_get_config_int("receive_input")) - midi_in_handler(1, es1371_input_msg, es1371_input_sysex, dev); + midi_in_handler(1, es137x_input_msg, es137x_input_sysex, dev); - sound_add_handler(es1371_get_buffer, dev); + sound_add_handler(es137x_get_buffer, dev); sound_set_cd_audio_filter(es1371_filter_cd_audio, dev); dev->gameport = gameport_add(&gameport_pnp_device); @@ -2258,9 +2677,9 @@ es1371_init(const device_t *info) pci_add_card((info->local & 1) ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, dev, &dev->pci_slot); - timer_add(&dev->dac[1].timer, es1371_poll, dev, 1); + timer_add(&dev->dac[1].timer, es137x_poll, dev, 1); - generate_es1371_filter(); + generate_es137x_filter(); ac97_codec = &dev->codec; ac97_codec_count = 1; @@ -2269,27 +2688,40 @@ es1371_init(const device_t *info) if (!(info->local & 1)) device_add(ac97_codec_get(device_get_config_int("codec"))); - es1371_reset(dev); + es137x_reset(dev); return dev; } static void -es1371_close(void *priv) +es137x_close(void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; free(dev); } static void -es1371_speed_changed(void *priv) +es137x_speed_changed(void *priv) { - es1371_t *dev = (es1371_t *) priv; + es137x_t *dev = (es137x_t *) priv; - dev->dac[1].latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) SOUND_FREQ)); + dev->dac[1].latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) (dev->type == AUDIOPCI_ES1370 ? WT_FREQ : SOUND_FREQ))); } +static const device_config_t es1370_config[] = { + // clang-format off + { + .name = "receive_input", + .description = "Receive input (MIDI)", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + static const device_config_t es1371_config[] = { // clang-format off { @@ -2397,16 +2829,30 @@ static const device_config_t es1371_onboard_config[] = { // clang-format on }; +const device_t es1370_device = { + .name = "Ensoniq AudioPCI (ES1370)", + .internal_name = "es1370", + .flags = DEVICE_PCI, + .local = 0, + .init = es1370_init, + .close = es137x_close, + .reset = es137x_reset, + { .available = NULL }, + .speed_changed = es137x_speed_changed, + .force_redraw = NULL, + .config = es1370_config +}; + const device_t es1371_device = { .name = "Ensoniq AudioPCI (ES1371)", .internal_name = "es1371", .flags = DEVICE_PCI, .local = AUDIOPCI_ES1371, .init = es1371_init, - .close = es1371_close, - .reset = es1371_reset, + .close = es137x_close, + .reset = es137x_reset, .available = NULL, - .speed_changed = es1371_speed_changed, + .speed_changed = es137x_speed_changed, .force_redraw = NULL, .config = es1371_config }; @@ -2417,10 +2863,10 @@ const device_t es1371_onboard_device = { .flags = DEVICE_PCI, .local = AUDIOPCI_ES1371 | 1, .init = es1371_init, - .close = es1371_close, - .reset = es1371_reset, + .close = es137x_close, + .reset = es137x_reset, .available = NULL, - .speed_changed = es1371_speed_changed, + .speed_changed = es137x_speed_changed, .force_redraw = NULL, .config = es1371_onboard_config }; @@ -2431,10 +2877,10 @@ const device_t es1373_device = { .flags = DEVICE_PCI, .local = AUDIOPCI_ES1373, .init = es1371_init, - .close = es1371_close, - .reset = es1371_reset, + .close = es137x_close, + .reset = es137x_reset, .available = NULL, - .speed_changed = es1371_speed_changed, + .speed_changed = es137x_speed_changed, .force_redraw = NULL, .config = es1373_config }; @@ -2445,10 +2891,10 @@ const device_t es1373_onboard_device = { .flags = DEVICE_PCI, .local = AUDIOPCI_ES1373 | 1, .init = es1371_init, - .close = es1371_close, - .reset = es1371_reset, + .close = es137x_close, + .reset = es137x_reset, .available = NULL, - .speed_changed = es1371_speed_changed, + .speed_changed = es137x_speed_changed, .force_redraw = NULL, .config = es1371_onboard_config }; @@ -2459,10 +2905,10 @@ const device_t ct5880_device = { .flags = DEVICE_PCI, .local = AUDIOPCI_CT5880, .init = es1371_init, - .close = es1371_close, - .reset = es1371_reset, + .close = es137x_close, + .reset = es137x_reset, .available = NULL, - .speed_changed = es1371_speed_changed, + .speed_changed = es137x_speed_changed, .force_redraw = NULL, .config = ct5880_config }; @@ -2473,10 +2919,10 @@ const device_t ct5880_onboard_device = { .flags = DEVICE_PCI, .local = AUDIOPCI_CT5880 | 1, .init = es1371_init, - .close = es1371_close, - .reset = es1371_reset, + .close = es137x_close, + .reset = es137x_reset, .available = NULL, - .speed_changed = es1371_speed_changed, + .speed_changed = es137x_speed_changed, .force_redraw = NULL, .config = es1371_onboard_config }; diff --git a/src/sound/sound.c b/src/sound/sound.c index b1762eaff..28cb96629 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -153,6 +153,7 @@ static const SOUND_CARD sound_cards[] = { { &ess_soundpiper_32_mca_device }, { &cmi8338_device }, { &cmi8738_device }, + { &es1370_device }, { &es1371_device }, { &es1373_device }, { &ct5880_device },