From 4f3ae96b63b071a91610719144129c0263a1ff44 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 19 Jul 2020 03:24:45 +0200 Subject: [PATCH] Switched the OPL and NukedOPL code to VARCem's reworked (and cleaner) versions. --- src/include/86box/snd_opl.h | 76 +- src/include/86box/snd_opl_backend.h | 17 - src/include/86box/snd_opl_nuked.h | 35 + src/include/86box/snd_sb.h | 2 +- src/include/nukedopl.h | 151 --- src/sound/nukedopl.c | 1374 -------------------------- src/sound/snd_adlib.c | 2 +- src/sound/snd_adlibgold.c | 2 +- src/sound/snd_opl.c | 348 ++++--- src/sound/snd_opl_backend.c | 158 --- src/sound/snd_opl_nuked.c | 1404 +++++++++++++++++++++++++++ src/sound/snd_pas16.c | 2 +- src/sound/snd_sb.c | 130 ++- src/sound/snd_wss.c | 2 +- src/win/Makefile.mingw | 3 +- 15 files changed, 1806 insertions(+), 1900 deletions(-) delete mode 100644 src/include/86box/snd_opl_backend.h create mode 100644 src/include/86box/snd_opl_nuked.h delete mode 100644 src/include/nukedopl.h delete mode 100644 src/sound/nukedopl.c delete mode 100644 src/sound/snd_opl_backend.c create mode 100644 src/sound/snd_opl_nuked.c diff --git a/src/include/86box/snd_opl.h b/src/include/86box/snd_opl.h index 68fd93f1d..22a5473f4 100644 --- a/src/include/86box/snd_opl.h +++ b/src/include/86box/snd_opl.h @@ -1,31 +1,61 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -typedef struct opl_t -{ - int pos, chip_nr[2]; +/* + * 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. + * + * Definitions for the OPL interface. + * + * Version: @(#)snd_opl.h 1.0.3 2020/07/15 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * TheCollector1995, + * Sarah Walker, + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + */ +#ifndef SOUND_OPL_H +# define SOUND_OPL_H - int32_t buffer[SOUNDBUFLEN * 2], - buffer2[SOUNDBUFLEN * 2]; - pc_timer_t timers[2][2]; +typedef void (*tmrfunc)(void *priv, int timer, uint64_t period); + +/* Define an OPLx chip. */ +typedef struct { +#ifdef SOUND_OPL_NUKED_H + nuked_t *opl; +#else + void *opl; +#endif + int8_t is_opl3; + + uint16_t port; + uint8_t status; + uint8_t status_mask; + uint8_t timer_ctrl; + uint16_t timer[2]; + + pc_timer_t timers[2]; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; } opl_t; -extern uint8_t opl2_read(uint16_t a, void *priv); -extern void opl2_write(uint16_t a, uint8_t v, void *priv); -extern uint8_t opl2_l_read(uint16_t a, void *priv); -extern void opl2_l_write(uint16_t a, uint8_t v, void *priv); -extern uint8_t opl2_r_read(uint16_t a, void *priv); -extern void opl2_r_write(uint16_t a, uint8_t v, void *priv); -extern uint8_t opl3_read(uint16_t a, void *priv); -extern void opl3_write(uint16_t a, uint8_t v, void *priv); +extern uint8_t opl2_read(uint16_t port, void *); +extern void opl2_write(uint16_t port, uint8_t val, void *); +extern void opl2_init(opl_t *); +extern void opl2_update(opl_t *); -extern void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); -extern void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +extern uint8_t opl3_read(uint16_t port, void *); +extern void opl3_write(uint16_t port, uint8_t val, void *); +extern void opl3_init(opl_t *); +extern void opl3_update(opl_t *); -extern void opl2_init(opl_t *opl); -extern void opl3_init(opl_t *opl); -extern void opl2_update2(opl_t *opl); -extern void opl3_update2(opl_t *opl); +#endif /*SOUND_OPL_H*/ diff --git a/src/include/86box/snd_opl_backend.h b/src/include/86box/snd_opl_backend.h deleted file mode 100644 index 24120d036..000000000 --- a/src/include/86box/snd_opl_backend.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#ifdef __cplusplus -extern "C" { -#endif - void opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3); - void opl_write(int nr, uint16_t addr, uint8_t val); - uint8_t opl_read(int nr, uint16_t addr); - void opl_timer_over(int nr, int timer); - void opl2_update(int nr, int32_t *buffer, int samples); - void opl3_update(int nr, int32_t *buffer, int samples); - - extern int opl_type; -#ifdef __cplusplus -} -#endif diff --git a/src/include/86box/snd_opl_nuked.h b/src/include/86box/snd_opl_nuked.h new file mode 100644 index 000000000..ff2e1db30 --- /dev/null +++ b/src/include/86box/snd_opl_nuked.h @@ -0,0 +1,35 @@ +/* + * 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. + * + * Definitions for the NukedOPL3 driver. + * + * Version: @(#)snd_opl_nuked.h 1.0.5 2020/07/16 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + */ +#ifndef SOUND_OPL_NUKED_H +# define SOUND_OPL_NUKED_H + + +extern void * nuked_init(uint32_t sample_rate); +extern void nuked_close(void *); + +extern uint16_t nuked_write_addr(void *, uint16_t port, uint8_t val); +extern void nuked_write_reg(void *, uint16_t reg, uint8_t v); +extern void nuked_write_reg_buffered(void *, uint16_t reg, uint8_t v); + +extern void nuked_generate(void *, int32_t *buf); +extern void nuked_generate_resampled(void *, int32_t *buf); +extern void nuked_generate_stream(void *, int32_t *sndptr, uint32_t num); + + +#endif /*SOUND_OPL_NUKED_H*/ diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 5b33adcf5..2c8e0ce21 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -113,7 +113,7 @@ typedef struct sb_ct1745_mixer_t typedef struct sb_t { uint8_t opl_enabled; - opl_t opl; + opl_t opl, opl2; sb_dsp_t dsp; union { sb_ct1335_mixer_t mixer_sb2; diff --git a/src/include/nukedopl.h b/src/include/nukedopl.h deleted file mode 100644 index 0c766b1ae..000000000 --- a/src/include/nukedopl.h +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// Nuked OPL3 emulator. -// Thanks: -// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): -// Feedback and Rhythm part calculation information. -// forums.submarine.org.uk(carbon14, opl3): -// Tremolo and phase generator calculation information. -// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): -// OPL2 ROMs. -// siliconpr0n.org(John McMaster, digshadow): -// YMF262 and VRC VII decaps and die shots. -// -// version: 1.8 -// - -#ifndef NUKEDOPL_H -#define NUKEDOPL_H -#define OPL_WRITEBUF_SIZE 1024 -#define OPL_WRITEBUF_DELAY 1 - -//#include "dosbox.h" -#include -typedef signed int Bits; -typedef unsigned int Bitu; -typedef int8_t Bit8s; -typedef uint8_t Bit8u; -typedef int16_t Bit16s; -typedef uint16_t Bit16u; -typedef int32_t Bit32s; -typedef uint32_t Bit32u; -typedef int64_t Bit64s; -typedef uint64_t Bit64u; - -struct opl3_slot; -struct opl3_channel; -struct opl3_writebuf; -struct opl3_chip; - -struct opl3_slot { - struct opl3_channel *channel; - struct opl3_chip *chip; - Bit16s out; - Bit16s fbmod; - Bit16s *mod; - Bit16s prout; - Bit16s eg_rout; - Bit16s eg_out; - Bit8u eg_inc; - Bit8u eg_gen; - Bit8u eg_rate; - Bit8u eg_ksl; - Bit8u *trem; - Bit8u reg_vib; - Bit8u reg_type; - Bit8u reg_ksr; - Bit8u reg_mult; - Bit8u reg_ksl; - Bit8u reg_tl; - Bit8u reg_ar; - Bit8u reg_dr; - Bit8u reg_sl; - Bit8u reg_rr; - Bit8u reg_wf; - Bit8u key; - Bit32u pg_reset; - Bit32u pg_phase; - Bit16u pg_phase_out; - Bit8u slot_num; -}; - -struct opl3_channel { - struct opl3_slot *slots[2]; - struct opl3_channel *pair; - struct opl3_chip *chip; - Bit16s *out[4]; - Bit8u chtype; - Bit16u f_num; - Bit8u block; - Bit8u fb; - Bit8u con; - Bit8u alg; - Bit8u ksv; - Bit16u cha, chb; - Bit8u ch_num; -}; - -struct opl3_writebuf { - Bit64u time; - Bit16u reg; - Bit8u data; -}; - -struct opl3_chip { - struct opl3_channel channel[18]; - struct opl3_slot slot[36]; - Bit16u timer; - Bit64u eg_timer; - Bit8u eg_timerrem; - Bit8u eg_state; - Bit8u eg_add; - Bit8u newm; - Bit8u nts; - Bit8u rhy; - Bit8u vibpos; - Bit8u vibshift; - Bit8u tremolo; - Bit8u tremolopos; - Bit8u tremoloshift; - Bit32u noise; - Bit16s zeromod; - Bit32s mixbuff[2]; - Bit8u rm_hh_bit2; - Bit8u rm_hh_bit3; - Bit8u rm_hh_bit7; - Bit8u rm_hh_bit8; - Bit8u rm_tc_bit3; - Bit8u rm_tc_bit5; - //OPL3L - Bit32s rateratio; - Bit32s samplecnt; - Bit32s oldsamples[2]; - Bit32s samples[2]; - - Bit64u writebuf_samplecnt; - Bit32u writebuf_cur; - Bit32u writebuf_last; - Bit64u writebuf_lasttime; - struct opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; -}; - -void OPL3_Generate(struct opl3_chip *chip, Bit32s *buf); -void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf); -void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate); -Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val); -void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples); -#endif diff --git a/src/sound/nukedopl.c b/src/sound/nukedopl.c deleted file mode 100644 index ec580c772..000000000 --- a/src/sound/nukedopl.c +++ /dev/null @@ -1,1374 +0,0 @@ -// -// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// Nuked OPL3 emulator. -// Thanks: -// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): -// Feedback and Rhythm part calculation information. -// forums.submarine.org.uk(carbon14, opl3): -// Tremolo and phase generator calculation information. -// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): -// OPL2 ROMs. -// siliconpr0n.org(John McMaster, digshadow): -// YMF262 and VRC VII decaps and die shots. -// -// version: 1.8 -// - -#include -#include -#include -#include "nukedopl.h" - -#define RSM_FRAC 10 - -// Channel types - -enum { - ch_2op = 0, - ch_4op = 1, - ch_4op2 = 2, - ch_drum = 3 -}; - -// Envelope key types - -enum { - egk_norm = 0x01, - egk_drum = 0x02 -}; - - -// -// logsin table -// - -static const Bit16u logsinrom[256] = { - 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, - 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, - 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, - 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, - 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, - 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, - 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, - 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, - 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, - 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, - 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, - 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, - 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, - 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, - 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, - 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, - 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, - 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, - 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, - 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, - 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, - 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, - 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, - 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, - 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, - 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, - 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, - 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, - 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, - 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, - 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 -}; - -// -// exp table -// - -static const Bit16u exprom[256] = { - 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, - 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, - 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, - 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, - 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, - 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, - 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, - 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, - 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, - 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, - 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, - 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, - 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, - 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, - 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, - 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, - 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, - 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, - 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, - 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, - 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, - 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, - 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, - 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, - 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, - 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, - 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, - 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, - 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, - 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, - 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, - 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 -}; - -// -// freq mult table multiplied by 2 -// -// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 -// - -static const Bit8u mt[16] = { - 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 -}; - -// -// ksl table -// - -static const Bit8u kslrom[16] = { - 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 -}; - -static const Bit8u kslshift[4] = { - 8, 1, 2, 0 -}; - -// -// envelope generator constants -// - -static const Bit8u eg_incstep[4][4] = { - { 0, 0, 0, 0 }, - { 1, 0, 0, 0 }, - { 1, 0, 1, 0 }, - { 1, 1, 1, 0 } -}; - -// -// address decoding -// - -static const Bit8s ad_slot[0x20] = { - 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, - 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static const Bit8u ch_slot[18] = { - 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 -}; - -// -// Envelope generator -// - -typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(struct opl3_slot *slott); - -static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) -{ - if (level > 0x1fff) - { - level = 0x1fff; - } - return (exprom[level & 0xff] << 1) >> (level >> 8); -} - -static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - } - if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x100) - { - out = 0x1000; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if ((phase & 0x300) == 0x100) - { - neg = 0xffff; - } - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x80) - { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else - { - out = logsinrom[(phase << 1) & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x80) - { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else - { - out = logsinrom[(phase << 1) & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) -{ - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - } - return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - phase = (phase & 0x1ff) ^ 0x1ff; - } - out = phase << 3; - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static const envelope_sinfunc envelope_sin[8] = { - OPL3_EnvelopeCalcSin0, - OPL3_EnvelopeCalcSin1, - OPL3_EnvelopeCalcSin2, - OPL3_EnvelopeCalcSin3, - OPL3_EnvelopeCalcSin4, - OPL3_EnvelopeCalcSin5, - OPL3_EnvelopeCalcSin6, - OPL3_EnvelopeCalcSin7 -}; - -enum envelope_gen_num -{ - envelope_gen_num_attack = 0, - envelope_gen_num_decay = 1, - envelope_gen_num_sustain = 2, - envelope_gen_num_release = 3 -}; - -static void OPL3_EnvelopeUpdateKSL(struct opl3_slot *slot) -{ - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - - ((0x08 - slot->channel->block) << 5); - if (ksl < 0) - { - ksl = 0; - } - slot->eg_ksl = (Bit8u)ksl; -} - -static void OPL3_EnvelopeCalc(struct opl3_slot *slot) -{ - Bit8u nonzero; - Bit8u rate; - Bit8u rate_hi; - Bit8u rate_lo; - Bit8u reg_rate = 0; - Bit8u ks; - Bit8u eg_shift, shift; - Bit16u eg_rout; - Bit16s eg_inc; - Bit8u eg_off; - Bit8u reset = 0; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) - + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - if (slot->key && slot->eg_gen == envelope_gen_num_release) - { - reset = 1; - reg_rate = slot->reg_ar; - } - else - { - switch (slot->eg_gen) - { - case envelope_gen_num_attack: - reg_rate = slot->reg_ar; - break; - case envelope_gen_num_decay: - reg_rate = slot->reg_dr; - break; - case envelope_gen_num_sustain: - if (!slot->reg_type) - { - reg_rate = slot->reg_rr; - } - break; - case envelope_gen_num_release: - reg_rate = slot->reg_rr; - break; - } - } - slot->pg_reset = reset; - ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); - nonzero = (reg_rate != 0); - rate = ks + (reg_rate << 2); - rate_hi = rate >> 2; - rate_lo = rate & 0x03; - if (rate_hi & 0x10) - { - rate_hi = 0x0f; - } - eg_shift = rate_hi + slot->chip->eg_add; - shift = 0; - if (nonzero) - { - if (rate_hi < 12) - { - if (slot->chip->eg_state) - { - switch (eg_shift) - { - case 12: - shift = 1; - break; - case 13: - shift = (rate_lo >> 1) & 0x01; - break; - case 14: - shift = rate_lo & 0x01; - break; - default: - break; - } - } - } - else - { - shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; - if (shift & 0x04) - { - shift = 0x03; - } - if (!shift) - { - shift = slot->chip->eg_state; - } - } - } - eg_rout = slot->eg_rout; - eg_inc = 0; - eg_off = 0; - // Instant attack - if (reset && rate_hi == 0x0f) - { - eg_rout = 0x00; - } - // Envelope off - if ((slot->eg_rout & 0x1f8) == 0x1f8) - { - eg_off = 1; - } - if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) - { - eg_rout = 0x1ff; - } - switch (slot->eg_gen) - { - case envelope_gen_num_attack: - if (!slot->eg_rout) - { - slot->eg_gen = envelope_gen_num_decay; - } - else if (slot->key && shift > 0 && rate_hi != 0x0f) - { - eg_inc = ((~slot->eg_rout) << shift) >> 4; - } - break; - case envelope_gen_num_decay: - if ((slot->eg_rout >> 4) == slot->reg_sl) - { - slot->eg_gen = envelope_gen_num_sustain; - } - else if (!eg_off && !reset && shift > 0) - { - eg_inc = 1 << (shift - 1); - } - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - if (!eg_off && !reset && shift > 0) - { - eg_inc = 1 << (shift - 1); - } - break; - } - slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; - // Key off - if (reset) - { - slot->eg_gen = envelope_gen_num_attack; - } - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_release; - } -} - -static void OPL3_EnvelopeKeyOn(struct opl3_slot *slot, Bit8u type) -{ - slot->key |= type; -} - -static void OPL3_EnvelopeKeyOff(struct opl3_slot *slot, Bit8u type) -{ - slot->key &= ~type; -} - -// -// Phase Generator -// - -static void OPL3_PhaseGenerate(struct opl3_slot *slot) -{ - struct opl3_chip *chip; - Bit16u f_num; - Bit32u basefreq; - Bit8u rm_xor, n_bit; - Bit32u noise; - Bit16u phase; - - chip = slot->chip; - f_num = slot->channel->f_num; - if (slot->reg_vib) - { - Bit8s range; - Bit8u vibpos; - - range = (f_num >> 7) & 7; - vibpos = slot->chip->vibpos; - - if (!(vibpos & 3)) - { - range = 0; - } - else if (vibpos & 1) - { - range >>= 1; - } - range >>= slot->chip->vibshift; - - if (vibpos & 4) - { - range = -range; - } - f_num += range; - } - basefreq = (f_num << slot->channel->block) >> 1; - phase = (Bit16u)(slot->pg_phase >> 9); - if (slot->pg_reset) - { - slot->pg_phase = 0; - } - slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; - // Rhythm mode - noise = chip->noise; - slot->pg_phase_out = phase; - if (slot->slot_num == 13) // hh - { - chip->rm_hh_bit2 = (phase >> 2) & 1; - chip->rm_hh_bit3 = (phase >> 3) & 1; - chip->rm_hh_bit7 = (phase >> 7) & 1; - chip->rm_hh_bit8 = (phase >> 8) & 1; - } - if (slot->slot_num == 17 && (chip->rhy & 0x20)) // tc - { - chip->rm_tc_bit3 = (phase >> 3) & 1; - chip->rm_tc_bit5 = (phase >> 5) & 1; - } - if (chip->rhy & 0x20) - { - rm_xor = (chip->rm_hh_bit2 ^ chip->rm_hh_bit7) - | (chip->rm_hh_bit3 ^ chip->rm_tc_bit5) - | (chip->rm_tc_bit3 ^ chip->rm_tc_bit5); - switch (slot->slot_num) - { - case 13: // hh - slot->pg_phase_out = rm_xor << 9; - if (rm_xor ^ (noise & 1)) - { - slot->pg_phase_out |= 0xd0; - } - else - { - slot->pg_phase_out |= 0x34; - } - break; - case 16: // sd - slot->pg_phase_out = (chip->rm_hh_bit8 << 9) - | ((chip->rm_hh_bit8 ^ (noise & 1)) << 8); - break; - case 17: // tc - slot->pg_phase_out = (rm_xor << 9) | 0x80; - break; - default: - break; - } - } - n_bit = ((noise >> 14) ^ noise) & 0x01; - chip->noise = (noise >> 1) | (n_bit << 22); -} - -// -// Slot -// - -static void OPL3_SlotWrite20(struct opl3_slot *slot, Bit8u data) -{ - if ((data >> 7) & 0x01) - { - slot->trem = &slot->chip->tremolo; - } - else - { - slot->trem = (Bit8u*)&slot->chip->zeromod; - } - slot->reg_vib = (data >> 6) & 0x01; - slot->reg_type = (data >> 5) & 0x01; - slot->reg_ksr = (data >> 4) & 0x01; - slot->reg_mult = data & 0x0f; -} - -static void OPL3_SlotWrite40(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_ksl = (data >> 6) & 0x03; - slot->reg_tl = data & 0x3f; - OPL3_EnvelopeUpdateKSL(slot); -} - -static void OPL3_SlotWrite60(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_ar = (data >> 4) & 0x0f; - slot->reg_dr = data & 0x0f; -} - -static void OPL3_SlotWrite80(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_sl = (data >> 4) & 0x0f; - if (slot->reg_sl == 0x0f) - { - slot->reg_sl = 0x1f; - } - slot->reg_rr = data & 0x0f; -} - -static void OPL3_SlotWriteE0(struct opl3_slot *slot, Bit8u data) -{ - slot->reg_wf = data & 0x07; - if (slot->chip->newm == 0x00) - { - slot->reg_wf &= 0x03; - } -} - -static void OPL3_SlotGenerate(struct opl3_slot *slot) -{ - slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); -} - -static void OPL3_SlotCalcFB(struct opl3_slot *slot) -{ - if (slot->channel->fb != 0x00) - { - slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); - } - else - { - slot->fbmod = 0; - } - slot->prout = slot->out; -} - -// -// Channel -// - -static void OPL3_ChannelSetupAlg(struct opl3_channel *channel); - -static void OPL3_ChannelUpdateRhythm(struct opl3_chip *chip, Bit8u data) -{ - struct opl3_channel *channel6; - struct opl3_channel *channel7; - struct opl3_channel *channel8; - Bit8u chnum; - - chip->rhy = data & 0x3f; - if (chip->rhy & 0x20) - { - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - channel6->out[0] = &channel6->slots[1]->out; - channel6->out[1] = &channel6->slots[1]->out; - channel6->out[2] = &chip->zeromod; - channel6->out[3] = &chip->zeromod; - channel7->out[0] = &channel7->slots[0]->out; - channel7->out[1] = &channel7->slots[0]->out; - channel7->out[2] = &channel7->slots[1]->out; - channel7->out[3] = &channel7->slots[1]->out; - channel8->out[0] = &channel8->slots[0]->out; - channel8->out[1] = &channel8->slots[0]->out; - channel8->out[2] = &channel8->slots[1]->out; - channel8->out[3] = &channel8->slots[1]->out; - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_drum; - } - OPL3_ChannelSetupAlg(channel6); - OPL3_ChannelSetupAlg(channel7); - OPL3_ChannelSetupAlg(channel8); - //hh - if (chip->rhy & 0x01) - { - OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); - } - //tc - if (chip->rhy & 0x02) - { - OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); - } - //tom - if (chip->rhy & 0x04) - { - OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); - } - //sd - if (chip->rhy & 0x08) - { - OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); - } - //bd - if (chip->rhy & 0x10) - { - OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); - OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); - OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); - } - } - else - { - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_2op; - OPL3_ChannelSetupAlg(&chip->channel[chnum]); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum); - } - } -} - -static void OPL3_ChannelWriteA0(struct opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0x300) | data; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); - } -} - -static void OPL3_ChannelWriteB0(struct opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); - channel->block = (data >> 2) & 0x07; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->block = channel->block; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); - } -} - -static void OPL3_ChannelSetupAlg(struct opl3_channel *channel) -{ - if (channel->chtype == ch_drum) - { - if (channel->ch_num == 7 || channel->ch_num == 8) - { - channel->slots[0]->mod = &channel->chip->zeromod; - channel->slots[1]->mod = &channel->chip->zeromod; - return; - } - switch (channel->alg & 0x01) - { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - break; - } - return; - } - if (channel->alg & 0x08) - { - return; - } - if (channel->alg & 0x04) - { - channel->pair->out[0] = &channel->chip->zeromod; - channel->pair->out[1] = &channel->chip->zeromod; - channel->pair->out[2] = &channel->chip->zeromod; - channel->pair->out[3] = &channel->chip->zeromod; - switch (channel->alg & 0x03) - { - case 0x00: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->chip->zeromod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[1]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x02: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x03: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[0]->out; - channel->out[2] = &channel->slots[1]->out; - channel->out[3] = &channel->chip->zeromod; - break; - } - } - else - { - switch (channel->alg & 0x01) - { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - } - } -} - -static void OPL3_ChannelWriteC0(struct opl3_channel *channel, Bit8u data) -{ - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; - channel->alg = channel->con; - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); - channel->alg = 0x08; - OPL3_ChannelSetupAlg(channel->pair); - } - else if (channel->chtype == ch_4op2) - { - channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); - channel->pair->alg = 0x08; - OPL3_ChannelSetupAlg(channel); - } - else - { - OPL3_ChannelSetupAlg(channel); - } - } - else - { - OPL3_ChannelSetupAlg(channel); - } - if (channel->chip->newm) - { - channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; - channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; - } - else - { - channel->cha = channel->chb = (Bit16u)~0; - } -} - -static void OPL3_ChannelKeyOn(struct opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); - } -} - -static void OPL3_ChannelKeyOff(struct opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); - } -} - -static void OPL3_ChannelSet4Op(struct opl3_chip *chip, Bit8u data) -{ - Bit8u bit; - Bit8u chnum; - for (bit = 0; bit < 6; bit++) - { - chnum = bit; - if (bit >= 3) - { - chnum += 9 - 3; - } - if ((data >> bit) & 0x01) - { - chip->channel[chnum].chtype = ch_4op; - chip->channel[chnum + 3].chtype = ch_4op2; - } - else - { - chip->channel[chnum].chtype = ch_2op; - chip->channel[chnum + 3].chtype = ch_2op; - } - } -} - -void OPL3_Generate(struct opl3_chip *chip, Bit32s *buf) -{ - Bit8u ii; - Bit8u jj; - Bit16s accm; - Bit8u shift = 0; - - buf[1] = chip->mixbuff[1]; - - for (ii = 0; ii < 15; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - chip->mixbuff[0] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); - } - - for (ii = 15; ii < 18; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - buf[0] = chip->mixbuff[0]; - - for (ii = 18; ii < 33; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - chip->mixbuff[1] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); - } - - for (ii = 33; ii < 36; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - if ((chip->timer & 0x3f) == 0x3f) - { - chip->tremolopos = (chip->tremolopos + 1) % 210; - } - if (chip->tremolopos < 105) - { - chip->tremolo = chip->tremolopos >> chip->tremoloshift; - } - else - { - chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; - } - - if ((chip->timer & 0x3ff) == 0x3ff) - { - chip->vibpos = (chip->vibpos + 1) & 7; - } - - chip->timer++; - - chip->eg_add = 0; - if (chip->eg_timer) - { - while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) - { - shift++; - } - if (shift > 12) - { - chip->eg_add = 0; - } - else - { - chip->eg_add = shift + 1; - } - } - - if (chip->eg_timerrem || chip->eg_state) - { - if (chip->eg_timer == 0xfffffffff) - { - chip->eg_timer = 0; - chip->eg_timerrem = 1; - } - else - { - chip->eg_timer++; - chip->eg_timerrem = 0; - } - } - - chip->eg_state ^= 1; - - while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) - { - if (!(chip->writebuf[chip->writebuf_cur].reg & 0x200)) - { - break; - } - chip->writebuf[chip->writebuf_cur].reg &= 0x1ff; - OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, - chip->writebuf[chip->writebuf_cur].data); - chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; - } - chip->writebuf_samplecnt++; -} - -void OPL3_GenerateResampled(struct opl3_chip *chip, Bit32s *buf) -{ - while (chip->samplecnt >= chip->rateratio) - { - chip->oldsamples[0] = chip->samples[0]; - chip->oldsamples[1] = chip->samples[1]; - OPL3_Generate(chip, chip->samples); - chip->samplecnt -= chip->rateratio; - } - buf[0] = (Bit32s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) - + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (Bit32s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) - + chip->samples[1] * chip->samplecnt) / chip->rateratio); - chip->samplecnt += 1 << RSM_FRAC; -} - -void OPL3_Reset(struct opl3_chip *chip, Bit32u samplerate) -{ - Bit8u slotnum; - Bit8u channum; - - memset(chip, 0, sizeof(struct opl3_chip)); - for (slotnum = 0; slotnum < 36; slotnum++) - { - chip->slot[slotnum].chip = chip; - chip->slot[slotnum].mod = &chip->zeromod; - chip->slot[slotnum].eg_rout = 0x1ff; - chip->slot[slotnum].eg_out = 0x1ff; - chip->slot[slotnum].eg_gen = envelope_gen_num_release; - chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; - chip->slot[slotnum].slot_num = slotnum; - } - for (channum = 0; channum < 18; channum++) - { - chip->channel[channum].slots[0] = &chip->slot[ch_slot[channum]]; - chip->channel[channum].slots[1] = &chip->slot[ch_slot[channum] + 3]; - chip->slot[ch_slot[channum]].channel = &chip->channel[channum]; - chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum]; - if ((channum % 9) < 3) - { - chip->channel[channum].pair = &chip->channel[channum + 3]; - } - else if ((channum % 9) < 6) - { - chip->channel[channum].pair = &chip->channel[channum - 3]; - } - chip->channel[channum].chip = chip; - chip->channel[channum].out[0] = &chip->zeromod; - chip->channel[channum].out[1] = &chip->zeromod; - chip->channel[channum].out[2] = &chip->zeromod; - chip->channel[channum].out[3] = &chip->zeromod; - chip->channel[channum].chtype = ch_2op; - chip->channel[channum].cha = 0xffff; - chip->channel[channum].chb = 0xffff; - chip->channel[channum].ch_num = channum; - OPL3_ChannelSetupAlg(&chip->channel[channum]); - } - chip->noise = 1; - chip->rateratio = (samplerate << RSM_FRAC) / 49716; - chip->tremoloshift = 4; - chip->vibshift = 1; -} - -Bit32u OPL3_WriteAddr(struct opl3_chip *chip, Bit32u port, Bit8u val) -{ - Bit16u addr; - addr = val; - if ((port & 2) && (addr == 0x05 || chip->newm)) { - addr |= 0x100; - } - return addr; -} - -void OPL3_WriteReg(struct opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - switch (regm & 0xf0) - { - case 0x00: - if (high) - { - switch (regm & 0x0f) - { - case 0x04: - OPL3_ChannelSet4Op(chip, v); - break; - case 0x05: - chip->newm = v & 0x01; - break; - } - } - else - { - switch (regm & 0x0f) - { - case 0x08: - chip->nts = (v >> 6) & 0x01; - break; - } - } - break; - case 0x20: - case 0x30: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x40: - case 0x50: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x60: - case 0x70: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x80: - case 0x90: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xe0: - case 0xf0: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xa0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - case 0xb0: - if (regm == 0xbd && !high) - { - chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; - chip->vibshift = ((v >> 6) & 0x01) ^ 1; - OPL3_ChannelUpdateRhythm(chip, v); - } - else if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); - if (v & 0x20) - { - OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); - } - else - { - OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); - } - } - break; - case 0xc0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - } -} - -void OPL3_WriteRegBuffered(struct opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit64u time1, time2; - - if (chip->writebuf[chip->writebuf_last].reg & 0x200) - { - OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_last].reg & 0x1ff, - chip->writebuf[chip->writebuf_last].data); - - chip->writebuf_cur = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; - chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; - } - - chip->writebuf[chip->writebuf_last].reg = reg | 0x200; - chip->writebuf[chip->writebuf_last].data = v; - time1 = chip->writebuf_lasttime + OPL_WRITEBUF_DELAY; - time2 = chip->writebuf_samplecnt; - - if (time1 < time2) - { - time1 = time2; - } - - chip->writebuf[chip->writebuf_last].time = time1; - chip->writebuf_lasttime = time1; - chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; -} - -void OPL3_GenerateStream(struct opl3_chip *chip, Bit32s *sndptr, Bit32u numsamples) -{ - Bit32u i; - - for(i = 0; i < numsamples; i++) - { - OPL3_GenerateResampled(chip, sndptr); - sndptr += 2; - } -} diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 2b9dfb443..ef1b15f24 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -47,7 +47,7 @@ static void adlib_get_buffer(int32_t *buffer, int len, void *p) adlib_t *adlib = (adlib_t *)p; int c; - opl2_update2(&adlib->opl); + opl2_update(&adlib->opl); for (c = 0; c < len * 2; c++) buffer[c] += (int32_t)adlib->opl.buffer[c]; diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index b031a6835..1cd5bc188 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -646,7 +646,7 @@ static void adgold_get_buffer(int32_t *buffer, int len, void *p) int c; - opl3_update2(&adgold->opl); + opl3_update(&adgold->opl); adgold_update(adgold); for (c = 0; c < len * 2; c += 2) diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 9d64fc906..68b778d4b 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -1,222 +1,284 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ +/* + * 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. + * + * Interface to the actual OPL emulator. + * + * TODO: Finish re-working this into a device_t, which requires a + * poll-like function for "update" so the sound card can call + * that and get a buffer-full of sample data. + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * TheCollector1995, + * Sarah Walker, + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + */ #include #include #include #include #include +#define dbglog sound_card_log #include <86box/86box.h> +#include <86box/timer.h> #include "cpu.h" #include <86box/io.h> -#include <86box/timer.h> #include <86box/sound.h> #include <86box/snd_opl.h> -#include <86box/snd_opl_backend.h> +#include <86box/snd_opl_nuked.h> -/*Interfaces between 86Box and the actual OPL emulator*/ +enum { + STATUS_TIMER_1 = 0x40, + STATUS_TIMER_2 = 0x20, + STATUS_TIMER_ALL = 0x80 +}; + +enum { + CTRL_IRQ_RESET = 0x80, + CTRL_TIMER1_MASK = 0x40, + CTRL_TIMER2_MASK = 0x20, + CTRL_TIMER2_CTRL = 0x02, + CTRL_TIMER1_CTRL = 0x01 +}; -uint8_t -opl2_read(uint16_t a, void *priv) +static void +status_update(opl_t *dev) { - opl_t *opl = (opl_t *)priv; - - sub_cycles((int) (isa_timing * 8)); - opl2_update2(opl); - - return opl_read(0, a); + if (dev->status & (STATUS_TIMER_1 | STATUS_TIMER_2) & dev->status_mask) + dev->status |= STATUS_TIMER_ALL; + else + dev->status &= ~STATUS_TIMER_ALL; } -void -opl2_write(uint16_t a, uint8_t v, void *priv) +static void +timer_set(opl_t *dev, int timer, uint64_t period) { - opl_t *opl = (opl_t *)priv; - - opl2_update2(opl); - opl_write(0, a, v); - opl_write(1, a, v); + timer_on_auto(&dev->timers[timer], ((double) period) * 20.0); } -uint8_t -opl2_l_read(uint16_t a, void *priv) +static void +timer_over(opl_t *dev, int tmr) { - opl_t *opl = (opl_t *)priv; + if (tmr) { + dev->status |= STATUS_TIMER_2; + timer_set(dev, 1, dev->timer[1] * 16); + } else { + dev->status |= STATUS_TIMER_1; + timer_set(dev, 0, dev->timer[0] * 4); + } - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - - return opl_read(0, a); + status_update(dev); } -void -opl2_l_write(uint16_t a, uint8_t v, void *priv) +static void +timer_1(void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *dev = (opl_t *)priv; - opl2_update2(opl); - opl_write(0, a, v); + timer_over(dev, 0); } -uint8_t -opl2_r_read(uint16_t a, void *priv) +static void +timer_2(void *priv) { - opl_t *opl = (opl_t *)priv; + opl_t *dev = (opl_t *)priv; - sub_cycles((int)(isa_timing * 8)); - opl2_update2(opl); - - return opl_read(1, a); + timer_over(dev, 1); } -void -opl2_r_write(uint16_t a, uint8_t v, void *priv) +static uint8_t +opl_read(opl_t *dev, uint16_t port) { - opl_t *opl = (opl_t *)priv; + if (! (port & 1)) + return((dev->status & dev->status_mask) | (dev->is_opl3 ? 0x00 : 0x06)); - opl2_update2(opl); - opl_write(1, a, v); + if (dev->is_opl3 && ((port & 0x03) == 0x03)) + return(0x00); + + return(dev->is_opl3 ? 0x00 : 0xff); } -uint8_t -opl3_read(uint16_t a, void *priv) +static void +opl_write(opl_t *dev, uint16_t port, uint8_t val) { - opl_t *opl = (opl_t *)priv; + if (! (port & 1)) { + dev->port = nuked_write_addr(dev->opl, port, val) & 0x01ff; - sub_cycles((int)(isa_timing * 8)); - opl3_update2(opl); + if (! dev->is_opl3) + dev->port &= 0x00ff; - return opl_read(0, a); -} + return; + } + nuked_write_reg_buffered(dev->opl, dev->port, val); -void -opl3_write(uint16_t a, uint8_t v, void *priv) -{ - opl_t *opl = (opl_t *)priv; - - opl3_update2(opl); - opl_write(0, a, v); -} + switch (dev->port) { + case 0x02: // timer 1 + dev->timer[0] = 256 - val; + break; + case 0x03: // timer 2 + dev->timer[1] = 256 - val; + break; -void -opl2_update2(opl_t *opl) -{ - if (opl->pos < sound_pos_global) { - opl2_update(0, &opl->buffer[opl->pos << 1], sound_pos_global - opl->pos); - opl2_update(1, &opl->buffer2[opl->pos << 1], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) { - opl->buffer[(opl->pos << 1) + 1] = opl->buffer2[(opl->pos << 1) + 1]; - opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); - opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); - } + case 0x04: // timer control + if (val & CTRL_IRQ_RESET) { + dev->status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + status_update(dev); + return; + } + if ((val ^ dev->timer_ctrl) & CTRL_TIMER1_CTRL) { + if (val & CTRL_TIMER1_CTRL) + timer_set(dev, 0, dev->timer[0] * 4); + else + timer_set(dev, 0, 0); + } + if ((val ^ dev->timer_ctrl) & CTRL_TIMER2_CTRL) { + if (val & CTRL_TIMER2_CTRL) + timer_set(dev, 1, dev->timer[1] * 16); + else + timer_set(dev, 1, 0); + } + dev->status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; + dev->timer_ctrl = val; + break; } } -void -opl3_update2(opl_t *opl) +static void +opl_init(opl_t *dev, int is_opl3) { - if (opl->pos < sound_pos_global) { - opl3_update(0, &opl->buffer[(opl->pos << 1)], sound_pos_global - opl->pos); - for (; opl->pos < sound_pos_global; opl->pos++) { - opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2); - opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2); - } + memset(dev, 0x00, sizeof(opl_t)); + dev->is_opl3 = is_opl3; + + /* Create a NukedOPL object. */ + dev->opl = nuked_init(48000); + + timer_add(&dev->timers[0], timer_1, dev, 0); + timer_add(&dev->timers[1], timer_2, dev, 0); +} + + +void +opl_close(opl_t *dev) +{ + /* Release the NukedOPL object. */ + if (dev->opl) { + nuked_close(dev->opl); + dev->opl = NULL; } } -void -ym3812_timer_set_0(void *param, int timer, uint64_t period) +uint8_t +opl2_read(uint16_t port, void *priv) { - opl_t *opl = (opl_t *)param; + opl_t *dev = (opl_t *)priv; - if (period) - timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[0][timer]); + cycles -= ISA_CYCLES(8); + + opl2_update(dev); + + return(opl_read(dev, port)); } void -ym3812_timer_set_1(void *param, int timer, uint64_t period) +opl2_write(uint16_t port, uint8_t val, void *priv) { - opl_t *opl = (opl_t *)param; + opl_t *dev = (opl_t *)priv; - if (period) - timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[1][timer]); -} + opl2_update(dev); - -void -ymf262_timer_set(void *param, int timer, uint64_t period) -{ - opl_t *opl = (opl_t *)param; - - if (period) - timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); - else - timer_disable(&opl->timers[0][timer]); -} - - -static void -opl_timer_callback00(void *p) -{ - opl_timer_over(0, 0); -} - - -static void -opl_timer_callback01(void *p) -{ - opl_timer_over(0, 1); -} - - -static void -opl_timer_callback10(void *p) -{ - opl_timer_over(1, 0); -} - - -static void -opl_timer_callback11(void *p) -{ - opl_timer_over(1, 1); + opl_write(dev, port, val); } void -opl2_init(opl_t *opl) +opl2_init(opl_t *dev) { - opl_init(ym3812_timer_set_0, opl, 0, 0); - opl_init(ym3812_timer_set_1, opl, 1, 0); - - timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); - timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0); - timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0); + opl_init(dev, 0); } void -opl3_init(opl_t *opl) +opl2_update(opl_t *dev) { - opl_init(ymf262_timer_set, opl, 0, 1); + if (dev->pos >= sound_pos_global) + return; - timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); - timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); + nuked_generate_stream(dev->opl, + &dev->buffer[dev->pos * 2], + sound_pos_global - dev->pos); + + for (; dev->pos < sound_pos_global; dev->pos++) { + dev->buffer[dev->pos * 2] /= 2; + dev->buffer[(dev->pos * 2) + 1] = dev->buffer[dev->pos * 2]; + } +} + + +uint8_t +opl3_read(uint16_t port, void *priv) +{ + opl_t *dev = (opl_t *)priv; + + cycles -= ISA_CYCLES(8); + + opl3_update(dev); + + return(opl_read(dev, port)); +} + + +void +opl3_write(uint16_t port, uint8_t val, void *priv) +{ + opl_t *dev = (opl_t *)priv; + + opl3_update(dev); + + opl_write(dev, port, val); +} + + +void +opl3_init(opl_t *dev) +{ + opl_init(dev, 1); +} + + +/* API to sound interface. */ +void +opl3_update(opl_t *dev) +{ + if (dev->pos >= sound_pos_global) + return; + + nuked_generate_stream(dev->opl, + &dev->buffer[dev->pos * 2], + sound_pos_global - dev->pos); + + for (; dev->pos < sound_pos_global; dev->pos++) { + dev->buffer[dev->pos * 2] /= 2; + dev->buffer[(dev->pos * 2) + 1] /= 2; + } } diff --git a/src/sound/snd_opl_backend.c b/src/sound/snd_opl_backend.c deleted file mode 100644 index 03bdbd2ea..000000000 --- a/src/sound/snd_opl_backend.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright holders: Sarah Walker, SA1988 - see COPYING for more details -*/ -#include -#include -#include -#include - -#include <86box/86box.h> -#include -#include <86box/sound.h> -#include <86box/snd_opl_backend.h> -#include "cpu.h" -#include <86box/mem.h> - - -int opl_type = 0; - - -static struct -{ - struct opl3_chip opl3chip; - int addr; - int timer[2]; - uint8_t timer_ctrl; - uint8_t status_mask; - uint8_t status; - int is_opl3; - - void (*timer_callback)(void *param, int timer, uint64_t period); - void *timer_param; -} opl[2]; - - -enum -{ - STATUS_TIMER_1 = 0x40, - STATUS_TIMER_2 = 0x20, - STATUS_TIMER_ALL = 0x80 -}; - -enum -{ - CTRL_IRQ_RESET = 0x80, - CTRL_TIMER1_MASK = 0x40, - CTRL_TIMER2_MASK = 0x20, - CTRL_TIMER2_CTRL = 0x02, - CTRL_TIMER1_CTRL = 0x01 -}; - - -void -opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3) -{ - opl[nr].timer_callback = timer_callback; - opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = is_opl3; - - opl[nr].opl3chip.newm = 0; - OPL3_Reset(&opl[nr].opl3chip, 48000); -} - - -void -opl_status_update(int nr) -{ - if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) - opl[nr].status |= STATUS_TIMER_ALL; - else - opl[nr].status &= ~STATUS_TIMER_ALL; -} - - -void -opl_timer_over(int nr, int timer) -{ - if (!timer) { - opl[nr].status |= STATUS_TIMER_1; - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - } else { - opl[nr].status |= STATUS_TIMER_2; - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - } - - opl_status_update(nr); -} - - -void -opl_write(int nr, uint16_t addr, uint8_t val) -{ - if (!(addr & 1)) { - opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; - if (!opl[nr].is_opl3) - opl[nr].addr &= 0xff; - } else { - OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); - if (opl[nr].addr == 0x105) - opl[nr].opl3chip.newm = opl[nr].addr & 0x01; - - switch (opl[nr].addr) { - case 0x02: /*Timer 1*/ - opl[nr].timer[0] = 256 - val; - break; - case 0x03: /*Timer 2*/ - opl[nr].timer[1] = 256 - val; - break; - case 0x04: /*Timer control*/ - if (val & CTRL_IRQ_RESET) { /*IRQ reset*/ - opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); - opl_status_update(nr); - return; - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) { - if (val & CTRL_TIMER1_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); - else - opl[nr].timer_callback(opl[nr].timer_param, 0, 0); - } - if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) { - if (val & CTRL_TIMER2_CTRL) - opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); - else - opl[nr].timer_callback(opl[nr].timer_param, 1, 0); - } - opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; - opl[nr].timer_ctrl = val; - break; - } - } -} - - -uint8_t -opl_read(int nr, uint16_t addr) -{ - if (!(addr & 1)) - return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); - - if (opl[nr].is_opl3 && ((addr & 3) == 3)) - return 0x00; - - return opl[nr].is_opl3 ? 0 : 0xff; -} - - -void -opl2_update(int nr, int32_t *buffer, int samples) -{ - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); -} - - -void -opl3_update(int nr, int32_t *buffer, int samples) -{ - OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); -} diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c new file mode 100644 index 000000000..0a5124913 --- /dev/null +++ b/src/sound/snd_opl_nuked.c @@ -0,0 +1,1404 @@ +/* + * 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. + * + * Nuked OPL3 emulator. + * + * Thanks: + * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): + * Feedback and Rhythm part calculation information. + * forums.submarine.org.uk(carbon14, opl3): + * Tremolo and phase generator calculation information. + * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): + * OPL2 ROMs. + * siliconpr0n.org(John McMaster, digshadow): + * YMF262 and VRC VII decaps and die shots. + * + * Version: 1.8.0 + * + * Translation from C++ into C done by Miran Grca. + * + * **TODO** The OPL3 is a stereo chip, and, thus, always generates + * a two-sample stream of data, for the L and R channels, + * in that order. The OPL2, however, is mono. What should + * we generate for that? + * + * Version: @(#)snd_opl_nuked.c 1.0.5 2020/07/16 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * Alexey Khokholov (Nuke.YKT) + * + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2020 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2013-2018 Alexey Khokholov (Nuke.YKT) + */ +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/sound.h> +#include <86box/snd_opl_nuked.h> + + +#define WRBUF_SIZE 1024 +#define WRBUF_DELAY 1 +#define RSM_FRAC 10 + + +// Channel types +enum { + ch_2op = 0, + ch_4op = 1, + ch_4op2 = 2, + ch_drum = 3 +}; + +// Envelope key types +enum { + egk_norm = 0x01, + egk_drum = 0x02 +}; + +enum envelope_gen_num { + envelope_gen_num_attack = 0, + envelope_gen_num_decay = 1, + envelope_gen_num_sustain = 2, + envelope_gen_num_release = 3 +}; + + +struct chan; +struct chip; + +typedef struct slot { + struct chan *chan; + struct chip *dev; + int16_t out; + int16_t fbmod; + int16_t *mod; + int16_t prout; + int16_t eg_rout; + int16_t eg_out; + uint8_t eg_inc; + uint8_t eg_gen; + uint8_t eg_rate; + uint8_t eg_ksl; + uint8_t *trem; + uint8_t reg_vib; + uint8_t reg_type; + uint8_t reg_ksr; + uint8_t reg_mult; + uint8_t reg_ksl; + uint8_t reg_tl; + uint8_t reg_ar; + uint8_t reg_dr; + uint8_t reg_sl; + uint8_t reg_rr; + uint8_t reg_wf; + uint8_t key; + uint32_t pg_reset; + uint32_t pg_phase; + uint16_t pg_phase_out; + uint8_t slot_num; +} slot_t; + +typedef struct chan { + slot_t *slots[2]; + struct chan *pair; + struct chip *dev; + int16_t *out[4]; + uint8_t chtype; + uint16_t f_num; + uint8_t block; + uint8_t fb; + uint8_t con; + uint8_t alg; + uint8_t ksv; + uint16_t cha, + chb; + uint8_t ch_num; +} chan_t; + +typedef struct wrbuf { + uint64_t time; + uint16_t reg; + uint8_t data; +} wrbuf_t; + +typedef struct chip { + chan_t chan[18]; + slot_t slot[36]; + uint16_t timer; + uint64_t eg_timer; + uint8_t eg_timerrem; + uint8_t eg_state; + uint8_t eg_add; + uint8_t newm; + uint8_t nts; + uint8_t rhy; + uint8_t vibpos; + uint8_t vibshift; + uint8_t tremolo; + uint8_t tremolopos; + uint8_t tremoloshift; + uint32_t noise; + int16_t zeromod; + int32_t mixbuff[2]; + uint8_t rm_hh_bit2; + uint8_t rm_hh_bit3; + uint8_t rm_hh_bit7; + uint8_t rm_hh_bit8; + uint8_t rm_tc_bit3; + uint8_t rm_tc_bit5; + + //OPL3L + int32_t rateratio; + int32_t samplecnt; + int32_t oldsamples[2]; + int32_t samples[2]; + + uint64_t wrbuf_samplecnt; + uint32_t wrbuf_cur; + uint32_t wrbuf_last; + uint64_t wrbuf_lasttime; + wrbuf_t wrbuf[WRBUF_SIZE]; +} nuked_t; + + +// logsin table +static const uint16_t logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, + 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, + 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, + 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, + 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, + 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, + 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, + 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, + 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, + 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, + 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, + 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, + 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, + 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, + 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, + 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +// exp table +static const uint16_t exprom[256] = { + 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, + 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, + 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, + 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, + 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, + 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, + 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, + 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, + 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, + 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, + 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, + 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, + 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, + 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, + 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, + 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, + 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, + 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, + 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, + 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, + 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, + 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, + 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, + 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, + 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, + 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, + 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, + 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, + 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, + 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, + 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, + 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 +}; + +// freq mult table multiplied by 2 +// +// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 +static const uint8_t mt[16] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 +}; + +// ksl table +static const uint8_t kslrom[16] = { + 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 +}; + +static const uint8_t kslshift[4] = { + 8, 1, 2, 0 +}; + +// envelope generator constants +static const uint8_t eg_incstep[4][4] = { + { 0, 0, 0, 0 }, + { 1, 0, 0, 0 }, + { 1, 0, 1, 0 }, + { 1, 1, 1, 0 } +}; + +// address decoding +static const int8_t ad_slot[0x20] = { + 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, + 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static const uint8_t ch_slot[18] = { + 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 +}; + +// Envelope generator +typedef int16_t(*env_sinfunc)(uint16_t phase, uint16_t envelope); +typedef void(*env_genfunc)(slot_t *slot); + + +static int16_t +env_calc_exp(uint32_t level) +{ + if (level > 0x1fff) + level = 0x1fff; + + return((exprom[level & 0xff] << 1) >> (level >> 8)); +} + + +static int16_t +env_calc_sin0(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + uint16_t neg = 0; + + phase &= 0x3ff; + + if (phase & 0x0200) + neg = 0xffff; + + if (phase & 0x0100) + out = logsinrom[(phase & 0xff) ^ 0xff]; + else + out = logsinrom[phase & 0xff]; + + return(env_calc_exp(out + (env << 3)) ^ neg); +} + + +static int16_t +env_calc_sin1(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x3ff; + + if (phase & 0x0200) + out = 0x1000; + else if (phase & 0x0100) + out = logsinrom[(phase & 0xff) ^ 0xff]; + else + out = logsinrom[phase & 0xff]; + + return(env_calc_exp(out + (env << 3))); +} + + +static int16_t +env_calc_sin2(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x03ff; + + if (phase & 0x0100) + out = logsinrom[(phase & 0xff) ^ 0xff]; + else + out = logsinrom[phase & 0xff]; + + return(env_calc_exp(out + (env << 3))); +} + + +static int16_t +env_calc_sin3(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x03ff; + + if (phase & 0x0100) + out = 0x1000; + else + out = logsinrom[phase & 0xff]; + + return(env_calc_exp(out + (env << 3))); +} + + +static int16_t +env_calc_sin4(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + uint16_t neg = 0; + + phase &= 0x03ff; + + if ((phase & 0x0300) == 0x0100) + neg = 0xffff; + + if (phase & 0x0200) + out = 0x1000; + else if (phase & 0x80) + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + else + out = logsinrom[(phase << 1) & 0xff]; + + return(env_calc_exp(out + (env << 3)) ^ neg); +} + + +static int16_t +env_calc_sin5(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + + phase &= 0x03ff; + + if (phase & 0x0200) + out = 0x1000; + else if (phase & 0x80) + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + else + out = logsinrom[(phase << 1) & 0xff]; + + return(env_calc_exp(out + (env << 3))); +} + + +static int16_t +env_calc_sin6(uint16_t phase, uint16_t env) +{ + uint16_t neg = 0; + + phase &= 0x03ff; + + if (phase & 0x0200) + neg = 0xffff; + + return(env_calc_exp(env << 3) ^ neg); +} + + +static int16_t +env_calc_sin7(uint16_t phase, uint16_t env) +{ + uint16_t out = 0; + uint16_t neg = 0; + + phase &= 0x03ff; + + if (phase & 0x0200) { + neg = 0xffff; + phase = (phase & 0x01ff) ^ 0x01ff; + } + + out = phase << 3; + + return(env_calc_exp(out + (env << 3)) ^ neg); +} + + +static const env_sinfunc env_sin[8] = { + env_calc_sin0, + env_calc_sin1, + env_calc_sin2, + env_calc_sin3, + env_calc_sin4, + env_calc_sin5, + env_calc_sin6, + env_calc_sin7 +}; + + +static void +env_update_ksl(slot_t *slot) +{ + int16_t ksl = (kslrom[slot->chan->f_num >> 6] << 2) - + ((0x08 - slot->chan->block) << 5); + + if (ksl < 0) + ksl = 0; + + slot->eg_ksl = (uint8_t)ksl; +} + + +static void +env_calc(slot_t *slot) +{ + uint8_t nonzero; + uint8_t rate; + uint8_t rate_hi; + uint8_t rate_lo; + uint8_t reg_rate = 0; + uint8_t ks; + uint8_t eg_shift, shift; + uint16_t eg_rout; + int16_t eg_inc; + uint8_t eg_off; + uint8_t reset = 0; + + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + if (slot->key && slot->eg_gen == envelope_gen_num_release) { + reset = 1; + reg_rate = slot->reg_ar; + } else switch (slot->eg_gen) { + case envelope_gen_num_attack: + reg_rate = slot->reg_ar; + break; + + case envelope_gen_num_decay: + reg_rate = slot->reg_dr; + break; + + case envelope_gen_num_sustain: + if (! slot->reg_type) + reg_rate = slot->reg_rr; + break; + + case envelope_gen_num_release: + reg_rate = slot->reg_rr; + break; + } + + slot->pg_reset = reset; + ks = slot->chan->ksv >> ((slot->reg_ksr ^ 1) << 1); + nonzero = (reg_rate != 0); + rate = ks + (reg_rate << 2); + rate_hi = rate >> 2; + rate_lo = rate & 0x03; + if (rate_hi & 0x10) + rate_hi = 0x0f; + eg_shift = rate_hi + slot->dev->eg_add; + shift = 0; + + if (nonzero) { + if (rate_hi < 12) { + if (slot->dev->eg_state) switch (eg_shift) { + case 12: + shift = 1; + break; + + case 13: + shift = (rate_lo >> 1) & 0x01; + break; + + case 14: + shift = rate_lo & 0x01; + break; + + default: + break; + } + } else { + shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->dev->timer & 0x03]; + if (shift & 0x04) + shift = 0x03; + if (! shift) + shift = slot->dev->eg_state; + } + } + + eg_rout = slot->eg_rout; + eg_inc = 0; + eg_off = 0; + + // Instant attack + if (reset && rate_hi == 0x0f) + eg_rout = 0x00; + + // Envelope off + if ((slot->eg_rout & 0x1f8) == 0x1f8) + eg_off = 1; + + if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) + eg_rout = 0x1ff; + + switch (slot->eg_gen) { + case envelope_gen_num_attack: + if (! slot->eg_rout) + slot->eg_gen = envelope_gen_num_decay; + else if (slot->key && shift > 0 && rate_hi != 0x0f) + eg_inc = ((~slot->eg_rout) << shift) >> 4; + break; + + case envelope_gen_num_decay: + if ((slot->eg_rout >> 4) == slot->reg_sl) + slot->eg_gen = envelope_gen_num_sustain; + else if (!eg_off && !reset && shift > 0) + eg_inc = 1 << (shift - 1); + break; + + case envelope_gen_num_sustain: + case envelope_gen_num_release: + if (!eg_off && !reset && shift > 0) + eg_inc = 1 << (shift - 1); + break; + } + slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; + + // Key off + if (reset) + slot->eg_gen = envelope_gen_num_attack; + + if (! slot->key) + slot->eg_gen = envelope_gen_num_release; +} + + +static void +env_key_on(slot_t *slot, uint8_t type) +{ + slot->key |= type; +} + + +static void +env_key_off(slot_t *slot, uint8_t type) +{ + slot->key &= ~type; +} + + +static void +phase_generate(slot_t *slot) +{ + uint16_t f_num; + uint32_t basefreq; + uint8_t rm_xor, n_bit; + uint32_t noise; + uint16_t phase; + int8_t range; + uint8_t vibpos; + nuked_t *dev; + + dev = slot->dev; + f_num = slot->chan->f_num; + if (slot->reg_vib) { + range = (f_num >> 7) & 7; + vibpos = dev->vibpos; + + if (! (vibpos & 3)) + range = 0; + else if (vibpos & 1) + range >>= 1; + range >>= dev->vibshift; + + if (vibpos & 4) + range = -range; + f_num += range; + } + + basefreq = (f_num << slot->chan->block) >> 1; + phase = (uint16_t)(slot->pg_phase >> 9); + + if (slot->pg_reset) + slot->pg_phase = 0; + slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; + + // Rhythm mode + noise = dev->noise; + slot->pg_phase_out = phase; + if (slot->slot_num == 13) { // hh + dev->rm_hh_bit2 = (phase >> 2) & 1; + dev->rm_hh_bit3 = (phase >> 3) & 1; + dev->rm_hh_bit7 = (phase >> 7) & 1; + dev->rm_hh_bit8 = (phase >> 8) & 1; + } + if (slot->slot_num == 17 && (dev->rhy & 0x20)) { // tc + dev->rm_tc_bit3 = (phase >> 3) & 1; + dev->rm_tc_bit5 = (phase >> 5) & 1; + } + if (dev->rhy & 0x20) { + rm_xor = (dev->rm_hh_bit2 ^ dev->rm_hh_bit7) | + (dev->rm_hh_bit3 ^ dev->rm_tc_bit5) | + (dev->rm_tc_bit3 ^ dev->rm_tc_bit5); + + switch (slot->slot_num) { + case 13: // hh + slot->pg_phase_out = rm_xor << 9; + if (rm_xor ^ (noise & 1)) + slot->pg_phase_out |= 0xd0; + else + slot->pg_phase_out |= 0x34; + break; + + case 16: // sd + slot->pg_phase_out = (dev->rm_hh_bit8 << 9) | + ((dev->rm_hh_bit8 ^ (noise & 1)) << 8); + break; + + case 17: // tc + slot->pg_phase_out = (rm_xor << 9) | 0x80; + break; + + default: + break; + } + } + + n_bit = ((noise >> 14) ^ noise) & 0x01; + + dev->noise = (noise >> 1) | (n_bit << 22); +} + + +static void +slot_write_20(slot_t *slot, uint8_t data) +{ + if ((data >> 7) & 0x01) + slot->trem = &slot->dev->tremolo; + else + slot->trem = (uint8_t*)&slot->dev->zeromod; + + slot->reg_vib = (data >> 6) & 0x01; + slot->reg_type = (data >> 5) & 0x01; + slot->reg_ksr = (data >> 4) & 0x01; + slot->reg_mult = data & 0x0f; +} + + +static void +slot_write_40(slot_t *slot, uint8_t data) +{ + slot->reg_ksl = (data >> 6) & 0x03; + slot->reg_tl = data & 0x3f; + + env_update_ksl(slot); +} + + +static void +slot_write_60(slot_t *slot, uint8_t data) +{ + slot->reg_ar = (data >> 4) & 0x0f; + slot->reg_dr = data & 0x0f; +} + + +static void +slot_write_80(slot_t *slot, uint8_t data) +{ + slot->reg_sl = (data >> 4) & 0x0f; + + if (slot->reg_sl == 0x0f) + slot->reg_sl = 0x1f; + + slot->reg_rr = data & 0x0f; +} + + +static void +slot_write_e0(slot_t *slot, uint8_t data) +{ + slot->reg_wf = data & 0x07; + + if (slot->dev->newm == 0x00) + slot->reg_wf &= 0x03; +} + + +static void +slot_generate(slot_t *slot) +{ + slot->out = env_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, + slot->eg_out); +} + + +static void +slot_calc_fb(slot_t *slot) +{ + if (slot->chan->fb != 0x00) + slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->chan->fb); + else + slot->fbmod = 0; + + slot->prout = slot->out; +} + + +static void +channel_setup_alg(chan_t *ch) +{ + if (ch->chtype == ch_drum) { + if (ch->ch_num == 7 || ch->ch_num == 8) { + ch->slots[0]->mod = &ch->dev->zeromod; + ch->slots[1]->mod = &ch->dev->zeromod; + return; + } + + switch (ch->alg & 0x01) { + case 0x00: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->slots[0]->out; + break; + + case 0x01: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->dev->zeromod; + break; + } + return; + } + + if (ch->alg & 0x08) + return; + + if (ch->alg & 0x04) { + ch->pair->out[0] = &ch->dev->zeromod; + ch->pair->out[1] = &ch->dev->zeromod; + ch->pair->out[2] = &ch->dev->zeromod; + ch->pair->out[3] = &ch->dev->zeromod; + + switch (ch->alg & 0x03) { + case 0x00: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->pair->slots[0]->out; + ch->slots[0]->mod = &ch->pair->slots[1]->out; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->slots[1]->out; + ch->out[1] = &ch->dev->zeromod; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x01: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->pair->slots[0]->out; + ch->slots[0]->mod = &ch->dev->zeromod; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->pair->slots[1]->out; + ch->out[1] = &ch->slots[1]->out; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x02: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->dev->zeromod; + ch->slots[0]->mod = &ch->pair->slots[1]->out; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->pair->slots[0]->out; + ch->out[1] = &ch->slots[1]->out; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x03: + ch->pair->slots[0]->mod = &ch->pair->slots[0]->fbmod; + ch->pair->slots[1]->mod = &ch->dev->zeromod; + ch->slots[0]->mod = &ch->pair->slots[1]->out; + ch->slots[1]->mod = &ch->dev->zeromod; + ch->out[0] = &ch->pair->slots[0]->out; + ch->out[1] = &ch->slots[0]->out; + ch->out[2] = &ch->slots[1]->out; + ch->out[3] = &ch->dev->zeromod; + break; + } + } else switch (ch->alg & 0x01) { + case 0x00: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->slots[0]->out; + ch->out[0] = &ch->slots[1]->out; + ch->out[1] = &ch->dev->zeromod; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + + case 0x01: + ch->slots[0]->mod = &ch->slots[0]->fbmod; + ch->slots[1]->mod = &ch->dev->zeromod; + ch->out[0] = &ch->slots[0]->out; + ch->out[1] = &ch->slots[1]->out; + ch->out[2] = &ch->dev->zeromod; + ch->out[3] = &ch->dev->zeromod; + break; + } +} + + +static void +channel_update_rhythm(nuked_t *dev, uint8_t data) +{ + chan_t *ch6, *ch7, *ch8; + uint8_t chnum; + + dev->rhy = data & 0x3f; + if (dev->rhy & 0x20) { + ch6 = &dev->chan[6]; + ch7 = &dev->chan[7]; + ch8 = &dev->chan[8]; + ch6->out[0] = &ch6->slots[1]->out; + ch6->out[1] = &ch6->slots[1]->out; + ch6->out[2] = &dev->zeromod; + ch6->out[3] = &dev->zeromod; + ch7->out[0] = &ch7->slots[0]->out; + ch7->out[1] = &ch7->slots[0]->out; + ch7->out[2] = &ch7->slots[1]->out; + ch7->out[3] = &ch7->slots[1]->out; + ch8->out[0] = &ch8->slots[0]->out; + ch8->out[1] = &ch8->slots[0]->out; + ch8->out[2] = &ch8->slots[1]->out; + ch8->out[3] = &ch8->slots[1]->out; + + for (chnum = 6; chnum < 9; chnum++) + dev->chan[chnum].chtype = ch_drum; + + channel_setup_alg(ch6); + channel_setup_alg(ch7); + channel_setup_alg(ch8); + + // hh + if (dev->rhy & 0x01) + env_key_on(ch7->slots[0], egk_drum); + else + env_key_off(ch7->slots[0], egk_drum); + + // tc + if (dev->rhy & 0x02) + env_key_on(ch8->slots[1], egk_drum); + else + env_key_off(ch8->slots[1], egk_drum); + + // tom + if (dev->rhy & 0x04) + env_key_on(ch8->slots[0], egk_drum); + else + env_key_off(ch8->slots[0], egk_drum); + + // sd + if (dev->rhy & 0x08) + env_key_on(ch7->slots[1], egk_drum); + else + env_key_off(ch7->slots[1], egk_drum); + + // bd + if (dev->rhy & 0x10) { + env_key_on(ch6->slots[0], egk_drum); + env_key_on(ch6->slots[1], egk_drum); + } else { + env_key_off(ch6->slots[0], egk_drum); + env_key_off(ch6->slots[1], egk_drum); + } + } else { + for (chnum = 6; chnum < 9; chnum++) { + dev->chan[chnum].chtype = ch_2op; + + channel_setup_alg(&dev->chan[chnum]); + env_key_off(dev->chan[chnum].slots[0], egk_drum); + env_key_off(dev->chan[chnum].slots[1], egk_drum); + } + } +} + + +static void +channel_write_a0(chan_t *ch, uint8_t data) +{ + if (ch->dev->newm && ch->chtype == ch_4op2) + return; + + ch->f_num = (ch->f_num & 0x300) | data; + ch->ksv = (ch->block << 1) | ((ch->f_num >> (0x09 - ch->dev->nts)) & 0x01); + + env_update_ksl(ch->slots[0]); + env_update_ksl(ch->slots[1]); + + if (ch->dev->newm && ch->chtype == ch_4op) { + ch->pair->f_num = ch->f_num; + ch->pair->ksv = ch->ksv; + + env_update_ksl(ch->pair->slots[0]); + env_update_ksl(ch->pair->slots[1]); + } +} + + +static void +channel_write_b0(chan_t *ch, uint8_t data) +{ + if (ch->dev->newm && ch->chtype == ch_4op2) + return; + + ch->f_num = (ch->f_num & 0xff) | ((data & 0x03) << 8); + ch->block = (data >> 2) & 0x07; + ch->ksv = (ch->block << 1) | ((ch->f_num >> (0x09 - ch->dev->nts)) & 0x01); + + env_update_ksl(ch->slots[0]); + env_update_ksl(ch->slots[1]); + + if (ch->dev->newm && ch->chtype == ch_4op) { + ch->pair->f_num = ch->f_num; + ch->pair->block = ch->block; + ch->pair->ksv = ch->ksv; + + env_update_ksl(ch->pair->slots[0]); + env_update_ksl(ch->pair->slots[1]); + } +} + + +static void +channel_write_c0(chan_t *ch, uint8_t data) +{ + ch->fb = (data & 0x0e) >> 1; + ch->con = data & 0x01; + ch->alg = ch->con; + + if (ch->dev->newm) { + if (ch->chtype == ch_4op) { + ch->pair->alg = 0x04 | (ch->con << 1) | ch->pair->con; + ch->alg = 0x08; + channel_setup_alg(ch->pair); + } else if (ch->chtype == ch_4op2) { + ch->alg = 0x04 | (ch->pair->con << 1) | ch->con; + ch->pair->alg = 0x08; + channel_setup_alg(ch); + } else + channel_setup_alg(ch); + } else + channel_setup_alg(ch); + + if (ch->dev->newm) { + ch->cha = ((data >> 4) & 0x01) ? ~0 : 0; + ch->chb = ((data >> 5) & 0x01) ? ~0 : 0; + } else + ch->cha = ch->chb = (uint16_t)~0; +} + + +static void +channel_key_on(chan_t *ch) +{ + if (ch->dev->newm) { + if (ch->chtype == ch_4op) { + env_key_on(ch->slots[0], egk_norm); + env_key_on(ch->slots[1], egk_norm); + env_key_on(ch->pair->slots[0], egk_norm); + env_key_on(ch->pair->slots[1], egk_norm); + } else if (ch->chtype == ch_2op || ch->chtype == ch_drum) { + env_key_on(ch->slots[0], egk_norm); + env_key_on(ch->slots[1], egk_norm); + } + } else { + env_key_on(ch->slots[0], egk_norm); + env_key_on(ch->slots[1], egk_norm); + } +} + + +static void +channel_key_off(chan_t *ch) +{ + if (ch->dev->newm) { + if (ch->chtype == ch_4op) { + env_key_off(ch->slots[0], egk_norm); + env_key_off(ch->slots[1], egk_norm); + env_key_off(ch->pair->slots[0], egk_norm); + env_key_off(ch->pair->slots[1], egk_norm); + } else if (ch->chtype == ch_2op || ch->chtype == ch_drum) { + env_key_off(ch->slots[0], egk_norm); + env_key_off(ch->slots[1], egk_norm); + } + } else { + env_key_off(ch->slots[0], egk_norm); + env_key_off(ch->slots[1], egk_norm); + } +} + + +static void +channel_set_4op(nuked_t *dev, uint8_t data) +{ + uint8_t chnum; + uint8_t bit; + + for (bit = 0; bit < 6; bit++) { + chnum = bit; + + if (bit >= 3) + chnum += 9 - 3; + + if ((data >> bit) & 0x01) { + dev->chan[chnum].chtype = ch_4op; + dev->chan[chnum + 3].chtype = ch_4op2; + } else { + dev->chan[chnum].chtype = ch_2op; + dev->chan[chnum + 3].chtype = ch_2op; + } + } +} + + +uint16_t +nuked_write_addr(void *priv, uint16_t port, uint8_t val) +{ + nuked_t *dev = (nuked_t *)priv; + uint16_t addr; + + addr = val; + if ((port & 0x0002) && (addr == 0x0005 || dev->newm)) + addr |= 0x0100; + + return(addr); +} + + +void +nuked_write_reg(void *priv, uint16_t reg, uint8_t val) +{ + nuked_t *dev = (nuked_t *)priv; + uint8_t high = (reg >> 8) & 0x01; + uint8_t regm = reg & 0xff; + + switch (regm & 0xf0) { + case 0x00: + if (high) switch (regm & 0x0f) { + case 0x04: + channel_set_4op(dev, val); + break; + + case 0x05: + dev->newm = val & 0x01; + break; + } else switch (regm & 0x0f) { + case 0x08: + dev->nts = (val >> 6) & 0x01; + break; + } + break; + + case 0x20: + case 0x30: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_20(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0x40: + case 0x50: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_40(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0x60: + case 0x70: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_60(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0x80: + case 0x90: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_80(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + case 0xa0: + if ((regm & 0x0f) < 9) + channel_write_a0(&dev->chan[9 * high + (regm & 0x0f)], val); + break; + + case 0xb0: + if (regm == 0xbd && !high) { + dev->tremoloshift = (((val >> 7) ^ 1) << 1) + 2; + dev->vibshift = ((val >> 6) & 0x01) ^ 1; + channel_update_rhythm(dev, val); + } else if ((regm & 0x0f) < 9) { + channel_write_b0(&dev->chan[9 * high + (regm & 0x0f)], val); + + if (val & 0x20) + channel_key_on(&dev->chan[9 * high + (regm & 0x0f)]); + else + channel_key_off(&dev->chan[9 * high + (regm & 0x0f)]); + } + break; + + case 0xc0: + if ((regm & 0x0f) < 9) + channel_write_c0(&dev->chan[9 * high + (regm & 0x0f)], val); + break; + + case 0xe0: + case 0xf0: + if (ad_slot[regm & 0x1f] >= 0) + slot_write_e0(&dev->slot[18 * high + ad_slot[regm & 0x1f]], val); + break; + + } +} + + +void +nuked_write_reg_buffered(void *priv, uint16_t reg, uint8_t val) +{ + nuked_t *dev = (nuked_t *)priv; + uint64_t time1, time2; + + if (dev->wrbuf[dev->wrbuf_last].reg & 0x0200) { + nuked_write_reg(dev, dev->wrbuf[dev->wrbuf_last].reg & 0x01ff, + dev->wrbuf[dev->wrbuf_last].data); + + dev->wrbuf_cur = (dev->wrbuf_last + 1) % WRBUF_SIZE; + dev->wrbuf_samplecnt = dev->wrbuf[dev->wrbuf_last].time; + } + + dev->wrbuf[dev->wrbuf_last].reg = reg | 0x0200; + dev->wrbuf[dev->wrbuf_last].data = val; + time1 = dev->wrbuf_lasttime + WRBUF_DELAY; + time2 = dev->wrbuf_samplecnt; + + if (time1 < time2) + time1 = time2; + + dev->wrbuf[dev->wrbuf_last].time = time1; + dev->wrbuf_lasttime = time1; + dev->wrbuf_last = (dev->wrbuf_last + 1) % WRBUF_SIZE; +} + + +void +nuked_generate(void *priv, int32_t *bufp) +{ + nuked_t *dev = (nuked_t *)priv; + int16_t accm, shift = 0; + uint8_t i, j; + + bufp[1] = dev->mixbuff[1]; + + for (i = 0; i < 15; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + dev->mixbuff[0] = 0; + + for (i = 0; i < 18; i++) { + accm = 0; + + for (j = 0; j < 4; j++) + accm += *dev->chan[i].out[j]; + + dev->mixbuff[0] += (int16_t)(accm & dev->chan[i].cha); + } + for (i = 15; i < 18; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + bufp[0] = dev->mixbuff[0]; + + for (i = 18; i < 33; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + dev->mixbuff[1] = 0; + + for (i = 0; i < 18; i++) { + accm = 0; + + for (j = 0; j < 4; j++) + accm += *dev->chan[i].out[j]; + + dev->mixbuff[1] += (int16_t)(accm & dev->chan[i].chb); + } + + for (i = 33; i < 36; i++) { + slot_calc_fb(&dev->slot[i]); + env_calc(&dev->slot[i]); + phase_generate(&dev->slot[i]); + slot_generate(&dev->slot[i]); + } + + if ((dev->timer & 0x3f) == 0x3f) + dev->tremolopos = (dev->tremolopos + 1) % 210; + + if (dev->tremolopos < 105) + dev->tremolo = dev->tremolopos >> dev->tremoloshift; + else + dev->tremolo = (210 - dev->tremolopos) >> dev->tremoloshift; + + if ((dev->timer & 0x03ff) == 0x03ff) + dev->vibpos = (dev->vibpos + 1) & 7; + + dev->timer++; + dev->eg_add = 0; + + if (dev->eg_timer) { + while (shift < 36 && ((dev->eg_timer >> shift) & 1) == 0) + shift++; + + if (shift > 12) + dev->eg_add = 0; + else + dev->eg_add = shift + 1; + } + + if (dev->eg_timerrem || dev->eg_state) { + if (dev->eg_timer == 0xfffffffff) { + dev->eg_timer = 0; + dev->eg_timerrem = 1; + } else { + dev->eg_timer++; + dev->eg_timerrem = 0; + } + } + + dev->eg_state ^= 1; + + while (dev->wrbuf[dev->wrbuf_cur].time <= dev->wrbuf_samplecnt) { + if (! (dev->wrbuf[dev->wrbuf_cur].reg & 0x200)) + break; + + dev->wrbuf[dev->wrbuf_cur].reg &= 0x01ff; + + nuked_write_reg(dev, dev->wrbuf[dev->wrbuf_cur].reg, + dev->wrbuf[dev->wrbuf_cur].data); + + dev->wrbuf_cur = (dev->wrbuf_cur + 1) % WRBUF_SIZE; + } + + dev->wrbuf_samplecnt++; +} + + +void +nuked_generate_resampled(void *priv, int32_t *bufp) +{ + nuked_t *dev = (nuked_t *)priv; + + while (dev->samplecnt >= dev->rateratio) { + dev->oldsamples[0] = dev->samples[0]; + dev->oldsamples[1] = dev->samples[1]; + nuked_generate(dev, dev->samples); + dev->samplecnt -= dev->rateratio; + } + + bufp[0] = (int32_t)((dev->oldsamples[0] * (dev->rateratio - dev->samplecnt) + + dev->samples[0] * dev->samplecnt) / dev->rateratio); + bufp[1] = (int32_t)((dev->oldsamples[1] * (dev->rateratio - dev->samplecnt) + + dev->samples[1] * dev->samplecnt) / dev->rateratio); + + dev->samplecnt += 1 << RSM_FRAC; +} + + +void +nuked_generate_stream(void *priv, int32_t *sndptr, uint32_t num) +{ + nuked_t *dev = (nuked_t *)priv; + uint32_t i; + + for (i = 0; i < num; i++) { + nuked_generate_resampled(dev, sndptr); + sndptr += 2; + } +} + + +void * +nuked_init(uint32_t samplerate) +{ + nuked_t *dev; + uint8_t i; + + dev = (nuked_t *)malloc(sizeof(nuked_t)); + memset(dev, 0x00, sizeof(nuked_t)); + + for (i = 0; i < 36; i++) { + dev->slot[i].dev = dev; + dev->slot[i].mod = &dev->zeromod; + dev->slot[i].eg_rout = 0x01ff; + dev->slot[i].eg_out = 0x01ff; + dev->slot[i].eg_gen = envelope_gen_num_release; + dev->slot[i].trem = (uint8_t*)&dev->zeromod; + dev->slot[i].slot_num = i; + } + + for (i = 0; i < 18; i++) { + dev->chan[i].slots[0] = &dev->slot[ch_slot[i]]; + dev->chan[i].slots[1] = &dev->slot[ch_slot[i] + 3]; + dev->slot[ch_slot[i]].chan = &dev->chan[i]; + dev->slot[ch_slot[i] + 3].chan = &dev->chan[i]; + + if ((i % 9) < 3) + dev->chan[i].pair = &dev->chan[i + 3]; + else if ((i % 9) < 6) + dev->chan[i].pair = &dev->chan[i - 3]; + + dev->chan[i].dev = dev; + dev->chan[i].out[0] = &dev->zeromod; + dev->chan[i].out[1] = &dev->zeromod; + dev->chan[i].out[2] = &dev->zeromod; + dev->chan[i].out[3] = &dev->zeromod; + dev->chan[i].chtype = ch_2op; + dev->chan[i].cha = 0xffff; + dev->chan[i].chb = 0xffff; + dev->chan[i].ch_num = i; + + channel_setup_alg(&dev->chan[i]); + } + + dev->noise = 1; + dev->rateratio = (samplerate << RSM_FRAC) / 49716; + dev->tremoloshift = 4; + dev->vibshift = 1; + + return(dev); +} + + +void +nuked_close(void *priv) +{ + nuked_t *dev = (nuked_t *)priv; + + free(dev); +} diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 8eccf1f6d..3dc2c1f0a 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -715,7 +715,7 @@ void pas16_get_buffer(int32_t *buffer, int len, void *p) pas16_t *pas16 = (pas16_t *)p; int c; - opl3_update2(&pas16->opl); + opl3_update(&pas16->opl); sb_dsp_update(&pas16->dsp); pas16_update(pas16); for (c = 0; c < len * 2; c++) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index e96e02c19..d382fc218 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -98,13 +98,16 @@ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) int c; if (sb->opl_enabled) - opl2_update2(&sb->opl); + opl2_update(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) { int32_t out = 0; if (sb->opl_enabled) out = ((sb->opl.buffer[c] * (sb->opl_emu ? 47000 : 51000)) >> 16); + //TODO: Recording: Mic and line In with AGC out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; @@ -113,7 +116,10 @@ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) } sb->pos = 0; - sb->opl.pos = 0; + + if (sb->opl_enabled) + sb->opl.pos = 0; + sb->dsp.pos = 0; } @@ -125,14 +131,17 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) int c; if (sb->opl_enabled) - opl2_update2(&sb->opl); + opl2_update(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) { int32_t out = 0; if (sb->opl_enabled) out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + /* TODO: Recording : I assume it has direct mic and line in like sb2 */ /* It is unclear from the docs if it has a filter, but it probably does */ out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice) / 3) >> 15; @@ -144,7 +153,10 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) } sb->pos = 0; - sb->opl.pos = 0; + + if (sb->opl_enabled) + sb->opl.pos = 0; + sb->dsp.pos = 0; } @@ -156,22 +168,34 @@ void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) int c; if (sb->opl_enabled) { - if (sb->dsp.sb_type == SBPRO) - opl2_update2(&sb->opl); - else - opl3_update2(&sb->opl); + if (sb->dsp.sb_type == SBPRO) { + opl2_update(&sb->opl); + opl2_update(&sb->opl2); + } else + opl3_update(&sb->opl); } sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) { int32_t out_l = 0, out_r = 0; if (sb->opl_enabled) { - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + if (sb->dsp.sb_type == SBPRO) { + /* + * Two chips for LEFT and RIGHT channels. + * Each chip stores data into the LEFT channel + * only (no sample alternating.) + */ + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl2.buffer[c] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + } else { + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + } } - + /*TODO: Implement the stereo switch on the mixer instead of on the dsp? */ if (mixer->output_filter) { @@ -193,7 +217,13 @@ void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) } sb->pos = 0; - sb->opl.pos = 0; + + if (sb->opl_enabled) { + sb->opl.pos = 0; + if (sb->dsp.sb_type != SBPRO) + sb->opl2.pos = 0; + } + sb->dsp.pos = 0; } @@ -201,13 +231,14 @@ static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - - int c; + int dsp_rec_pos = sb->dsp.record_pos_write; + int c; if (sb->opl_enabled) - opl3_update2(&sb->opl); + opl3_update(&sb->opl); + sb_dsp_update(&sb->dsp); - const int dsp_rec_pos = sb->dsp.record_pos_write; + for (c = 0; c < len * 2; c += 2) { int32_t out_l = 0, out_r = 0, in_l, in_r; @@ -266,7 +297,10 @@ static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) sb->dsp.record_pos_write&=0xFFFF; sb->pos = 0; - sb->opl.pos = 0; + + if (sb->opl_enabled) + sb->opl.pos = 0; + sb->dsp.pos = 0; } #ifdef SB_DSP_RECORD_DEBUG @@ -278,14 +312,16 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; - - int c; + int c; + int dsp_rec_pos = sb->dsp.record_pos_write; if (sb->opl_enabled) - opl3_update2(&sb->opl); + opl3_update(&sb->opl); + emu8k_update(&sb->emu8k); + sb_dsp_update(&sb->dsp); - const int dsp_rec_pos = sb->dsp.record_pos_write; + for (c = 0; c < len * 2; c += 2) { int32_t out_l = 0, out_r = 0, in_l, in_r; @@ -374,9 +410,14 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; sb->dsp.record_pos_write&=0xFFFF; + sb->pos = 0; - sb->opl.pos = 0; + + if (sb->opl_enabled) + sb->opl.pos = 0; + sb->dsp.pos = 0; + sb->emu8k.pos = 0; } @@ -1140,6 +1181,35 @@ void *sb_2_init(const device_t *info) return sb; } + +static uint8_t +sb_pro_v1_opl_read(uint16_t port, void *priv) +{ + sb_t *sb = (sb_t *)priv; + + (void)opl2_read(port, &sb->opl2); // read, but ignore + return(opl2_read(port, &sb->opl)); +} + + +static void +sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv) +{ + sb_t *sb = (sb_t *)priv; + + opl2_write(port, val, &sb->opl); + opl2_write(port, val, &sb->opl2); +} + + +/*sbpro port mappings. 220h or 240h. + 2x0 to 2x1 -> FM chip, Left (9*2 voices) + 2x1 to 2x3 -> FM chip, Right (9*2 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface. +*/ void *sb_pro_v1_init(const device_t *info) { /*sbpro port mappings. 220h or 240h. @@ -1153,8 +1223,10 @@ void *sb_pro_v1_init(const device_t *info) memset(sb, 0, sizeof(sb_t)); sb->opl_enabled = device_get_config_int("opl"); - if (sb->opl_enabled) + if (sb->opl_enabled) { opl2_init(&sb->opl); + opl2_init(&sb->opl2); + } sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); @@ -1162,10 +1234,14 @@ void *sb_pro_v1_init(const device_t *info) sb_ct1345_mixer_reset(sb); /* DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { - io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); - io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl); - io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); - io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 0, 2, + opl2_read,NULL,NULL, opl2_write,NULL,NULL, &sb->opl); + io_sethandler(addr + 2, 2, + opl2_read,NULL,NULL, opl2_write,NULL,NULL, &sb->opl2); + io_sethandler(addr + 8, 2, + sb_pro_v1_opl_read,NULL,NULL, sb_pro_v1_opl_write,NULL,NULL, sb); + io_sethandler(0x0388, 2, + sb_pro_v1_opl_read,NULL,NULL, sb_pro_v1_opl_write,NULL,NULL, sb); } io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 0dc3d2f6b..e7fc1387c 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -81,7 +81,7 @@ static void wss_get_buffer(int32_t *buffer, int len, void *p) wss_t *wss = (wss_t *)p; int c; - opl3_update2(&wss->opl); + opl3_update(&wss->opl); ad1848_update(&wss->ad1848); for (c = 0; c < len * 2; c++) { buffer[c] += wss->opl.buffer[c]; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 4c7f62087..318a2e82a 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -702,8 +702,7 @@ PRINTOBJ := png.o prt_cpmap.o \ SNDOBJ := sound.o \ openal.o \ - snd_opl.o snd_opl_backend.o \ - nukedopl.o \ + snd_opl.o snd_opl_nuked.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ filter.o pot.o sid.o voice.o wave6581__ST.o \