From 7bb722cdec073944ec681e3bc3f741dfadfa4fb7 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Sat, 2 Jul 2016 02:57:36 -0700 Subject: [PATCH] Updated VGMPlay. --- Frameworks/GME/GME.xcodeproj/project.pbxproj | 36 +- Frameworks/GME/gme/Vgm_Core.cpp | 463 +-- Frameworks/GME/gme/Vgm_Emu.cpp | 1161 +++---- Frameworks/GME/vgmplay/ChipMapper.c | 14 +- Frameworks/GME/vgmplay/ChipMapper.h | 1 + Frameworks/GME/vgmplay/VGMPlay.c | 62 +- Frameworks/GME/vgmplay/VGMPlay.h | 3 +- Frameworks/GME/vgmplay/VGMPlayUI.c | 11 +- Frameworks/GME/vgmplay/VGMPlay_AddFmts.c | 2 +- Frameworks/GME/vgmplay/VGMPlay_Intf.h | 1 + Frameworks/GME/vgmplay/chips/2151intf.c | 2 + Frameworks/GME/vgmplay/chips/2203intf.c | 2 +- Frameworks/GME/vgmplay/chips/2413intf.c | 5 + Frameworks/GME/vgmplay/chips/2608intf.c | 7 +- Frameworks/GME/vgmplay/chips/2610intf.c | 4 +- Frameworks/GME/vgmplay/chips/262intf.c | 8 +- Frameworks/GME/vgmplay/chips/3526intf.c | 6 +- Frameworks/GME/vgmplay/chips/3812intf.c | 14 +- Frameworks/GME/vgmplay/chips/8950intf.c | 16 +- Frameworks/GME/vgmplay/chips/Ootake_PSG.c | 4 +- Frameworks/GME/vgmplay/chips/Ootake_PSG.h | 2 +- Frameworks/GME/vgmplay/chips/ay8910.c | 8 +- Frameworks/GME/vgmplay/chips/ay_intf.c | 2 +- Frameworks/GME/vgmplay/chips/c140.c | 4 +- Frameworks/GME/vgmplay/chips/c352.c | 941 ++---- Frameworks/GME/vgmplay/chips/c6280.c | 4 +- Frameworks/GME/vgmplay/chips/c6280intf.c | 2 + Frameworks/GME/vgmplay/chips/dac_control.c | 34 +- Frameworks/GME/vgmplay/chips/emu2413.c | 4 +- Frameworks/GME/vgmplay/chips/emuconfig.h | 101 + Frameworks/GME/vgmplay/chips/es5503.c | 4 +- Frameworks/GME/vgmplay/chips/es5506.c | 18 +- Frameworks/GME/vgmplay/chips/fm.c | 152 +- Frameworks/GME/vgmplay/chips/fm2612.c | 4 +- Frameworks/GME/vgmplay/chips/fmopl.c | 8 +- Frameworks/GME/vgmplay/chips/gb.c | 2 +- Frameworks/GME/vgmplay/chips/iremga20.c | 4 +- Frameworks/GME/vgmplay/chips/k051649.c | 6 +- Frameworks/GME/vgmplay/chips/k053260.c | 14 +- Frameworks/GME/vgmplay/chips/k054539.c | 14 +- Frameworks/GME/vgmplay/chips/mamedef.h | 2 + Frameworks/GME/vgmplay/chips/multipcm.c | 4 +- Frameworks/GME/vgmplay/chips/nes_apu.c | 2 +- Frameworks/GME/vgmplay/chips/nes_intf.c | 2 +- Frameworks/GME/vgmplay/chips/np_nes_apu.c | 2 +- Frameworks/GME/vgmplay/chips/np_nes_dmc.c | 5 +- Frameworks/GME/vgmplay/chips/np_nes_fds.c | 2 +- Frameworks/GME/vgmplay/chips/okim6258.c | 8 +- Frameworks/GME/vgmplay/chips/okim6295.c | 4 +- Frameworks/GME/vgmplay/chips/opl.c | 4 +- Frameworks/GME/vgmplay/chips/opl.h | 11 + Frameworks/GME/vgmplay/chips/pokey.c | 8 + Frameworks/GME/vgmplay/chips/qsound.c | 8 +- Frameworks/GME/vgmplay/chips/rf5c68.c | 4 +- Frameworks/GME/vgmplay/chips/saa1099.c | 8 +- Frameworks/GME/vgmplay/chips/scsp.c | 1583 +-------- Frameworks/GME/vgmplay/chips/scspdsp.c | 356 -- Frameworks/GME/vgmplay/chips/scspdsp.h | 40 - Frameworks/GME/vgmplay/chips/scsplfo.c | 165 - Frameworks/GME/vgmplay/chips/segapcm.c | 2 +- Frameworks/GME/vgmplay/chips/sn76489.c | 2 +- Frameworks/GME/vgmplay/chips/sn76496.c | 10 +- Frameworks/GME/vgmplay/chips/sn764intf.c | 2 + Frameworks/GME/vgmplay/chips/upd7759.c | 34 +- Frameworks/GME/vgmplay/chips/vsu.c | 2 +- Frameworks/GME/vgmplay/chips/ws_audio.c | 2 +- Frameworks/GME/vgmplay/chips/x1_010.c | 21 +- Frameworks/GME/vgmplay/chips/yam.c | 3076 ++++++++++++++++++ Frameworks/GME/vgmplay/chips/yam.h | 54 + Frameworks/GME/vgmplay/chips/ym2151.c | 14 +- Frameworks/GME/vgmplay/chips/ym2413.c | 4 +- Frameworks/GME/vgmplay/chips/ymdeltat.c | 4 +- Frameworks/GME/vgmplay/chips/ymf262.c | 6 +- Frameworks/GME/vgmplay/chips/ymf271.c | 10 +- Frameworks/GME/vgmplay/chips/ymf278b.c | 24 +- Frameworks/GME/vgmplay/chips/ymz280b.c | 6 +- Frameworks/GME/vgmplay/resampler.c | 47 +- Frameworks/GME/vgmplay/vgm2pcm.c | 6 +- 78 files changed, 4855 insertions(+), 3839 deletions(-) create mode 100644 Frameworks/GME/vgmplay/chips/emuconfig.h delete mode 100644 Frameworks/GME/vgmplay/chips/scspdsp.c delete mode 100644 Frameworks/GME/vgmplay/chips/scspdsp.h delete mode 100644 Frameworks/GME/vgmplay/chips/scsplfo.c create mode 100644 Frameworks/GME/vgmplay/chips/yam.c create mode 100644 Frameworks/GME/vgmplay/chips/yam.h diff --git a/Frameworks/GME/GME.xcodeproj/project.pbxproj b/Frameworks/GME/GME.xcodeproj/project.pbxproj index b8d25b127..d30c2e4c3 100644 --- a/Frameworks/GME/GME.xcodeproj/project.pbxproj +++ b/Frameworks/GME/GME.xcodeproj/project.pbxproj @@ -90,6 +90,11 @@ 17C8F2560CBED286008D969D /* Ym2413_Emu.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C8F1ED0CBED286008D969D /* Ym2413_Emu.h */; }; 17C8F2570CBED286008D969D /* Ym2612_Emu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17C8F1EE0CBED286008D969D /* Ym2612_Emu.cpp */; }; 17C8F2580CBED286008D969D /* Ym2612_Emu.h in Headers */ = {isa = PBXBuildFile; fileRef = 17C8F1EF0CBED286008D969D /* Ym2612_Emu.h */; }; + 8342DC841D27A171007FB1C1 /* yam.h in Headers */ = {isa = PBXBuildFile; fileRef = 8342DC811D27A171007FB1C1 /* yam.h */; }; + 8342DC851D27A171007FB1C1 /* scsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 8342DC821D27A171007FB1C1 /* scsp.c */; }; + 8342DC861D27A171007FB1C1 /* scsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 8342DC831D27A171007FB1C1 /* scsp.h */; }; + 8342DCCB1D27C0E9007FB1C1 /* yam.c in Sources */ = {isa = PBXBuildFile; fileRef = 8342DCC91D27C0E9007FB1C1 /* yam.c */; }; + 8342DCCC1D27C0E9007FB1C1 /* emuconfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 8342DCCA1D27C0E9007FB1C1 /* emuconfig.h */; }; 8370B73017F615FE001A4D7A /* Ay_Core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8370B68D17F615FD001A4D7A /* Ay_Core.cpp */; }; 8370B73117F615FE001A4D7A /* Ay_Core.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B68E17F615FD001A4D7A /* Ay_Core.h */; }; 8370B73217F615FE001A4D7A /* blargg_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8370B68F17F615FD001A4D7A /* blargg_common.cpp */; }; @@ -254,10 +259,6 @@ 83BB5EA31C0842A600734457 /* saa1099.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BB5E0F1C0842A600734457 /* saa1099.h */; }; 83BB5EA41C0842A600734457 /* scd_pcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB5E101C0842A600734457 /* scd_pcm.c */; }; 83BB5EA51C0842A600734457 /* scd_pcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BB5E111C0842A600734457 /* scd_pcm.h */; }; - 83BB5EA61C0842A600734457 /* scsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB5E121C0842A600734457 /* scsp.c */; }; - 83BB5EA71C0842A600734457 /* scsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BB5E131C0842A600734457 /* scsp.h */; }; - 83BB5EA81C0842A600734457 /* scspdsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB5E141C0842A600734457 /* scspdsp.c */; }; - 83BB5EA91C0842A600734457 /* scspdsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BB5E151C0842A600734457 /* scspdsp.h */; }; 83BB5EAB1C0842A600734457 /* segapcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB5E171C0842A600734457 /* segapcm.c */; }; 83BB5EAC1C0842A600734457 /* segapcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BB5E181C0842A600734457 /* segapcm.h */; }; 83BB5EAD1C0842A600734457 /* sn76489.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BB5E191C0842A600734457 /* sn76489.c */; }; @@ -402,6 +403,11 @@ 17C8F1EE0CBED286008D969D /* Ym2612_Emu.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Ym2612_Emu.cpp; path = gme/Ym2612_Emu.cpp; sourceTree = ""; }; 17C8F1EF0CBED286008D969D /* Ym2612_Emu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Ym2612_Emu.h; path = gme/Ym2612_Emu.h; sourceTree = ""; }; 833F68361CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; + 8342DC811D27A171007FB1C1 /* yam.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = yam.h; sourceTree = ""; }; + 8342DC821D27A171007FB1C1 /* scsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scsp.c; sourceTree = ""; }; + 8342DC831D27A171007FB1C1 /* scsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scsp.h; sourceTree = ""; }; + 8342DCC91D27C0E9007FB1C1 /* yam.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yam.c; sourceTree = ""; }; + 8342DCCA1D27C0E9007FB1C1 /* emuconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emuconfig.h; sourceTree = ""; }; 8370B68D17F615FD001A4D7A /* Ay_Core.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Ay_Core.cpp; path = gme/Ay_Core.cpp; sourceTree = ""; }; 8370B68E17F615FD001A4D7A /* Ay_Core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Ay_Core.h; path = gme/Ay_Core.h; sourceTree = ""; }; 8370B68F17F615FD001A4D7A /* blargg_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = blargg_common.cpp; path = gme/blargg_common.cpp; sourceTree = ""; }; @@ -566,10 +572,6 @@ 83BB5E0F1C0842A600734457 /* saa1099.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = saa1099.h; sourceTree = ""; }; 83BB5E101C0842A600734457 /* scd_pcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scd_pcm.c; sourceTree = ""; }; 83BB5E111C0842A600734457 /* scd_pcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scd_pcm.h; sourceTree = ""; }; - 83BB5E121C0842A600734457 /* scsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scsp.c; sourceTree = ""; }; - 83BB5E131C0842A600734457 /* scsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scsp.h; sourceTree = ""; }; - 83BB5E141C0842A600734457 /* scspdsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scspdsp.c; sourceTree = ""; }; - 83BB5E151C0842A600734457 /* scspdsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scspdsp.h; sourceTree = ""; }; 83BB5E171C0842A600734457 /* segapcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = segapcm.c; sourceTree = ""; }; 83BB5E181C0842A600734457 /* segapcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = segapcm.h; sourceTree = ""; }; 83BB5E191C0842A600734457 /* sn76489.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sn76489.c; sourceTree = ""; }; @@ -882,6 +884,11 @@ 83BB5DAC1C0842A600734457 /* chips */ = { isa = PBXGroup; children = ( + 8342DCC91D27C0E9007FB1C1 /* yam.c */, + 8342DCCA1D27C0E9007FB1C1 /* emuconfig.h */, + 8342DC811D27A171007FB1C1 /* yam.h */, + 8342DC821D27A171007FB1C1 /* scsp.c */, + 8342DC831D27A171007FB1C1 /* scsp.h */, 83BB5DAD1C0842A600734457 /* 2151intf.c */, 83BB5DAE1C0842A600734457 /* 2151intf.h */, 83BB5DAF1C0842A600734457 /* 2203intf.c */, @@ -981,10 +988,6 @@ 83BB5E0F1C0842A600734457 /* saa1099.h */, 83BB5E101C0842A600734457 /* scd_pcm.c */, 83BB5E111C0842A600734457 /* scd_pcm.h */, - 83BB5E121C0842A600734457 /* scsp.c */, - 83BB5E131C0842A600734457 /* scsp.h */, - 83BB5E141C0842A600734457 /* scspdsp.c */, - 83BB5E151C0842A600734457 /* scspdsp.h */, 83BB5E171C0842A600734457 /* segapcm.c */, 83BB5E181C0842A600734457 /* segapcm.h */, 83BB5E191C0842A600734457 /* sn76489.c */, @@ -1087,6 +1090,7 @@ files = ( 83BB5ECF1C0842A600734457 /* ChipMapper.h in Headers */, 83BB5E861C0842A600734457 /* nes_apu.h in Headers */, + 8342DC861D27A171007FB1C1 /* scsp.h in Headers */, 8370B76C17F615FE001A4D7A /* Nes_Cpu_run.h in Headers */, 83BB5EBC1C0842A600734457 /* x1_010.h in Headers */, 8370B7B017F615FE001A4D7A /* Spc_Sfm.h in Headers */, @@ -1108,7 +1112,6 @@ 83BB5E631C0842A600734457 /* c6280.h in Headers */, 83BB5ED21C0842A600734457 /* VGMPlay.h in Headers */, 83BB5E8D1C0842A600734457 /* np_nes_dmc.h in Headers */, - 83BB5EA91C0842A600734457 /* scspdsp.h in Headers */, 17C8F1FC0CBED286008D969D /* blargg_endian.h in Headers */, 83FC5D5F181B47FB00B917E5 /* dsp.hpp in Headers */, 17C8F1FD0CBED286008D969D /* blargg_source.h in Headers */, @@ -1119,7 +1122,6 @@ 83FC5D79181B47FB00B917E5 /* smp.hpp in Headers */, 8370B73617F615FE001A4D7A /* Blip_Buffer_impl2.h in Headers */, 83BB5E6A1C0842A600734457 /* emu2149.h in Headers */, - 83BB5EA71C0842A600734457 /* scsp.h in Headers */, 8370B78117F615FE001A4D7A /* Opl_Apu.h in Headers */, 83BB5EC61C0842A600734457 /* ymf262.h in Headers */, 83BB5E721C0842A600734457 /* es5506.h in Headers */, @@ -1140,6 +1142,7 @@ 83BB5E821C0842A600734457 /* mamedef.h in Headers */, 83BB5E501C0842A600734457 /* 281btone.h in Headers */, 83BB5EB91C0842A600734457 /* ws_audio.h in Headers */, + 8342DCCC1D27C0E9007FB1C1 /* emuconfig.h in Headers */, 83BB5E611C0842A600734457 /* c352.h in Headers */, 83BB5E6E1C0842A600734457 /* emutypes.h in Headers */, 8370B79317F615FE001A4D7A /* Rom_Data.h in Headers */, @@ -1225,6 +1228,7 @@ 83BB5E561C0842A600734457 /* 8950intf.h in Headers */, 17C8F2470CBED286008D969D /* Sms_Apu.h in Headers */, 83BB5E931C0842A600734457 /* okim6295.h in Headers */, + 8342DC841D27A171007FB1C1 /* yam.h in Headers */, 8370B7AE17F615FE001A4D7A /* Spc_Filter.h in Headers */, 8370B7AA17F615FE001A4D7A /* Sgc_Impl.h in Headers */, 8370B79D17F615FE001A4D7A /* Sap_Core.h in Headers */, @@ -1355,6 +1359,7 @@ 8370B7A917F615FE001A4D7A /* Sgc_Impl.cpp in Sources */, 17C8F20F0CBED286008D969D /* Gb_Oscs.cpp in Sources */, 8370B74317F615FE001A4D7A /* Downsampler.cpp in Sources */, + 8342DCCB1D27C0E9007FB1C1 /* yam.c in Sources */, 17C8F2110CBED286008D969D /* Gbs_Emu.cpp in Sources */, 83BB5E831C0842A600734457 /* multipcm.c in Sources */, 8370B73317F615FE001A4D7A /* blargg_errors.cpp in Sources */, @@ -1386,7 +1391,6 @@ 83BB5E731C0842A600734457 /* fm.c in Sources */, 17C8F2330CBED286008D969D /* Nes_Fme7_Apu.cpp in Sources */, 8370B7B517F615FE001A4D7A /* Vgm_Core.cpp in Sources */, - 83BB5EA61C0842A600734457 /* scsp.c in Sources */, 17C8F2350CBED286008D969D /* Nes_Namco_Apu.cpp in Sources */, 8370B7A617F615FE001A4D7A /* Sgc_Cpu.cpp in Sources */, 83BB5E431C0842A600734457 /* 2203intf.c in Sources */, @@ -1418,11 +1422,11 @@ 83BB5EB11C0842A600734457 /* sn764intf.c in Sources */, 8370B76817F615FE001A4D7A /* Kss_Core.cpp in Sources */, 17C8F23D0CBED286008D969D /* Nsfe_Emu.cpp in Sources */, + 8342DC851D27A171007FB1C1 /* scsp.c in Sources */, 8370B7A717F615FE001A4D7A /* Sgc_Emu.cpp in Sources */, 83BB5E881C0842A600734457 /* nes_intf.c in Sources */, 17C8F23F0CBED286008D969D /* Sap_Apu.cpp in Sources */, 8370B75117F615FE001A4D7A /* Gme_Loader.cpp in Sources */, - 83BB5EA81C0842A600734457 /* scspdsp.c in Sources */, 83BB5E781C0842A600734457 /* gb.c in Sources */, 17C8F2420CBED286008D969D /* Sap_Cpu.cpp in Sources */, 8370B73717F615FE001A4D7A /* Bml_Parser.cpp in Sources */, diff --git a/Frameworks/GME/gme/Vgm_Core.cpp b/Frameworks/GME/gme/Vgm_Core.cpp index 9972caeb3..67f81b918 100644 --- a/Frameworks/GME/gme/Vgm_Core.cpp +++ b/Frameworks/GME/gme/Vgm_Core.cpp @@ -1,226 +1,237 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Vgm_Core.h" - -#include "blargg_endian.h" -#include -#include - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -Vgm_Core::Vgm_Core() -{ - vgmp = (VGM_PLAYER *) VGMPlay_Init(); - vgmp->VGMMaxLoop = 0; - VGMPlay_Init2(vgmp); -} - -Vgm_Core::~Vgm_Core() -{ - StopVGM(vgmp); - CloseVGMFile(vgmp); - VGMPlay_Deinit(vgmp); -} - -static UINT32 gcd(UINT32 x, UINT32 y) -{ - UINT32 shift; - UINT32 diff; - - // Thanks to Wikipedia for this algorithm - // http://en.wikipedia.org/wiki/Binary_GCD_algorithm - if (! x || ! y) - return x | y; - - for (shift = 0; ((x | y) & 1) == 0; shift ++) - { - x >>= 1; - y >>= 1; - } - - while((x & 1) == 0) - x >>= 1; - - do - { - while((y & 1) == 0) - y >>= 1; - - if (x < y) - { - y -= x; - } - else - { - diff = x - y; - x = y; - y = diff; - } - y >>= 1; - } while(y); - - return x << shift; -} - -void Vgm_Core::set_tempo( double t ) -{ - if ( file_begin() ) - { - int vgm_rate_unit = header().lngRate; - if (!vgm_rate_unit) - vgm_rate_unit = 44100; - int vgm_rate = (int) (vgm_rate_unit * t + 0.5); - int old_rate = vgmp->VGMPbRate; - vgmp->VGMPbRate = vgm_rate; - vgmp->SampleRate = sample_rate; - - if (vgmp->PlayingMode != 0xFF) - { - if (!old_rate) - old_rate = vgm_rate_unit; - - INT32 TempSLng = gcd(vgm_rate_unit, vgmp->VGMPbRate); - vgmp->VGMPbRateMul = vgm_rate_unit / TempSLng; - vgmp->VGMPbRateDiv = vgmp->VGMPbRate / TempSLng; - - vgmp->VGMSmplRateMul = vgmp->SampleRate * vgmp->VGMPbRateMul; - vgmp->VGMSmplRateDiv = vgmp->VGMSampleRate * vgmp->VGMPbRateDiv; - // same as above - to speed up the VGM <-> Playback calculation - TempSLng = gcd(vgmp->VGMSmplRateMul, vgmp->VGMSmplRateDiv); - vgmp->VGMSmplRateMul /= TempSLng; - vgmp->VGMSmplRateDiv /= TempSLng; - - vgmp->VGMSmplPlayed = (INT32)((INT64)vgmp->VGMSmplPlayed * old_rate / vgm_rate); - } - } -} - -struct VGM_FILE_mem -{ - VGM_FILE vf; - const BOOST::uint8_t* buffer; - UINT32 ptr; - UINT32 size; -}; - -static int VGMF_mem_Read(VGM_FILE* f, void* out, UINT32 count) -{ - VGM_FILE_mem* mf = (VGM_FILE_mem *) f; - if (count + mf->ptr > mf->size) - count = mf->size - mf->ptr; - memcpy(out, mf->buffer + mf->ptr, count); - mf->ptr += count; - return count; -} - -static int VGMF_mem_Seek(VGM_FILE* f, UINT32 offset) -{ - VGM_FILE_mem* mf = (VGM_FILE_mem *) f; - if (offset > mf->size) - offset = mf->size; - mf->ptr = offset; - return 0; -} - -static UINT32 VGMF_mem_GetSize(VGM_FILE* f) -{ - VGM_FILE_mem* mf = (VGM_FILE_mem *) f; - return mf->size; -} - -blargg_err_t Vgm_Core::load_mem_( byte const data [], int size ) -{ - VGM_FILE_mem memFile; - - memFile.vf.Read = &VGMF_mem_Read; - memFile.vf.Seek = &VGMF_mem_Seek; - memFile.vf.GetSize = &VGMF_mem_GetSize; - memFile.buffer = data; - memFile.ptr = 0; - memFile.size = size; - - if ( !GetVGMFileInfo_Handle( (VGM_FILE *) &memFile, &_header, 0 ) ) - return blargg_err_file_type; - - memFile.ptr = 0; - - if ( !OpenVGMFile_Handle( vgmp, (VGM_FILE *) &memFile ) ) - return blargg_err_file_type; - - if ( !header().lngLoopOffset ) - vgmp->VGMMaxLoop = 1; - - set_tempo( 1 ); - - return blargg_ok; -} - -int Vgm_Core::get_channel_count() -{ - // XXX may support more than this, but 32 bit masks and all... - unsigned i; - UINT32 j; - for (i = 0; i < 32; i++) - { - if (!GetAccurateChipNameByChannel(vgmp, i, &j)) - break; - } - return i; -} - -char* Vgm_Core::get_voice_name(int channel) -{ - UINT32 realChannel; - const char * name = GetAccurateChipNameByChannel(vgmp, channel, &realChannel); - size_t length = strlen(name) + 16; - char * finalName = (char *) malloc(length); - if (finalName) - sprintf(finalName, "%s #%u", name, realChannel); - return finalName; -} - -void Vgm_Core::free_voice_name(char *name) -{ - free(name); -} - -void Vgm_Core::set_mute(int mask) -{ - for (int i = 0; i < 32; i++) - { - SetChannelMute(vgmp, i, (mask >> i) & 1); - } -} - -void Vgm_Core::start_track() -{ - PlayVGM(vgmp); - RestartVGM(vgmp); -} - -int Vgm_Core::play_( int sample_count, short out [] ) -{ - // to do: timing is working mostly by luck - int pairs = (unsigned) sample_count / 2; - - memset(out, 0, sizeof(short) * pairs * 2); - FillBuffer(vgmp, (WAVE_16BS*) out, pairs); - - return pairs * 2; -} - -void Vgm_Core::skip_( int count ) -{ - SeekVGM( vgmp, true, count / 2 ); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Vgm_Core.h" + +#include "blargg_endian.h" +#include +#include + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +Vgm_Core::Vgm_Core() +{ + vgmp = (VGM_PLAYER *) VGMPlay_Init(); + vgmp->VGMMaxLoop = 0; + VGMPlay_Init2(vgmp); +} + +Vgm_Core::~Vgm_Core() +{ + StopVGM(vgmp); + CloseVGMFile(vgmp); + VGMPlay_Deinit(vgmp); +} + +static UINT32 gcd(UINT32 x, UINT32 y) +{ + UINT32 shift; + UINT32 diff; + + // Thanks to Wikipedia for this algorithm + // http://en.wikipedia.org/wiki/Binary_GCD_algorithm + if (! x || ! y) + return x | y; + + for (shift = 0; ((x | y) & 1) == 0; shift ++) + { + x >>= 1; + y >>= 1; + } + + while((x & 1) == 0) + x >>= 1; + + do + { + while((y & 1) == 0) + y >>= 1; + + if (x < y) + { + y -= x; + } + else + { + diff = x - y; + x = y; + y = diff; + } + y >>= 1; + } while(y); + + return x << shift; +} + +void Vgm_Core::set_tempo( double t ) +{ + if ( file_begin() ) + { + int vgm_rate_unit = header().lngRate; + if (!vgm_rate_unit) + vgm_rate_unit = 44100; + int vgm_rate = (int) (vgm_rate_unit * t + 0.5); + int old_rate = vgmp->VGMPbRate; + vgmp->VGMPbRate = vgm_rate; + vgmp->SampleRate = sample_rate; + + if (vgmp->PlayingMode != 0xFF) + { + if (!old_rate) + old_rate = vgm_rate_unit; + + INT32 TempSLng = gcd(vgm_rate_unit, vgmp->VGMPbRate); + vgmp->VGMPbRateMul = vgm_rate_unit / TempSLng; + vgmp->VGMPbRateDiv = vgmp->VGMPbRate / TempSLng; + + vgmp->VGMSmplRateMul = vgmp->SampleRate * vgmp->VGMPbRateMul; + vgmp->VGMSmplRateDiv = vgmp->VGMSampleRate * vgmp->VGMPbRateDiv; + // same as above - to speed up the VGM <-> Playback calculation + TempSLng = gcd(vgmp->VGMSmplRateMul, vgmp->VGMSmplRateDiv); + vgmp->VGMSmplRateMul /= TempSLng; + vgmp->VGMSmplRateDiv /= TempSLng; + + vgmp->VGMSmplPlayed = (INT32)((INT64)vgmp->VGMSmplPlayed * old_rate / vgm_rate); + } + } +} + +struct VGM_FILE_mem +{ + VGM_FILE vf; + const BOOST::uint8_t* buffer; + UINT32 ptr; + UINT32 size; +}; + +static int VGMF_mem_Read(VGM_FILE* f, void* out, UINT32 count) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + if (count + mf->ptr > mf->size) + count = mf->size - mf->ptr; + memcpy(out, mf->buffer + mf->ptr, count); + mf->ptr += count; + return count; +} + +static int VGMF_mem_Seek(VGM_FILE* f, UINT32 offset) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + if (offset > mf->size) + offset = mf->size; + mf->ptr = offset; + return 0; +} + +static UINT32 VGMF_mem_GetSize(VGM_FILE* f) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + return mf->size; +} + +static UINT32 VGMF_mem_Tell(VGM_FILE* f) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + return mf->ptr; +} + +blargg_err_t Vgm_Core::load_mem_( byte const data [], int size ) +{ + VGM_FILE_mem memFile; + + memFile.vf.Read = &VGMF_mem_Read; + memFile.vf.Seek = &VGMF_mem_Seek; + memFile.vf.GetSize = &VGMF_mem_GetSize; + memFile.vf.Tell = &VGMF_mem_Tell; + memFile.buffer = data; + memFile.ptr = 0; + memFile.size = size; + + if ( !GetVGMFileInfo_Handle( (VGM_FILE *) &memFile, &_header, 0 ) ) + return blargg_err_file_type; + + memFile.ptr = 0; + + if ( !OpenVGMFile_Handle( vgmp, (VGM_FILE *) &memFile ) ) + return blargg_err_file_type; + + if ( !header().lngLoopOffset ) + vgmp->VGMMaxLoop = 1; + + set_tempo( 1 ); + + return blargg_ok; +} + +int Vgm_Core::get_channel_count() +{ + // XXX may support more than this, but 32 bit masks and all... + unsigned i; + UINT32 j; + for (i = 0; i < 32; i++) + { + if (!GetAccurateChipNameByChannel(vgmp, i, &j)) + break; + } + return i; +} + +char* Vgm_Core::get_voice_name(int channel) +{ + UINT32 realChannel; + const char * name = GetAccurateChipNameByChannel(vgmp, channel, &realChannel); + size_t length = strlen(name) + 16; + char * finalName = (char *) malloc(length); + if (finalName) +#ifdef _MSC_VER + sprintf_s(finalName, length, "%s #%u", name, realChannel); +#else + sprintf(finalName, "%s #%u", name, realChannel); +#endif + return finalName; +} + +void Vgm_Core::free_voice_name(char *name) +{ + free(name); +} + +void Vgm_Core::set_mute(int mask) +{ + for (int i = 0; i < 32; i++) + { + SetChannelMute(vgmp, i, (mask >> i) & 1); + } +} + +void Vgm_Core::start_track() +{ + PlayVGM(vgmp); + RestartVGM(vgmp); +} + +int Vgm_Core::play_( int sample_count, short out [] ) +{ + // to do: timing is working mostly by luck + int pairs = (unsigned) sample_count / 2; + + memset(out, 0, sizeof(short) * pairs * 2); + FillBuffer(vgmp, (WAVE_16BS*) out, pairs); + + return pairs * 2; +} + +void Vgm_Core::skip_( int count ) +{ + SeekVGM( vgmp, true, count / 2 ); +} diff --git a/Frameworks/GME/gme/Vgm_Emu.cpp b/Frameworks/GME/gme/Vgm_Emu.cpp index ec34a5a98..e8350fb78 100644 --- a/Frameworks/GME/gme/Vgm_Emu.cpp +++ b/Frameworks/GME/gme/Vgm_Emu.cpp @@ -1,577 +1,584 @@ -// Game_Music_Emu $vers. http://www.slack.net/~ant/ - -#include "Vgm_Emu.h" - -#include "blargg_endian.h" -#include "blargg_common.h" - -/* Copyright (C) 2003-2008 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -// FM emulators are internally quieter to avoid 16-bit overflow -double const fm_gain = 3.0; -double const rolloff = 0.990; -double const oversample_factor = 1.5; - -Vgm_Emu::Vgm_Emu() -{ - muted_voices = 0; - set_type( gme_vgm_type ); - set_max_initial_silence( 1 ); - set_silence_lookahead( 1 ); // tracks should already be trimmed -} - -Vgm_Emu::~Vgm_Emu() -{ - // XXX ugly use of deprecated functions to free allocated voice names - const char ** voice_names_ = voice_names(); - if (voice_names_) - { - for (int i = 0; i < 32; ++i) - { - if (voice_names_[i]) - core.free_voice_name((char*)voice_names_[i]); - else break; - } - free((void *)voice_names_); - } -} - -void Vgm_Emu::unload() -{ - core.unload(); -} - -// Track info - -static byte const* skip_gd3_str( byte const in [], byte const* end ) -{ - while ( end - in >= 2 ) - { - in += 2; - if ( !(in [-2] | in [-1]) ) - break; - } - return in; -} - -static byte const* get_gd3_str( byte const* in, byte const* end, char field [] ) -{ - byte const* mid = skip_gd3_str( in, end ); - int len = (int)((mid - in) / 2) - 1; - if ( len > 0 ) - { - char * in_utf8 = blargg_to_utf8( (blargg_wchar_t *) in ); - len = min( len, (int) Gme_File::max_field_ ); - field [len] = 0; - for ( int i = 0; i < len; i++ ) - field [i] = in_utf8 [i]; - free(in_utf8); - } - return mid; -} - -static byte const* get_gd3_pair( byte const* in, byte const* end, char field [], char field_j [] ) -{ - return get_gd3_str( get_gd3_str( in, end, field ), end, field_j ); -} - -static void parse_gd3( byte const in [], byte const* end, track_info_t* out, track_info_t* out_j ) -{ - in = get_gd3_pair( in, end, out->song , out_j->song ); - in = get_gd3_pair( in, end, out->game , out_j->game ); - in = get_gd3_pair( in, end, out->system , out_j->system ); - in = get_gd3_pair( in, end, out->author , out_j->author ); - in = get_gd3_str ( in, end, out->copyright ); - in = get_gd3_pair( in, end, out->dumper , out_j->dumper ); - in = get_gd3_str ( in, end, out->comment ); -} - -static blargg_err_t write_gd3_str( gme_writer_t writer, void* your_data, const char field [] ) -{ - blargg_wchar_t * wstring = blargg_to_wide( field ); - if (!wstring) - return "Out of memory"; - blargg_err_t err = writer( your_data, wstring, blargg_wcslen( wstring ) * 2 + 2 ); - free( wstring ); - return err; -} - -static blargg_err_t write_gd3_pair( gme_writer_t writer, void* your_data, const char field [], const char field_j [] ) -{ - RETURN_ERR(write_gd3_str( writer, your_data, field )); - RETURN_ERR(write_gd3_str( writer, your_data, field )); - return blargg_ok; -} - -static blargg_err_t write_gd3_strings( gme_writer_t writer, void* your_data, const track_info_t* in, const track_info_t* in_j ) -{ - RETURN_ERR(write_gd3_pair( writer, your_data, in->song , in_j->song )); - RETURN_ERR(write_gd3_pair( writer, your_data, in->game , in_j->game )); - RETURN_ERR(write_gd3_pair( writer, your_data, in->system , in_j->system )); - RETURN_ERR(write_gd3_pair( writer, your_data, in->author , in_j->author )); - RETURN_ERR(write_gd3_str ( writer, your_data, in->copyright )); - RETURN_ERR(write_gd3_pair( writer, your_data, in->dumper , in_j->dumper )); - RETURN_ERR(write_gd3_str ( writer, your_data, in->comment )); - return blargg_ok; -} - -static gme_err_t writer_calc_size(void* param, const void* ptr, long count) -{ - *(long *)param += count; - return blargg_ok; -} - -static blargg_err_t write_gd3( gme_writer_t writer, void* your_data, const track_info_t* in, const track_info_t* in_j ) -{ - long string_size = 0; - byte version[4]; - RETURN_ERR(writer( your_data, "Gd3 ", 4 )); - set_le32(version, 0x100); - RETURN_ERR(writer( your_data, version, 4 )); - write_gd3_strings( &writer_calc_size, &string_size, in, in_j ); - if ( string_size > 1000000000 ) - return "GD3 tag too large"; - set_le32(version, (int)string_size); - RETURN_ERR(writer( your_data, version, 4)); - return write_gd3_strings( writer, your_data, in, in_j ); -} - -int const gd3_header_size = 12; - -static int check_gd3_header( byte const h [], int remain ) -{ - if ( remain < gd3_header_size ) return 0; - if ( memcmp( h, "Gd3 ", 4 ) ) return 0; - if ( get_le32( h + 4 ) >= 0x200 ) return 0; - - int gd3_size = get_le32( h + 8 ); - if ( gd3_size > remain - gd3_header_size ) return 0; - - return gd3_size; -} - -static void get_vgm_length( Vgm_Emu::header_t const& h, track_info_t* out ) -{ - int length = h.lngTotalSamples * 10 / 441; // 1000 / 44100 - if ( length > 0 ) - { - int loop = h.lngLoopSamples; - if ( loop > 0 && h.lngLoopOffset ) - { - out->length = 0; - out->loop_length = loop * 10 / 441; - out->intro_length = length - out->loop_length; - check( out->loop_length <= length ); - // TODO: Also set out->length? We now have play_length for suggested play time. - } - else - { - out->length = length; - out->intro_length = length; - out->loop_length = 0; - } - } -} - -blargg_err_t Vgm_Emu::track_info_( track_info_t* out, int ) const -{ - *out = metadata; - - return blargg_ok; -} - -blargg_err_t Vgm_Emu::gd3_data( const unsigned char ** data, int * size ) -{ - *data = 0; - *size = 0; - - int gd3_offset = header().lngGD3Offset; - if ( gd3_offset <= 0 ) - return blargg_ok; - - byte const* gd3 = core.file_begin() + gd3_offset; - int gd3_size = check_gd3_header( gd3, (int)(core.file_end() - gd3) ); - if ( gd3_size ) - { - *data = gd3; - *size = gd3_size + gd3_header_size; - } - - return blargg_ok; -} - -static void hash_vgm_file( Vgm_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) -{ - out.hash_( (const byte *) &h.lngEOFOffset, sizeof(h.lngEOFOffset) ); - out.hash_( (const byte *) &h.lngVersion, sizeof(h.lngVersion) ); - out.hash_( (const byte *) &h.lngHzPSG, sizeof(h.lngHzPSG) ); - out.hash_( (const byte *) &h.lngHzYM2413, sizeof(h.lngHzYM2413) ); - out.hash_( (const byte *) &h.lngTotalSamples, sizeof(h.lngTotalSamples) ); - out.hash_( (const byte *) &h.lngLoopOffset, sizeof(h.lngLoopOffset) ); - out.hash_( (const byte *) &h.lngLoopSamples, sizeof(h.lngLoopSamples) ); - out.hash_( (const byte *) &h.lngRate, sizeof(h.lngRate) ); - out.hash_( (const byte *) &h.shtPSG_Feedback, sizeof(h.shtPSG_Feedback) ); - out.hash_( (const byte *) &h.bytPSG_SRWidth, sizeof(h.bytPSG_SRWidth) ); - out.hash_( (const byte *) &h.bytPSG_Flags, sizeof(h.bytPSG_Flags) ); - out.hash_( (const byte *) &h.lngHzYM2612, sizeof(h.lngHzYM2612) ); - out.hash_( (const byte *) &h.lngHzYM2151, sizeof(h.lngHzYM2151) ); - out.hash_( (const byte *) &h.lngDataOffset, sizeof(h.lngDataOffset) ); - out.hash_( (const byte *) &h.lngHzSPCM, sizeof(h.lngHzSPCM) ); - out.hash_( (const byte *) &h.lngSPCMIntf, sizeof(h.lngSPCMIntf) ); - out.hash_( (const byte *) &h.lngHzRF5C68, sizeof(h.lngHzRF5C68) ); - out.hash_( (const byte *) &h.lngHzYM2203, sizeof(h.lngHzYM2203) ); - out.hash_( (const byte *) &h.lngHzYM2608, sizeof(h.lngHzYM2608) ); - out.hash_( (const byte *) &h.lngHzYM2610, sizeof(h.lngHzYM2610) ); - out.hash_( (const byte *) &h.lngHzYM3812, sizeof(h.lngHzYM3812) ); - out.hash_( (const byte *) &h.lngHzYM3526, sizeof(h.lngHzYM3526) ); - out.hash_( (const byte *) &h.lngHzY8950, sizeof(h.lngHzY8950) ); - out.hash_( (const byte *) &h.lngHzYMF262, sizeof(h.lngHzYMF262) ); - out.hash_( (const byte *) &h.lngHzYMF278B, sizeof(h.lngHzYMF278B) ); - out.hash_( (const byte *) &h.lngHzYMF271, sizeof(h.lngHzYMF271) ); - out.hash_( (const byte *) &h.lngHzYMZ280B, sizeof(h.lngHzYMZ280B) ); - out.hash_( (const byte *) &h.lngHzRF5C164, sizeof(h.lngHzRF5C164) ); - out.hash_( (const byte *) &h.lngHzPWM, sizeof(h.lngHzPWM) ); - out.hash_( (const byte *) &h.lngHzAY8910, sizeof(h.lngHzAY8910) ); - out.hash_( (const byte *) &h.bytAYType, sizeof(h.bytAYType) ); - out.hash_( (const byte *) &h.bytAYFlag, sizeof(h.bytAYFlag) ); - out.hash_( (const byte *) &h.bytAYFlagYM2203, sizeof(h.bytAYFlagYM2203) ); - out.hash_( (const byte *) &h.bytAYFlagYM2608, sizeof(h.bytAYFlagYM2608) ); - out.hash_( (const byte *) &h.bytReserved2, sizeof(h.bytReserved2) ); - out.hash_( (const byte *) &h.lngHzGBDMG, sizeof(h.lngHzGBDMG) ); - out.hash_( (const byte *) &h.lngHzNESAPU, sizeof(h.lngHzNESAPU) ); - out.hash_( (const byte *) &h.lngHzMultiPCM, sizeof(h.lngHzMultiPCM) ); - out.hash_( (const byte *) &h.lngHzUPD7759, sizeof(h.lngHzUPD7759) ); - out.hash_( (const byte *) &h.lngHzOKIM6258, sizeof(h.lngHzOKIM6258) ); - out.hash_( (const byte *) &h.bytOKI6258Flags, sizeof(h.bytOKI6258Flags) ); - out.hash_( (const byte *) &h.bytK054539Flags, sizeof(h.bytK054539Flags) ); - out.hash_( (const byte *) &h.bytC140Type, sizeof(h.bytC140Type) ); - out.hash_( (const byte *) &h.bytReservedFlags, sizeof(h.bytReservedFlags) ); - out.hash_( (const byte *) &h.lngHzOKIM6295, sizeof(h.lngHzOKIM6295) ); - out.hash_( (const byte *) &h.lngHzK051649, sizeof(h.lngHzK051649) ); - out.hash_( (const byte *) &h.lngHzK054539, sizeof(h.lngHzK054539) ); - out.hash_( (const byte *) &h.lngHzHuC6280, sizeof(h.lngHzHuC6280) ); - out.hash_( (const byte *) &h.lngHzC140, sizeof(h.lngHzC140) ); - out.hash_( (const byte *) &h.lngHzK053260, sizeof(h.lngHzK053260) ); - out.hash_( (const byte *) &h.lngHzPokey, sizeof(h.lngHzPokey) ); - out.hash_( (const byte *) &h.lngHzQSound, sizeof(h.lngHzQSound) ); - out.hash_( (const byte *) &h.lngHzSCSP, sizeof(h.lngHzSCSP) ); - // out.hash_( (const byte *) &h.lngExtraOffset, sizeof(h.lngExtraOffset) ); - out.hash_( (const byte *) &h.lngHzWSwan, sizeof(h.lngHzWSwan) ); - out.hash_( (const byte *) &h.lngHzVSU, sizeof(h.lngHzVSU) ); - out.hash_( (const byte *) &h.lngHzSAA1099, sizeof(h.lngHzSAA1099) ); - out.hash_( (const byte *) &h.lngHzES5503, sizeof(h.lngHzES5503) ); - out.hash_( (const byte *) &h.lngHzES5506, sizeof(h.lngHzES5506) ); - out.hash_( (const byte *) &h.bytES5503Chns, sizeof(h.bytES5503Chns) ); - out.hash_( (const byte *) &h.bytES5506Chns, sizeof(h.bytES5506Chns) ); - out.hash_( (const byte *) &h.bytC352ClkDiv, sizeof(h.bytC352ClkDiv) ); - out.hash_( (const byte *) &h.bytESReserved, sizeof(h.bytESReserved) ); - out.hash_( (const byte *) &h.lngHzX1_010, sizeof(h.lngHzX1_010) ); - out.hash_( (const byte *) &h.lngHzC352, sizeof(h.lngHzC352) ); - out.hash_( (const byte *) &h.lngHzGA20, sizeof(h.lngHzGA20) ); - out.hash_( data, data_size ); -} - -struct VGM_FILE_mem -{ - VGM_FILE vf; - const BOOST::uint8_t* buffer; - UINT32 ptr; - UINT32 size; -}; - -static int VGMF_mem_Read(VGM_FILE* f, void* out, UINT32 count) -{ - VGM_FILE_mem* mf = (VGM_FILE_mem *) f; - if (count + mf->ptr > mf->size) - count = mf->size - mf->ptr; - memcpy(out, mf->buffer + mf->ptr, count); - mf->ptr += count; - return count; -} - -static int VGMF_mem_Seek(VGM_FILE* f, UINT32 offset) -{ - VGM_FILE_mem* mf = (VGM_FILE_mem *) f; - if (offset > mf->size) - offset = mf->size; - mf->ptr = offset; - return 0; -} - -static UINT32 VGMF_mem_GetSize(VGM_FILE* f) -{ - VGM_FILE_mem* mf = (VGM_FILE_mem *) f; - return mf->size; -} - -struct Vgm_File : Gme_Info_ -{ - Vgm_Emu::header_t h; - blargg_vector original_header; - blargg_vector data; - blargg_vector gd3; - - track_info_t metadata; - track_info_t metadata_j; - - Vgm_File() { set_type( gme_vgm_type ); } - - blargg_err_t load_mem_( const byte* in, int file_size ) - { - VGM_FILE_mem memFile; - - memFile.vf.Read = &VGMF_mem_Read; - memFile.vf.Seek = &VGMF_mem_Seek; - memFile.vf.GetSize = &VGMF_mem_GetSize; - memFile.buffer = in; - memFile.ptr = 0; - memFile.size = file_size; - - if (!GetVGMFileInfo_Handle((VGM_FILE *) &memFile, &h, 0)) - return blargg_err_file_type; - - int data_offset = get_le32( &h.lngDataOffset ); - int data_size = file_size - data_offset; - int gd3_offset = get_le32( &h.lngGD3Offset ); - - if ( gd3_offset > 0 && gd3_offset > data_offset ) - { - data_size = gd3_offset - data_offset; - - RETURN_ERR( data.resize( data_size ) ); - memcpy( data.begin(), in + data_offset, data_size ); - } - - int remain = file_size - gd3_offset; - byte gd3_h [gd3_header_size]; - if ( gd3_offset > 0 && remain >= gd3_header_size ) - { - memcpy( gd3_h, in + gd3_offset, sizeof gd3_h ); - int gd3_size = check_gd3_header( gd3_h, remain ); - if ( gd3_size ) - { - RETURN_ERR( gd3.resize( gd3_size ) ); - memcpy( gd3.begin(), in + sizeof gd3_h + gd3_offset, gd3.size() ); - } - - if ( data_offset > gd3_offset ) - { - RETURN_ERR( data.resize( data_size ) ); - memcpy( data.begin(), in + data_offset, data_size ); - } - } - - int header_size = data_offset; - if ( gd3_offset && data_offset > gd3_offset ) - header_size = gd3_offset; - RETURN_ERR( original_header.resize( header_size ) ); - memcpy( original_header.begin(), in, header_size ); - - memset( &metadata, 0, sizeof(metadata) ); - memset( &metadata_j, 0, sizeof(metadata_j) ); - get_vgm_length( h, &metadata ); - if ( gd3.size() ) - parse_gd3( gd3.begin(), gd3.end(), &metadata, &metadata_j ); - - return blargg_ok; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - *out = metadata; - return blargg_ok; - } - - blargg_err_t hash_( Hash_Function& out ) const - { - hash_vgm_file( h, data.begin(), (int)(data.end() - data.begin()), out ); - return blargg_ok; - } - - blargg_err_t set_track_info_( const track_info_t* in, int ) - { - metadata = *in; - - return blargg_ok; - } - - blargg_err_t save_( gme_writer_t writer, void* your_data ) const - { - byte buffer[4]; - int data_size = (int)(data.end() - data.begin()); - int gd3_offset = (int)(original_header.end() - original_header.begin()) + data_size; - - RETURN_ERR( writer( your_data, original_header.begin(), 0x14 ) ); - set_le32(buffer, gd3_offset - 0x14); - RETURN_ERR( writer( your_data, buffer, 4 ) ); - RETURN_ERR( writer( your_data, original_header.begin() + 0x18, original_header.end() - original_header.begin() - 0x18 ) ); - RETURN_ERR( writer( your_data, data.begin(), data_size ) ); - - return write_gd3( writer, your_data, &metadata, &metadata_j ); - } -}; - -static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; } -static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; } - -gme_type_t_ const gme_vgm_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 0 }}; - -gme_type_t_ const gme_vgz_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 0 }}; - -// Setup - -void Vgm_Emu::set_tempo_( double t ) -{ - core.set_tempo( t ); -} - -blargg_err_t Vgm_Emu::set_sample_rate_( int sample_rate ) -{ - core.set_sample_rate(sample_rate); - return blargg_ok; -} - -void Vgm_Emu::mute_voices_( int mask ) -{ - muted_voices = mask; - core.set_mute(mask); -} - -// Emulation - -blargg_err_t Vgm_Emu::start_track_( int track ) -{ - core.start_track(); - - mute_voices_(muted_voices); - - return blargg_ok; -} - -inline void Vgm_Emu::check_end() -{ - if ( core.track_ended() ) - set_track_ended(); -} - -blargg_err_t Vgm_Emu::play_( int count, sample_t out [] ) -{ - core.play_(count, out); - check_end(); - return blargg_ok; -} - -blargg_err_t Vgm_Emu::hash_( Hash_Function& out ) const -{ - byte const* p = file_begin(); - byte const* e = file_end(); - int data_offset = header().lngDataOffset; - if ( data_offset ) - p += data_offset; - int gd3_offset = header().lngGD3Offset; - if ( gd3_offset > 0 && gd3_offset > data_offset ) - e = file_begin() + gd3_offset; - hash_vgm_file( header(), p, (int)(e - p), out ); - return blargg_ok; -} - -blargg_err_t Vgm_Emu::load_mem_( const byte* in, int file_size ) -{ - RETURN_ERR( core.load_mem(in, file_size) ); - - int voice_count = core.get_channel_count(); - - set_voice_count( voice_count ); - - char ** voice_names = (char **) calloc( sizeof(char *), voice_count + 1 ); - if (voice_names) - { - int i; - for (i = 0; i < voice_count; i++) - { - voice_names[i] = core.get_voice_name(i); - if (!voice_names[i]) - break; - } - if (i == voice_count) - set_voice_names(voice_names); - else - { - for (i = 0; i < voice_count; i++) - { - if (voice_names[i]) - free(voice_names[i]); - } - free(voice_names); - } - } - - get_vgm_length( header(), &metadata ); - - int data_offset = header().lngDataOffset; - int gd3_offset = header().lngGD3Offset; - int data_size = file_size - data_offset; - - if (gd3_offset > 0) - { - if (gd3_offset > data_offset) - data_size = gd3_offset - data_offset; - byte const* gd3 = core.file_begin() + gd3_offset; - int gd3_size = check_gd3_header( gd3, (int)(core.file_end() - gd3) ); - if ( gd3_size ) - { - byte const* gd3_data = gd3 + gd3_header_size; - parse_gd3( gd3_data, gd3_data + gd3_size, &metadata, &metadata_j ); - } - } - - int header_size = data_offset; - if ( gd3_offset && data_offset > gd3_offset ) - header_size = gd3_offset; - RETURN_ERR( original_header.resize( header_size ) ); - memcpy( original_header.begin(), in, header_size ); - - RETURN_ERR( data.resize(data_size) ); - memcpy( data.begin(), in + data_offset, data_size ); - - return blargg_ok; -} - -blargg_err_t Vgm_Emu::skip_( int count ) -{ - core.skip_(count); - return blargg_ok; -} - -blargg_err_t Vgm_Emu::set_track_info_( const track_info_t* in, int ) -{ - metadata = *in; - - return blargg_ok; -} - -blargg_err_t Vgm_Emu::save_(gme_writer_t writer, void* your_data) -{ - byte buffer[4]; - int data_size = (int)(data.end() - data.begin()); - int gd3_offset = (int)(original_header.end() - original_header.begin()) + data_size; - - RETURN_ERR( writer( your_data, original_header.begin(), 0x14 ) ); - set_le32(buffer, gd3_offset - 0x14); - RETURN_ERR( writer( your_data, buffer, 4 ) ); - RETURN_ERR( writer( your_data, original_header.begin() + 0x18, original_header.end() - original_header.begin() - 0x18 ) ); - RETURN_ERR( writer( your_data, data.begin(), data_size ) ); - - return write_gd3( writer, your_data, &metadata, &metadata_j ); -} +// Game_Music_Emu $vers. http://www.slack.net/~ant/ + +#include "Vgm_Emu.h" + +#include "blargg_endian.h" +#include "blargg_common.h" + +/* Copyright (C) 2003-2008 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +// FM emulators are internally quieter to avoid 16-bit overflow +double const fm_gain = 3.0; +double const rolloff = 0.990; +double const oversample_factor = 1.5; + +Vgm_Emu::Vgm_Emu() +{ + muted_voices = 0; + set_type( gme_vgm_type ); + set_max_initial_silence( 1 ); + set_silence_lookahead( 1 ); // tracks should already be trimmed +} + +Vgm_Emu::~Vgm_Emu() +{ + // XXX ugly use of deprecated functions to free allocated voice names + const char ** voice_names_ = voice_names(); + if (voice_names_) + { + for (int i = 0; i < 32; ++i) + { + if (voice_names_[i]) + core.free_voice_name((char*)voice_names_[i]); + else break; + } + free((void *)voice_names_); + } +} + +void Vgm_Emu::unload() +{ + core.unload(); +} + +// Track info + +static byte const* skip_gd3_str( byte const in [], byte const* end ) +{ + while ( end - in >= 2 ) + { + in += 2; + if ( !(in [-2] | in [-1]) ) + break; + } + return in; +} + +static byte const* get_gd3_str( byte const* in, byte const* end, char field [] ) +{ + byte const* mid = skip_gd3_str( in, end ); + int len = (int)((mid - in) / 2) - 1; + if ( len > 0 ) + { + char * in_utf8 = blargg_to_utf8( (blargg_wchar_t *) in ); + len = min( len, (int) Gme_File::max_field_ ); + field [len] = 0; + for ( int i = 0; i < len; i++ ) + field [i] = in_utf8 [i]; + free(in_utf8); + } + return mid; +} + +static byte const* get_gd3_pair( byte const* in, byte const* end, char field [], char field_j [] ) +{ + return get_gd3_str( get_gd3_str( in, end, field ), end, field_j ); +} + +static void parse_gd3( byte const in [], byte const* end, track_info_t* out, track_info_t* out_j ) +{ + in = get_gd3_pair( in, end, out->song , out_j->song ); + in = get_gd3_pair( in, end, out->game , out_j->game ); + in = get_gd3_pair( in, end, out->system , out_j->system ); + in = get_gd3_pair( in, end, out->author , out_j->author ); + in = get_gd3_str ( in, end, out->copyright ); + in = get_gd3_pair( in, end, out->dumper , out_j->dumper ); + in = get_gd3_str ( in, end, out->comment ); +} + +static blargg_err_t write_gd3_str( gme_writer_t writer, void* your_data, const char field [] ) +{ + blargg_wchar_t * wstring = blargg_to_wide( field ); + if (!wstring) + return "Out of memory"; + blargg_err_t err = writer( your_data, wstring, blargg_wcslen( wstring ) * 2 + 2 ); + free( wstring ); + return err; +} + +static blargg_err_t write_gd3_pair( gme_writer_t writer, void* your_data, const char field [], const char field_j [] ) +{ + RETURN_ERR(write_gd3_str( writer, your_data, field )); + RETURN_ERR(write_gd3_str( writer, your_data, field )); + return blargg_ok; +} + +static blargg_err_t write_gd3_strings( gme_writer_t writer, void* your_data, const track_info_t* in, const track_info_t* in_j ) +{ + RETURN_ERR(write_gd3_pair( writer, your_data, in->song , in_j->song )); + RETURN_ERR(write_gd3_pair( writer, your_data, in->game , in_j->game )); + RETURN_ERR(write_gd3_pair( writer, your_data, in->system , in_j->system )); + RETURN_ERR(write_gd3_pair( writer, your_data, in->author , in_j->author )); + RETURN_ERR(write_gd3_str ( writer, your_data, in->copyright )); + RETURN_ERR(write_gd3_pair( writer, your_data, in->dumper , in_j->dumper )); + RETURN_ERR(write_gd3_str ( writer, your_data, in->comment )); + return blargg_ok; +} + +static gme_err_t writer_calc_size(void* param, const void* ptr, long count) +{ + *(long *)param += count; + return blargg_ok; +} + +static blargg_err_t write_gd3( gme_writer_t writer, void* your_data, const track_info_t* in, const track_info_t* in_j ) +{ + long string_size = 0; + byte version[4]; + RETURN_ERR(writer( your_data, "Gd3 ", 4 )); + set_le32(version, 0x100); + RETURN_ERR(writer( your_data, version, 4 )); + write_gd3_strings( &writer_calc_size, &string_size, in, in_j ); + if ( string_size > 1000000000 ) + return "GD3 tag too large"; + set_le32(version, (int)string_size); + RETURN_ERR(writer( your_data, version, 4)); + return write_gd3_strings( writer, your_data, in, in_j ); +} + +int const gd3_header_size = 12; + +static int check_gd3_header( byte const h [], int remain ) +{ + if ( remain < gd3_header_size ) return 0; + if ( memcmp( h, "Gd3 ", 4 ) ) return 0; + if ( get_le32( h + 4 ) >= 0x200 ) return 0; + + int gd3_size = get_le32( h + 8 ); + if ( gd3_size > remain - gd3_header_size ) return 0; + + return gd3_size; +} + +static void get_vgm_length( Vgm_Emu::header_t const& h, track_info_t* out ) +{ + int length = h.lngTotalSamples * 10 / 441; // 1000 / 44100 + if ( length > 0 ) + { + int loop = h.lngLoopSamples; + if ( loop > 0 && h.lngLoopOffset ) + { + out->length = 0; + out->loop_length = loop * 10 / 441; + out->intro_length = length - out->loop_length; + check( out->loop_length <= length ); + // TODO: Also set out->length? We now have play_length for suggested play time. + } + else + { + out->length = length; + out->intro_length = length; + out->loop_length = 0; + } + } +} + +blargg_err_t Vgm_Emu::track_info_( track_info_t* out, int ) const +{ + *out = metadata; + + return blargg_ok; +} + +blargg_err_t Vgm_Emu::gd3_data( const unsigned char ** data, int * size ) +{ + *data = 0; + *size = 0; + + int gd3_offset = header().lngGD3Offset; + if ( gd3_offset <= 0 ) + return blargg_ok; + + byte const* gd3 = core.file_begin() + gd3_offset; + int gd3_size = check_gd3_header( gd3, (int)(core.file_end() - gd3) ); + if ( gd3_size ) + { + *data = gd3; + *size = gd3_size + gd3_header_size; + } + + return blargg_ok; +} + +static void hash_vgm_file( Vgm_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) +{ + out.hash_( (const byte *) &h.lngEOFOffset, sizeof(h.lngEOFOffset) ); + out.hash_( (const byte *) &h.lngVersion, sizeof(h.lngVersion) ); + out.hash_( (const byte *) &h.lngHzPSG, sizeof(h.lngHzPSG) ); + out.hash_( (const byte *) &h.lngHzYM2413, sizeof(h.lngHzYM2413) ); + out.hash_( (const byte *) &h.lngTotalSamples, sizeof(h.lngTotalSamples) ); + out.hash_( (const byte *) &h.lngLoopOffset, sizeof(h.lngLoopOffset) ); + out.hash_( (const byte *) &h.lngLoopSamples, sizeof(h.lngLoopSamples) ); + out.hash_( (const byte *) &h.lngRate, sizeof(h.lngRate) ); + out.hash_( (const byte *) &h.shtPSG_Feedback, sizeof(h.shtPSG_Feedback) ); + out.hash_( (const byte *) &h.bytPSG_SRWidth, sizeof(h.bytPSG_SRWidth) ); + out.hash_( (const byte *) &h.bytPSG_Flags, sizeof(h.bytPSG_Flags) ); + out.hash_( (const byte *) &h.lngHzYM2612, sizeof(h.lngHzYM2612) ); + out.hash_( (const byte *) &h.lngHzYM2151, sizeof(h.lngHzYM2151) ); + out.hash_( (const byte *) &h.lngDataOffset, sizeof(h.lngDataOffset) ); + out.hash_( (const byte *) &h.lngHzSPCM, sizeof(h.lngHzSPCM) ); + out.hash_( (const byte *) &h.lngSPCMIntf, sizeof(h.lngSPCMIntf) ); + out.hash_( (const byte *) &h.lngHzRF5C68, sizeof(h.lngHzRF5C68) ); + out.hash_( (const byte *) &h.lngHzYM2203, sizeof(h.lngHzYM2203) ); + out.hash_( (const byte *) &h.lngHzYM2608, sizeof(h.lngHzYM2608) ); + out.hash_( (const byte *) &h.lngHzYM2610, sizeof(h.lngHzYM2610) ); + out.hash_( (const byte *) &h.lngHzYM3812, sizeof(h.lngHzYM3812) ); + out.hash_( (const byte *) &h.lngHzYM3526, sizeof(h.lngHzYM3526) ); + out.hash_( (const byte *) &h.lngHzY8950, sizeof(h.lngHzY8950) ); + out.hash_( (const byte *) &h.lngHzYMF262, sizeof(h.lngHzYMF262) ); + out.hash_( (const byte *) &h.lngHzYMF278B, sizeof(h.lngHzYMF278B) ); + out.hash_( (const byte *) &h.lngHzYMF271, sizeof(h.lngHzYMF271) ); + out.hash_( (const byte *) &h.lngHzYMZ280B, sizeof(h.lngHzYMZ280B) ); + out.hash_( (const byte *) &h.lngHzRF5C164, sizeof(h.lngHzRF5C164) ); + out.hash_( (const byte *) &h.lngHzPWM, sizeof(h.lngHzPWM) ); + out.hash_( (const byte *) &h.lngHzAY8910, sizeof(h.lngHzAY8910) ); + out.hash_( (const byte *) &h.bytAYType, sizeof(h.bytAYType) ); + out.hash_( (const byte *) &h.bytAYFlag, sizeof(h.bytAYFlag) ); + out.hash_( (const byte *) &h.bytAYFlagYM2203, sizeof(h.bytAYFlagYM2203) ); + out.hash_( (const byte *) &h.bytAYFlagYM2608, sizeof(h.bytAYFlagYM2608) ); + out.hash_( (const byte *) &h.bytReserved2, sizeof(h.bytReserved2) ); + out.hash_( (const byte *) &h.lngHzGBDMG, sizeof(h.lngHzGBDMG) ); + out.hash_( (const byte *) &h.lngHzNESAPU, sizeof(h.lngHzNESAPU) ); + out.hash_( (const byte *) &h.lngHzMultiPCM, sizeof(h.lngHzMultiPCM) ); + out.hash_( (const byte *) &h.lngHzUPD7759, sizeof(h.lngHzUPD7759) ); + out.hash_( (const byte *) &h.lngHzOKIM6258, sizeof(h.lngHzOKIM6258) ); + out.hash_( (const byte *) &h.bytOKI6258Flags, sizeof(h.bytOKI6258Flags) ); + out.hash_( (const byte *) &h.bytK054539Flags, sizeof(h.bytK054539Flags) ); + out.hash_( (const byte *) &h.bytC140Type, sizeof(h.bytC140Type) ); + out.hash_( (const byte *) &h.bytReservedFlags, sizeof(h.bytReservedFlags) ); + out.hash_( (const byte *) &h.lngHzOKIM6295, sizeof(h.lngHzOKIM6295) ); + out.hash_( (const byte *) &h.lngHzK051649, sizeof(h.lngHzK051649) ); + out.hash_( (const byte *) &h.lngHzK054539, sizeof(h.lngHzK054539) ); + out.hash_( (const byte *) &h.lngHzHuC6280, sizeof(h.lngHzHuC6280) ); + out.hash_( (const byte *) &h.lngHzC140, sizeof(h.lngHzC140) ); + out.hash_( (const byte *) &h.lngHzK053260, sizeof(h.lngHzK053260) ); + out.hash_( (const byte *) &h.lngHzPokey, sizeof(h.lngHzPokey) ); + out.hash_( (const byte *) &h.lngHzQSound, sizeof(h.lngHzQSound) ); + out.hash_( (const byte *) &h.lngHzSCSP, sizeof(h.lngHzSCSP) ); + // out.hash_( (const byte *) &h.lngExtraOffset, sizeof(h.lngExtraOffset) ); + out.hash_( (const byte *) &h.lngHzWSwan, sizeof(h.lngHzWSwan) ); + out.hash_( (const byte *) &h.lngHzVSU, sizeof(h.lngHzVSU) ); + out.hash_( (const byte *) &h.lngHzSAA1099, sizeof(h.lngHzSAA1099) ); + out.hash_( (const byte *) &h.lngHzES5503, sizeof(h.lngHzES5503) ); + out.hash_( (const byte *) &h.lngHzES5506, sizeof(h.lngHzES5506) ); + out.hash_( (const byte *) &h.bytES5503Chns, sizeof(h.bytES5503Chns) ); + out.hash_( (const byte *) &h.bytES5506Chns, sizeof(h.bytES5506Chns) ); + out.hash_( (const byte *) &h.bytC352ClkDiv, sizeof(h.bytC352ClkDiv) ); + out.hash_( (const byte *) &h.bytESReserved, sizeof(h.bytESReserved) ); + out.hash_( (const byte *) &h.lngHzX1_010, sizeof(h.lngHzX1_010) ); + out.hash_( (const byte *) &h.lngHzC352, sizeof(h.lngHzC352) ); + out.hash_( (const byte *) &h.lngHzGA20, sizeof(h.lngHzGA20) ); + out.hash_( data, data_size ); +} + +struct VGM_FILE_mem +{ + VGM_FILE vf; + const BOOST::uint8_t* buffer; + UINT32 ptr; + UINT32 size; +}; + +static int VGMF_mem_Read(VGM_FILE* f, void* out, UINT32 count) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + if (count + mf->ptr > mf->size) + count = mf->size - mf->ptr; + memcpy(out, mf->buffer + mf->ptr, count); + mf->ptr += count; + return count; +} + +static int VGMF_mem_Seek(VGM_FILE* f, UINT32 offset) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + if (offset > mf->size) + offset = mf->size; + mf->ptr = offset; + return 0; +} + +static UINT32 VGMF_mem_GetSize(VGM_FILE* f) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + return mf->size; +} + +static UINT32 VGMF_mem_Tell(VGM_FILE* f) +{ + VGM_FILE_mem* mf = (VGM_FILE_mem *) f; + return mf->ptr; +} + +struct Vgm_File : Gme_Info_ +{ + Vgm_Emu::header_t h; + blargg_vector original_header; + blargg_vector data; + blargg_vector gd3; + + track_info_t metadata; + track_info_t metadata_j; + + Vgm_File() { set_type( gme_vgm_type ); } + + blargg_err_t load_mem_( const byte* in, int file_size ) + { + VGM_FILE_mem memFile; + + memFile.vf.Read = &VGMF_mem_Read; + memFile.vf.Seek = &VGMF_mem_Seek; + memFile.vf.GetSize = &VGMF_mem_GetSize; + memFile.vf.Tell = &VGMF_mem_Tell; + memFile.buffer = in; + memFile.ptr = 0; + memFile.size = file_size; + + if (!GetVGMFileInfo_Handle((VGM_FILE *) &memFile, &h, 0)) + return blargg_err_file_type; + + int data_offset = get_le32( &h.lngDataOffset ); + int data_size = file_size - data_offset; + int gd3_offset = get_le32( &h.lngGD3Offset ); + + if ( gd3_offset > 0 && gd3_offset > data_offset ) + { + data_size = gd3_offset - data_offset; + + RETURN_ERR( data.resize( data_size ) ); + memcpy( data.begin(), in + data_offset, data_size ); + } + + int remain = file_size - gd3_offset; + byte gd3_h [gd3_header_size]; + if ( gd3_offset > 0 && remain >= gd3_header_size ) + { + memcpy( gd3_h, in + gd3_offset, sizeof gd3_h ); + int gd3_size = check_gd3_header( gd3_h, remain ); + if ( gd3_size ) + { + RETURN_ERR( gd3.resize( gd3_size ) ); + memcpy( gd3.begin(), in + sizeof gd3_h + gd3_offset, gd3.size() ); + } + + if ( data_offset > gd3_offset ) + { + RETURN_ERR( data.resize( data_size ) ); + memcpy( data.begin(), in + data_offset, data_size ); + } + } + + int header_size = data_offset; + if ( gd3_offset && data_offset > gd3_offset ) + header_size = gd3_offset; + RETURN_ERR( original_header.resize( header_size ) ); + memcpy( original_header.begin(), in, header_size ); + + memset( &metadata, 0, sizeof(metadata) ); + memset( &metadata_j, 0, sizeof(metadata_j) ); + get_vgm_length( h, &metadata ); + if ( gd3.size() ) + parse_gd3( gd3.begin(), gd3.end(), &metadata, &metadata_j ); + + return blargg_ok; + } + + blargg_err_t track_info_( track_info_t* out, int ) const + { + *out = metadata; + return blargg_ok; + } + + blargg_err_t hash_( Hash_Function& out ) const + { + hash_vgm_file( h, data.begin(), (int)(data.end() - data.begin()), out ); + return blargg_ok; + } + + blargg_err_t set_track_info_( const track_info_t* in, int ) + { + metadata = *in; + + return blargg_ok; + } + + blargg_err_t save_( gme_writer_t writer, void* your_data ) const + { + byte buffer[4]; + int data_size = (int)(data.end() - data.begin()); + int gd3_offset = (int)(original_header.end() - original_header.begin()) + data_size; + + RETURN_ERR( writer( your_data, original_header.begin(), 0x14 ) ); + set_le32(buffer, gd3_offset - 0x14); + RETURN_ERR( writer( your_data, buffer, 4 ) ); + RETURN_ERR( writer( your_data, original_header.begin() + 0x18, original_header.end() - original_header.begin() - 0x18 ) ); + RETURN_ERR( writer( your_data, data.begin(), data_size ) ); + + return write_gd3( writer, your_data, &metadata, &metadata_j ); + } +}; + +static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; } +static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; } + +gme_type_t_ const gme_vgm_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 0 }}; + +gme_type_t_ const gme_vgz_type [1] = {{ "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 0 }}; + +// Setup + +void Vgm_Emu::set_tempo_( double t ) +{ + core.set_tempo( t ); +} + +blargg_err_t Vgm_Emu::set_sample_rate_( int sample_rate ) +{ + core.set_sample_rate(sample_rate); + return blargg_ok; +} + +void Vgm_Emu::mute_voices_( int mask ) +{ + muted_voices = mask; + core.set_mute(mask); +} + +// Emulation + +blargg_err_t Vgm_Emu::start_track_( int track ) +{ + core.start_track(); + + mute_voices_(muted_voices); + + return blargg_ok; +} + +inline void Vgm_Emu::check_end() +{ + if ( core.track_ended() ) + set_track_ended(); +} + +blargg_err_t Vgm_Emu::play_( int count, sample_t out [] ) +{ + core.play_(count, out); + check_end(); + return blargg_ok; +} + +blargg_err_t Vgm_Emu::hash_( Hash_Function& out ) const +{ + byte const* p = file_begin(); + byte const* e = file_end(); + int data_offset = header().lngDataOffset; + if ( data_offset ) + p += data_offset; + int gd3_offset = header().lngGD3Offset; + if ( gd3_offset > 0 && gd3_offset > data_offset ) + e = file_begin() + gd3_offset; + hash_vgm_file( header(), p, (int)(e - p), out ); + return blargg_ok; +} + +blargg_err_t Vgm_Emu::load_mem_( const byte* in, int file_size ) +{ + RETURN_ERR( core.load_mem(in, file_size) ); + + int voice_count = core.get_channel_count(); + + set_voice_count( voice_count ); + + char ** voice_names = (char **) calloc( sizeof(char *), voice_count + 1 ); + if (voice_names) + { + int i; + for (i = 0; i < voice_count; i++) + { + voice_names[i] = core.get_voice_name(i); + if (!voice_names[i]) + break; + } + if (i == voice_count) + set_voice_names(voice_names); + else + { + for (i = 0; i < voice_count; i++) + { + if (voice_names[i]) + free(voice_names[i]); + } + free(voice_names); + } + } + + get_vgm_length( header(), &metadata ); + + int data_offset = header().lngDataOffset; + int gd3_offset = header().lngGD3Offset; + int data_size = file_size - data_offset; + + if (gd3_offset > 0) + { + if (gd3_offset > data_offset) + data_size = gd3_offset - data_offset; + byte const* gd3 = core.file_begin() + gd3_offset; + int gd3_size = check_gd3_header( gd3, (int)(core.file_end() - gd3) ); + if ( gd3_size ) + { + byte const* gd3_data = gd3 + gd3_header_size; + parse_gd3( gd3_data, gd3_data + gd3_size, &metadata, &metadata_j ); + } + } + + int header_size = data_offset; + if ( gd3_offset && data_offset > gd3_offset ) + header_size = gd3_offset; + RETURN_ERR( original_header.resize( header_size ) ); + memcpy( original_header.begin(), in, header_size ); + + RETURN_ERR( data.resize(data_size) ); + memcpy( data.begin(), in + data_offset, data_size ); + + return blargg_ok; +} + +blargg_err_t Vgm_Emu::skip_( int count ) +{ + core.skip_(count); + return blargg_ok; +} + +blargg_err_t Vgm_Emu::set_track_info_( const track_info_t* in, int ) +{ + metadata = *in; + + return blargg_ok; +} + +blargg_err_t Vgm_Emu::save_(gme_writer_t writer, void* your_data) +{ + byte buffer[4]; + int data_size = (int)(data.end() - data.begin()); + int gd3_offset = (int)(original_header.end() - original_header.begin()) + data_size; + + RETURN_ERR( writer( your_data, original_header.begin(), 0x14 ) ); + set_le32(buffer, gd3_offset - 0x14); + RETURN_ERR( writer( your_data, buffer, 4 ) ); + RETURN_ERR( writer( your_data, original_header.begin() + 0x18, original_header.end() - original_header.begin() - 0x18 ) ); + RETURN_ERR( writer( your_data, data.begin(), data_size ) ); + + return write_gd3( writer, your_data, &metadata, &metadata_j ); +} diff --git a/Frameworks/GME/vgmplay/ChipMapper.c b/Frameworks/GME/vgmplay/ChipMapper.c index 0c02e8359..0c0719546 100644 --- a/Frameworks/GME/vgmplay/ChipMapper.c +++ b/Frameworks/GME/vgmplay/ChipMapper.c @@ -1,7 +1,7 @@ // ChipMapper.c - Handles Chip Write (including OPL Hardware Support) #include -#include +#include #include #include #include "stdbool.h" @@ -14,6 +14,18 @@ #include "ChipMapper.h" +// To finish filling out later +UINT8 chip_reg_read(void *param, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset) +{ + VGM_PLAYER* p = (VGM_PLAYER *) param; + switch(ChipType) + { + case 0x1B: // HuC6280 + return c6280_r(p->huc6280[ChipID], Offset); + } + return 0; +} + void chip_reg_write(void *param, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data) { diff --git a/Frameworks/GME/vgmplay/ChipMapper.h b/Frameworks/GME/vgmplay/ChipMapper.h index c61579f17..cd2853d44 100644 --- a/Frameworks/GME/vgmplay/ChipMapper.h +++ b/Frameworks/GME/vgmplay/ChipMapper.h @@ -1 +1,2 @@ +UINT8 chip_reg_read(void *, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset); void chip_reg_write(void *, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data); diff --git a/Frameworks/GME/vgmplay/VGMPlay.c b/Frameworks/GME/vgmplay/VGMPlay.c index e8f84d39a..53ee86840 100644 --- a/Frameworks/GME/vgmplay/VGMPlay.c +++ b/Frameworks/GME/vgmplay/VGMPlay.c @@ -109,7 +109,7 @@ INLINE INT32 SampleVGM2Pbk_I(VGM_PLAYER*, INT32 SampleVal); // inline functions INLINE INT32 SamplePbk2VGM_I(VGM_PLAYER*, INT32 SampleVal); //INT32 SampleVGM2Playback(void*, INT32 SampleVal); // non-inline functions //INT32 SamplePlayback2VGM(void*, INT32 SampleVal); -static bool SetMuteControl(VGM_PLAYER*, bool mute); +//static bool SetMuteControl(VGM_PLAYER*, bool mute); static void InterpretFile(VGM_PLAYER*, UINT32 SampleCount); static void AddPCMData(VGM_PLAYER*, UINT8 Type, UINT32 DataSize, const UINT8* Data); @@ -156,6 +156,7 @@ void * VGMPlay_Init(void) p->SampleRate = 44100; p->FadeTime = 5000; + p->HardStopOldVGMs = 0x00; p->FadeRAWLog = false; p->VolumeLevel = 1.0f; //p->FullBufFill = false; @@ -381,8 +382,8 @@ static UINT32 gcd(UINT32 x, UINT32 y) void PlayVGM(void *_p) { - UINT8 CurChip; - UINT8 FMVal; + /*UINT8 CurChip;*/ + /*UINT8 FMVal;*/ INT32 TempSLng; VGM_PLAYER* p = (VGM_PLAYER*)_p; @@ -659,6 +660,12 @@ static UINT32 VGMF_gzgetsize(VGM_FILE* hFile) VGM_FILE_gz* File = (VGM_FILE_gz *)hFile; return File->Size; } + +static UINT32 VGMF_gztell(VGM_FILE* hFile) +{ + VGM_FILE_gz* File = (VGM_FILE_gz *)hFile; + return gztell(File->hFile); +} #endif bool OpenVGMFile(void *_p, const char* FileName) @@ -683,6 +690,7 @@ bool OpenVGMFile(void *_p, const char* FileName) vgmFile.vf.Read = VGMF_gzread; vgmFile.vf.Seek = VGMF_gzseek; vgmFile.vf.GetSize = VGMF_gzgetsize; + vgmFile.vf.Tell = VGMF_gztell; vgmFile.hFile = hFile; vgmFile.Size = FileSize; @@ -729,6 +737,7 @@ bool OpenVGMFileW(void *_p, const wchar_t* FileName) vgmFile.vf.Read = VGMF_gzread; vgmFile.vf.Seek = VGMF_gzseek; vgmFile.vf.GetSize = VGMF_gzgetsize; + vgmFile.vf.Tell = VGMF_gztell; vgmFile.hFile = hFile; vgmFile.Size = FileSize; @@ -765,6 +774,12 @@ static bool OpenVGMFile_Internal(VGM_PLAYER* p, VGM_FILE* hFile, UINT32 FileSize hFile->Seek(hFile, 0x00); ReadVGMHeader(hFile, &p->VGMHead); + if (p->VGMHead.fccVGM != FCC_VGM) + { + printf("VGM signature matched on the first read, but not on the second one!\n"); + printf("This is a known zlib bug where gzseek fails. Please install a fixed zlib.\n"); + return false; + } p->VGMSampleRate = 44100; if (! p->VGMDataLen) @@ -1172,7 +1187,8 @@ static wchar_t* ReadWStrFromFile(VGM_FILE* hFile, UINT32* FilePos, UINT32 EOFPos if (TextStr == NULL) return NULL; - hFile->Seek(hFile, CurPos); + if (hFile->Tell(hFile) != CurPos) + hFile->Seek(hFile, CurPos); TempStr = TextStr - 1; StrLen = 0x00; do @@ -1294,6 +1310,12 @@ static UINT32 GetVGMFileInfo_Internal(VGM_FILE* hFile, UINT32 FileSize, hFile->Seek(hFile, 0x00); ReadVGMHeader(hFile, &TempHead); + if (TempHead.fccVGM != FCC_VGM) + { + printf("VGM signature matched on the first read, but not on the second one!\n"); + printf("This is a known zlib bug where gzseek fails. Please install a fixed zlib.\n"); + return 0x00; + } if (! TempHead.lngEOFOffset || TempHead.lngEOFOffset > FileSize) TempHead.lngEOFOffset = FileSize; @@ -1416,7 +1438,7 @@ UINT32 CalcSampleMSecExt(void *_p, UINT64 Value, UINT8 Mode, VGM_HEADER* FileHea return RetVal; } -static UINT32 EncryptChipName(void* DstBuf, const void* SrcBuf, UINT32 Length) +/*static UINT32 EncryptChipName(void* DstBuf, const void* SrcBuf, UINT32 Length) { // using nineko's awesome encryption algorithm // http://forums.sonicretro.org/index.php?showtopic=25300 @@ -1446,7 +1468,7 @@ static UINT32 EncryptChipName(void* DstBuf, const void* SrcBuf, UINT32 Length) } return Length; -} +}*/ const char* GetChipName(UINT8 ChipID) { @@ -1576,6 +1598,12 @@ const char* GetAccurateChipName(UINT8 ChipID, UINT8 SubType) else RetStr = "NES APU + FDS"; break; + case 0x19: + if (! (ChipID & 0x80)) + RetStr = "K051649"; + else + RetStr = "K052539"; + break; case 0x1C: switch(SubType) { @@ -1756,6 +1784,7 @@ UINT32 GetChipClock(void* _p, UINT8 ChipID, UINT8* RetSubType) break; case 0x19: Clock = FileHead->lngHzK051649; + AllowBit31 = 0x01; // SCC/SCC+ Bit break; case 0x1A: Clock = FileHead->lngHzK054539; @@ -1802,6 +1831,7 @@ UINT32 GetChipClock(void* _p, UINT8 ChipID, UINT8* RetSubType) break; case 0x27: Clock = FileHead->lngHzC352; + AllowBit31 = 0x01; // disable rear channels break; case 0x28: Clock = FileHead->lngHzGA20; @@ -1848,14 +1878,14 @@ static UINT16 GetChipVolume(VGM_PLAYER* p, UINT8 ChipID, UINT8 ChipNum, UINT8 Ch 0x80, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x98, // 08-0F 0x80, 0xE0/*0xCD*/, 0x100, 0xC0, 0x100, 0x40, 0x11E, 0x1C0, // 10-17 0x100/*110*/, 0xA0, 0x100, 0x100, 0x100, 0xB3, 0x100, 0x100, // 18-1F - 0x100, 0x100, 0x100, 0x100, 0x40, 0x20, 0x100, 0x40, // 20-27 + 0x20, 0x100, 0x100, 0x100, 0x40, 0x20, 0x100, 0x40, // 20-27 0x280}; UINT16 Volume; UINT8 CurChp; VGMX_CHP_EXTRA16* TempCX; VGMX_CHIP_DATA16* TempCD; - VGM_HEADER* FileHead = &p->VGMHead; + /*VGM_HEADER* FileHead = &p->VGMHead;*/ Volume = CHIP_VOLS[ChipID & 0x7F]; switch(ChipID) @@ -2695,7 +2725,7 @@ static void Chips_GeneralActions(VGM_PLAYER* p, UINT8 Mode) { p->ChipOpts[0x01].SCSP.SpecialFlags = p->ChipOpts[0x00].SCSP.SpecialFlags; - //ChipVol = 0x100; + //ChipVol = 0x20; ChipCnt = (p->VGMHead.lngHzSCSP & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { @@ -2708,7 +2738,7 @@ static void Chips_GeneralActions(VGM_PLAYER* p, UINT8 Mode) CAA->StreamUpdateParam = p->scsp[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); - AbsVol += CAA->Volume; + AbsVol += CAA->Volume * 8; } } if (p->VGMHead.lngHzWSwan) @@ -3305,7 +3335,7 @@ INT32 SamplePlayback2VGM(void* _p, INT32 SampleVal) static void InterpretFile(VGM_PLAYER* p, UINT32 SampleCount) { - UINT32 TempLng; + /*UINT32 TempLng;*/ UINT8 CurChip; if (p->DacCtrlUsed && SampleCount > 1) // handle skipping @@ -4007,6 +4037,14 @@ static void InterpretVGM(VGM_PLAYER* p, UINT32 SampleCount) #endif p->VGMHead.lngTotalSamples = p->VGMSmplPos; } + + if (p->HardStopOldVGMs) + { + if (p->VGMHead.lngVersion < 0x150 || + (p->VGMHead.lngVersion == 0x150 && p->HardStopOldVGMs == 0x02)) + Chips_GeneralActions(p, 0x01); // reset all chips, for instant silence + } + p->VGMEnd = true; break; } @@ -4803,7 +4841,7 @@ static void GeneralChipLists(VGM_PLAYER* p) UINT16 CurBufIdx; CA_LIST* CLstOld; CA_LIST* CLst; - CA_LIST* CurLst; + /*CA_LIST* CurLst;*/ UINT8 CurChip; UINT8 CurCSet; CAUD_ATTR* CAA; diff --git a/Frameworks/GME/vgmplay/VGMPlay.h b/Frameworks/GME/vgmplay/VGMPlay.h index da1add077..e3a92fe22 100644 --- a/Frameworks/GME/vgmplay/VGMPlay.h +++ b/Frameworks/GME/vgmplay/VGMPlay.h @@ -6,7 +6,7 @@ #include "VGMPlay_Intf.h" -#define VGMPLAY_VER_STR "0.40.6" +#define VGMPLAY_VER_STR "0.40.7" //#define APLHA //#define BETA #define VGM_VER_STR "1.71b" @@ -179,6 +179,7 @@ typedef struct vgm_player float VolumeLevel; bool SurroundSound; + UINT8 HardStopOldVGMs; bool FadeRAWLog; //bool FullBufFill; // Fill Buffer until it's full diff --git a/Frameworks/GME/vgmplay/VGMPlayUI.c b/Frameworks/GME/vgmplay/VGMPlayUI.c index 1aad2d786..4cc345e58 100644 --- a/Frameworks/GME/vgmplay/VGMPlayUI.c +++ b/Frameworks/GME/vgmplay/VGMPlayUI.c @@ -131,6 +131,7 @@ static UINT8 Show95Cmds; extern float VolumeLevel; extern bool SurroundSound; +extern UINT8 HardStopOldVGMs; extern bool FadeRAWLog; static UINT8 LogToWave; //extern bool FullBufFill; @@ -1105,6 +1106,12 @@ static void ReadOptions(const char* AppName) { PauseTimeJ = strtoul(RStr, NULL, 0); } + else if (! stricmp_u(LStr, "HardStopOld")) + { + HardStopOldVGMs = (UINT8)strtoul(RStr, &TempPnt, 0); + if (TempPnt == RStr) + HardStopOldVGMs = GetBoolFromStr(RStr) ? 0x01 : 0x00; + } else if (! stricmp_u(LStr, "FadeRAWLogs")) { FadeRAWLog = GetBoolFromStr(RStr); @@ -2004,7 +2011,7 @@ static void ShowVGMTag(void) } else { -#if (defined(_MSC_VER) && _MSC_VER < 1400) || defined(__MINGW32__) +#if (defined(_MSC_VER) && _MSC_VER < 1400)// || defined(__MINGW32__) swprintf(TitleStr, L"%.*ls", 0x70, TitleTag); #else swprintf(TitleStr, 0x80, L"%.*ls", 0x70, TitleTag); @@ -2014,7 +2021,7 @@ static void ShowVGMTag(void) if (wcslen(GameTag) && StrLen < 0x6C) { -#if (defined(_MSC_VER) && _MSC_VER < 1400) || defined(__MINGW32__) +#if (defined(_MSC_VER) && _MSC_VER < 1400)// || defined(__MINGW32__) swprintf(TitleStr + StrLen, L" (%.*ls)", 0x70 - 3 - StrLen, GameTag); #else swprintf(TitleStr + StrLen, 0x80, L" (%.*ls)", 0x70 - 3 - StrLen, GameTag); diff --git a/Frameworks/GME/vgmplay/VGMPlay_AddFmts.c b/Frameworks/GME/vgmplay/VGMPlay_AddFmts.c index c71754ffb..0f4f93a8e 100644 --- a/Frameworks/GME/vgmplay/VGMPlay_AddFmts.c +++ b/Frameworks/GME/vgmplay/VGMPlay_AddFmts.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "stdbool.h" #include diff --git a/Frameworks/GME/vgmplay/VGMPlay_Intf.h b/Frameworks/GME/vgmplay/VGMPlay_Intf.h index 938257c0c..1ae677147 100644 --- a/Frameworks/GME/vgmplay/VGMPlay_Intf.h +++ b/Frameworks/GME/vgmplay/VGMPlay_Intf.h @@ -25,6 +25,7 @@ struct vgm_file int (*Read)(VGM_FILE*, void*, UINT32); int (*Seek)(VGM_FILE*, UINT32); UINT32 (*GetSize)(VGM_FILE*); + UINT32 (*Tell)(VGM_FILE*); }; #ifdef __cplusplus diff --git a/Frameworks/GME/vgmplay/chips/2151intf.c b/Frameworks/GME/vgmplay/chips/2151intf.c index 71b4a395c..fa651dae8 100644 --- a/Frameworks/GME/vgmplay/chips/2151intf.c +++ b/Frameworks/GME/vgmplay/chips/2151intf.c @@ -15,7 +15,9 @@ #include "ym2151.h" +#ifndef NULL #define NULL ((void *)0) +#endif typedef struct _ym2151_state ym2151_state; struct _ym2151_state diff --git a/Frameworks/GME/vgmplay/chips/2203intf.c b/Frameworks/GME/vgmplay/chips/2203intf.c index f5c2143b0..519d4a8d5 100644 --- a/Frameworks/GME/vgmplay/chips/2203intf.c +++ b/Frameworks/GME/vgmplay/chips/2203intf.c @@ -1,5 +1,5 @@ #include -#include // for memset +#include // for memset #include // for free #include // for NULL #include "mamedef.h" diff --git a/Frameworks/GME/vgmplay/chips/2413intf.c b/Frameworks/GME/vgmplay/chips/2413intf.c index 4dc30b4c6..a32a564cd 100644 --- a/Frameworks/GME/vgmplay/chips/2413intf.c +++ b/Frameworks/GME/vgmplay/chips/2413intf.c @@ -4,6 +4,7 @@ ****************************************************************/ +#include #include "mamedef.h" //#include "sndintrf.h" //#include "streams.h" @@ -18,7 +19,9 @@ #endif #define EC_EMU2413 0x00 // EMU2413 core from in_vgm, value 0 because it's better than MAME +#ifndef NULL #define NULL ((void *)0) +#endif /* for stream system */ typedef struct _ym2413_state ym2413_state; @@ -75,6 +78,7 @@ void ym2413_stream_update(void *_info, stream_sample_t **outputs, int samples) } } +#ifdef ENABLE_ALL_CORES static stream_sample_t* DUMMYBUF[0x02] = {NULL, NULL}; static void _stream_update(void *param, int interval) @@ -94,6 +98,7 @@ static void _stream_update(void *param, int interval) break; } } +#endif //static DEVICE_START( ym2413 ) int device_start_ym2413(void **_info, int EMU_CORE, int clock, int CHIP_SAMPLING_MODE, int CHIP_SAMPLE_RATE) diff --git a/Frameworks/GME/vgmplay/chips/2608intf.c b/Frameworks/GME/vgmplay/chips/2608intf.c index 512d6e544..c7ab54235 100644 --- a/Frameworks/GME/vgmplay/chips/2608intf.c +++ b/Frameworks/GME/vgmplay/chips/2608intf.c @@ -11,7 +11,7 @@ ***************************************************************************/ -#include // for memset +#include // for memset #include // for free #include // for NULL #include "mamedef.h" @@ -248,6 +248,8 @@ int device_start_ym2608(void **_info, int AY_EMU_CORE, int clock, UINT8 AYDisabl int ay_clock; //void *pcmbufa; //int pcmsizea; + //ym2608_state *info = get_safe_token(device); + ym2608_state *info; #ifdef ENABLE_ALL_CORES if (AY_EMU_CORE >= 0x02) @@ -256,9 +258,6 @@ int device_start_ym2608(void **_info, int AY_EMU_CORE, int clock, UINT8 AYDisabl AY_EMU_CORE = EC_EMU2149; #endif - //ym2608_state *info = get_safe_token(device); - ym2608_state *info; - info = (ym2608_state *) calloc(1, sizeof(ym2608_state)); *_info = (void *) info; diff --git a/Frameworks/GME/vgmplay/chips/2610intf.c b/Frameworks/GME/vgmplay/chips/2610intf.c index 44c03015e..ee7159061 100644 --- a/Frameworks/GME/vgmplay/chips/2610intf.c +++ b/Frameworks/GME/vgmplay/chips/2610intf.c @@ -11,7 +11,7 @@ ***************************************************************************/ -#include // for memset +#include // for memset #include // for free #include // for NULL #include "mamedef.h" @@ -243,12 +243,14 @@ int device_start_ym2610(void **_info, int AY_EMU_CORE, int clock, UINT8 AYDisabl // 1 - YM2610B //static const ym2610_interface generic_2610 = { 0 }; +#ifdef ENABLE_ALL_CORES static const ay8910_interface generic_ay8910 = { AY8910_LEGACY_OUTPUT | AY8910_SINGLE_OUTPUT, AY8910_DEFAULT_LOADS //DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL }; +#endif //const ym2610_interface *intf = device->static_config ? (const ym2610_interface *)device->static_config : &generic_2610; //const ym2610_interface *intf = &generic_2610; int rate; diff --git a/Frameworks/GME/vgmplay/chips/262intf.c b/Frameworks/GME/vgmplay/chips/262intf.c index 96cdb74a4..5b8560c85 100644 --- a/Frameworks/GME/vgmplay/chips/262intf.c +++ b/Frameworks/GME/vgmplay/chips/262intf.c @@ -48,11 +48,13 @@ struct _ymf262_state +#ifdef ENABLE_ALL_CORES static void IRQHandler_262(void *param,int irq) { - ymf262_state *info = (ymf262_state *)param; + //ymf262_state *info = (ymf262_state *)param; //if (info->intf->handler) (info->intf->handler)(info->device, irq); } +#endif /*static TIMER_CALLBACK( timer_callback_262_0 ) { @@ -67,9 +69,10 @@ static TIMER_CALLBACK( timer_callback_262_1 ) }*/ //static void timer_handler_262(void *param,int timer, attotime period) +#ifdef ENABLE_ALL_CORES static void timer_handler_262(void *param,int timer, int period) { - ymf262_state *info = (ymf262_state *)param; + //ymf262_state *info = (ymf262_state *)param; if( period == 0 ) { /* Reset FM Timer */ //timer_enable(info->timer[timer], 0); @@ -79,6 +82,7 @@ static void timer_handler_262(void *param,int timer, int period) //timer_adjust_oneshot(info->timer[timer], period, 0); } } +#endif //static STREAM_UPDATE( ymf262_stream_update ) void ymf262_stream_update(void *param, stream_sample_t **outputs, int samples) diff --git a/Frameworks/GME/vgmplay/chips/3526intf.c b/Frameworks/GME/vgmplay/chips/3526intf.c index 1d0cb0ddf..10db0f958 100644 --- a/Frameworks/GME/vgmplay/chips/3526intf.c +++ b/Frameworks/GME/vgmplay/chips/3526intf.c @@ -25,7 +25,7 @@ #include "3526intf.h" #include "fmopl.h" -#include +#include typedef struct _ym3526_state ym3526_state; struct _ym3526_state @@ -51,7 +51,7 @@ struct _ym3526_state /* IRQ Handler */ static void IRQHandler(void *param,int irq) { - ym3526_state *info = (ym3526_state *)param; + //ym3526_state *info = (ym3526_state *)param; //if (info->intf->handler) (info->intf->handler)(info->device, irq ? ASSERT_LINE : CLEAR_LINE); //if (info->intf->handler) (info->intf->handler)(irq ? ASSERT_LINE : CLEAR_LINE); } @@ -70,7 +70,7 @@ static TIMER_CALLBACK( timer_callback_1 ) //static void TimerHandler(void *param,int c,attotime period) static void TimerHandler(void *param,int c,int period) { - ym3526_state *info = (ym3526_state *)param; + //ym3526_state *info = (ym3526_state *)param; //if( attotime_compare(period, attotime_zero) == 0 ) if( period == 0 ) { /* Reset FM Timer */ diff --git a/Frameworks/GME/vgmplay/chips/3812intf.c b/Frameworks/GME/vgmplay/chips/3812intf.c index e80b984db..87fd3f0ff 100644 --- a/Frameworks/GME/vgmplay/chips/3812intf.c +++ b/Frameworks/GME/vgmplay/chips/3812intf.c @@ -16,7 +16,7 @@ * NOTES * ******************************************************************************/ -#include +#include #include #include "mamedef.h" @@ -32,7 +32,9 @@ #define OPLTYPE_IS_OPL2 #include "adlibemu.h" +#ifndef NULL #define NULL ((void *)0) +#endif #define EC_DBOPL 0x00 // DosBox OPL (AdLibEmu) @@ -62,13 +64,15 @@ struct _ym3812_state }*/ - +#ifdef ENABLE_ALL_CORES static void IRQHandler(void *param,int irq) { - ym3812_state *info = (ym3812_state *)param; + //ym3812_state *info = (ym3812_state *)param; //if (info->intf->handler) (info->intf->handler)(info->device, irq ? ASSERT_LINE : CLEAR_LINE); //if (info->intf->handler) (info->intf->handler)(irq ? ASSERT_LINE : CLEAR_LINE); } +#endif + /*static TIMER_CALLBACK( timer_callback_0 ) { ym3812_state *info = (ym3812_state *)ptr; @@ -82,9 +86,10 @@ static TIMER_CALLBACK( timer_callback_1 ) }*/ //static void TimerHandler(void *param,int c,attotime period) +#ifdef ENABLE_ALL_CORES static void TimerHandler(void *param,int c,int period) { - ym3812_state *info = (ym3812_state *)param; + //ym3812_state *info = (ym3812_state *)param; //if( attotime_compare(period, attotime_zero) == 0 ) if( period == 0 ) { /* Reset FM Timer */ @@ -95,6 +100,7 @@ static void TimerHandler(void *param,int c,int period) //timer_adjust_oneshot(info->timer[c], period, 0); } } +#endif //static STREAM_UPDATE( ym3812_stream_update ) diff --git a/Frameworks/GME/vgmplay/chips/8950intf.c b/Frameworks/GME/vgmplay/chips/8950intf.c index 02770da4a..bc72fc3a2 100644 --- a/Frameworks/GME/vgmplay/chips/8950intf.c +++ b/Frameworks/GME/vgmplay/chips/8950intf.c @@ -26,9 +26,11 @@ //#include "fm.h" #include "fmopl.h" -#include +#include +#ifndef NULL #define NULL ((void *)0) +#endif typedef struct _y8950_state y8950_state; @@ -54,7 +56,7 @@ struct _y8950_state static void IRQHandler(void *param,int irq) { - y8950_state *info = (y8950_state *)param; + //y8950_state *info = (y8950_state *)param; //if (info->intf->handler) (info->intf->handler)(info->device, irq ? ASSERT_LINE : CLEAR_LINE); //if (info->intf->handler) (info->intf->handler)(irq ? ASSERT_LINE : CLEAR_LINE); } @@ -71,7 +73,7 @@ static TIMER_CALLBACK( timer_callback_1 ) //static void TimerHandler(void *param,int c,attotime period) static void TimerHandler(void *param,int c,int period) { - y8950_state *info = (y8950_state *)param; + //y8950_state *info = (y8950_state *)param; //if( attotime_compare(period, attotime_zero) == 0 ) if( period == 0 ) { /* Reset FM Timer */ @@ -86,7 +88,7 @@ static void TimerHandler(void *param,int c,int period) static unsigned char Y8950PortHandler_r(void *param) { - y8950_state *info = (y8950_state *)param; + //y8950_state *info = (y8950_state *)param; /*if (info->intf->portread) return info->intf->portread(0);*/ return 0; @@ -94,14 +96,14 @@ static unsigned char Y8950PortHandler_r(void *param) static void Y8950PortHandler_w(void *param,unsigned char data) { - y8950_state *info = (y8950_state *)param; + //y8950_state *info = (y8950_state *)param; /*if (info->intf->portwrite) info->intf->portwrite(0,data);*/ } static unsigned char Y8950KeyboardHandler_r(void *param) { - y8950_state *info = (y8950_state *)param; + //y8950_state *info = (y8950_state *)param; /*if (info->intf->keyboardread) return info->intf->keyboardread(0);*/ return 0; @@ -109,7 +111,7 @@ static unsigned char Y8950KeyboardHandler_r(void *param) static void Y8950KeyboardHandler_w(void *param,unsigned char data) { - y8950_state *info = (y8950_state *)param; + //y8950_state *info = (y8950_state *)param; /*if (info->intf->keyboardwrite) info->intf->keyboardwrite(0,data);*/ } diff --git a/Frameworks/GME/vgmplay/chips/Ootake_PSG.c b/Frameworks/GME/vgmplay/chips/Ootake_PSG.c index 6b3d94ffb..936cd20e2 100644 --- a/Frameworks/GME/vgmplay/chips/Ootake_PSG.c +++ b/Frameworks/GME/vgmplay/chips/Ootake_PSG.c @@ -50,7 +50,7 @@ Copyright(C)2006-2012 Kitao Nakamura. ******************************************************************************/ #include #include -#include +#include #include #include "mamedef.h" #include "Ootake_PSG.h" @@ -803,7 +803,7 @@ PSG_Write( Uint32 regNum, Uint8 data) { - huc6280_state* info = (huc6280_state*)chip; + //huc6280_state* info = (huc6280_state*)chip; //v1.10更新。キュー処理をここに統合して高速化。 //Kitao更新。clockは考慮せずにシンプルにして高速化した。 diff --git a/Frameworks/GME/vgmplay/chips/Ootake_PSG.h b/Frameworks/GME/vgmplay/chips/Ootake_PSG.h index 7bb6efcd1..3febb04e0 100644 --- a/Frameworks/GME/vgmplay/chips/Ootake_PSG.h +++ b/Frameworks/GME/vgmplay/chips/Ootake_PSG.h @@ -53,7 +53,7 @@ PSG_Mix( /*void PSG_SetSampleRate( - Uint32 sampleRate);* + Uint32 sampleRate);*/ /*void PSGDEBUG_ShowRegs();*/ diff --git a/Frameworks/GME/vgmplay/chips/ay8910.c b/Frameworks/GME/vgmplay/chips/ay8910.c index ed85b1dfd..bdd4837d7 100644 --- a/Frameworks/GME/vgmplay/chips/ay8910.c +++ b/Frameworks/GME/vgmplay/chips/ay8910.c @@ -117,11 +117,13 @@ has twice the steps, happening twice as fast. //#include "cpuintrf.h" //#include "cpuexec.h" #include -#include +#include #include #include "ay8910.h" +#ifndef NULL #define NULL ((void *)0) +#endif /************************************* * @@ -385,6 +387,7 @@ static const ay_ym_param ay8910_param = * *************************************/ +#if 0 INLINE void build_3D_table(double rl, const ay_ym_param *par, const ay_ym_param *par_env, int normalize, double factor, int zero_is_off, INT32 *tab) { int j, j1, j2, j3, e, indx; @@ -456,6 +459,7 @@ INLINE void build_3D_table(double rl, const ay_ym_param *par, const ay_ym_param free(temp); } +#endif INLINE void build_single_table(double rl, const ay_ym_param *par, int normalize, INT32 *tab, int zero_is_off) { @@ -500,6 +504,7 @@ INLINE void build_single_table(double rl, const ay_ym_param *par, int normalize, } +#if 0 INLINE UINT16 mix_3D(ay8910_context *psg) { int indx = 0, chan; @@ -523,6 +528,7 @@ INLINE UINT16 mix_3D(ay8910_context *psg) } return psg->vol3d_table[indx]; } +#endif /************************************* * diff --git a/Frameworks/GME/vgmplay/chips/ay_intf.c b/Frameworks/GME/vgmplay/chips/ay_intf.c index 37702e2b2..a32ee0a94 100644 --- a/Frameworks/GME/vgmplay/chips/ay_intf.c +++ b/Frameworks/GME/vgmplay/chips/ay_intf.c @@ -4,7 +4,7 @@ ****************************************************************/ -#include // for memset +#include // for memset #include // for free #include // for NULL #include "mamedef.h" diff --git a/Frameworks/GME/vgmplay/chips/c140.c b/Frameworks/GME/vgmplay/chips/c140.c index fd81c17d8..303899dc8 100644 --- a/Frameworks/GME/vgmplay/chips/c140.c +++ b/Frameworks/GME/vgmplay/chips/c140.c @@ -45,11 +45,13 @@ Unmapped registers: //#include "emu.h" #include -#include +#include #include "mamedef.h" #include "c140.h" +#ifndef NULL #define NULL ((void *)0) +#endif #define MAX_VOICE 24 diff --git a/Frameworks/GME/vgmplay/chips/c352.c b/Frameworks/GME/vgmplay/chips/c352.c index f22ae20fb..27cefd5cc 100644 --- a/Frameworks/GME/vgmplay/chips/c352.c +++ b/Frameworks/GME/vgmplay/chips/c352.c @@ -1,7 +1,10 @@ /* c352.c - Namco C352 custom PCM chip emulation - v1.2 - By R. Belmont + v2.0 + + Rewritten by superctr + + Original code by R. Belmont Additional code by cync and the hoot development team Thanks to Cap of VivaNonno for info and The_Author for preliminary reverse-engineering @@ -17,717 +20,351 @@ //#include "streams.h" #include #include -#include -#include // for NULL +#include +#include // for NULL #include "mamedef.h" #include "c352.h" #define VERBOSE (0) #define LOG(x) do { if (VERBOSE) logerror x; } while (0) -// flags - +#define C352_VOICES 32 enum { - C352_FLG_BUSY = 0x8000, // channel is busy - C352_FLG_KEYON = 0x4000, // Keyon - C352_FLG_KEYOFF = 0x2000, // Keyoff - C352_FLG_LOOPTRG = 0x1000, // Loop Trigger - C352_FLG_LOOPHIST = 0x0800, // Loop History - C352_FLG_FM = 0x0400, // Frequency Modulation - C352_FLG_PHASERL = 0x0200, // Rear Left invert phase 180 degrees - C352_FLG_PHASEFL = 0x0100, // Front Left invert phase 180 degrees - C352_FLG_PHASEFR = 0x0080, // invert phase 180 degrees (e.g. flip sign of sample) - C352_FLG_LDIR = 0x0040, // loop direction - C352_FLG_LINK = 0x0020, // "long-format" sample (can't loop, not sure what else it means) - C352_FLG_NOISE = 0x0010, // play noise instead of sample - C352_FLG_MULAW = 0x0008, // sample is mulaw instead of linear 8-bit PCM - C352_FLG_FILTER = 0x0004, // don't apply filter - C352_FLG_REVLOOP = 0x0003, // loop backwards - C352_FLG_LOOP = 0x0002, // loop forward - C352_FLG_REVERSE = 0x0001, // play sample backwards + C352_FLG_BUSY = 0x8000, // channel is busy + C352_FLG_KEYON = 0x4000, // Keyon + C352_FLG_KEYOFF = 0x2000, // Keyoff + C352_FLG_LOOPTRG = 0x1000, // Loop Trigger + C352_FLG_LOOPHIST = 0x0800, // Loop History + C352_FLG_FM = 0x0400, // Frequency Modulation + C352_FLG_PHASERL = 0x0200, // Rear Left invert phase 180 degrees + C352_FLG_PHASEFL = 0x0100, // Front Left invert phase 180 degrees + C352_FLG_PHASEFR = 0x0080, // invert phase 180 degrees (e.g. flip sign of sample) + C352_FLG_LDIR = 0x0040, // loop direction + C352_FLG_LINK = 0x0020, // "long-format" sample (can't loop, not sure what else it means) + C352_FLG_NOISE = 0x0010, // play noise instead of sample + C352_FLG_MULAW = 0x0008, // sample is mulaw instead of linear 8-bit PCM + C352_FLG_FILTER = 0x0004, // don't apply filter + C352_FLG_REVLOOP = 0x0003, // loop backwards + C352_FLG_LOOP = 0x0002, // loop forward + C352_FLG_REVERSE = 0x0001 // play sample backwards }; -typedef struct +typedef struct { + + UINT32 pos; + UINT32 counter; + + INT16 sample; + INT16 last_sample; + + UINT16 vol_f; + UINT16 vol_r; + UINT16 freq; + UINT16 flags; + + UINT16 wave_bank; + UINT16 wave_start; + UINT16 wave_end; + UINT16 wave_loop; + + int mute; + +} C352_Voice; + +typedef struct { + + UINT32 rate; + UINT8 muteRear; + + C352_Voice v[C352_VOICES]; + + UINT16 control1; // unknown purpose for both + UINT16 control2; + + UINT8* wave; + UINT32 wavesize; + UINT32 wave_mask; + + UINT16 random; + + INT16 mulaw[256]; + +} C352; + +void C352_generate_mulaw(C352 *c) { - UINT8 vol_l; - UINT8 vol_r; - UINT8 vol_l2; - UINT8 vol_r2; - UINT8 bank; - UINT8 Muted; - - INT16 noise; - INT16 noisebuf; - UINT16 noisecnt; - UINT16 pitch; - UINT16 start_addr; - UINT16 end_addr; - UINT16 repeat_addr; - UINT32 flag; + int i; + double x_max = 32752.0; + double y_max = 127.0; + double u = 10.0; - UINT16 start; - UINT16 repeat; - UINT32 current_addr; - UINT32 pos; -} c352_ch_t; + // generate mulaw table for mulaw format samples + for (i = 0; i < 256; i++) + { + double y = (double) (i & 0x7f); + double x = (exp (y / y_max * log (1.0 + u)) - 1.0) * x_max / u; -typedef struct _c352_state c352_state; -struct _c352_state -{ - //sound_stream *stream; - c352_ch_t c352_ch[32]; - unsigned char *c352_rom_samples; - UINT32 c352_rom_length; - int sample_rate_base; - - /*long channel_l[2048*2]; - long channel_r[2048*2]; - long channel_l2[2048*2]; - long channel_r2[2048*2];*/ - - short mulaw_table[256]; - unsigned int mseq_reg; -}; - -/*INLINE c352_state *get_safe_token(running_device *device) -{ - assert(device != NULL); - assert(device->type() == C352); - return (c352_state *)downcast(device)->token(); -}*/ - -// noise generator -static int get_mseq_bit(c352_state *info) -{ - unsigned int mask = (1 << (7 - 1)); - unsigned int reg = info->mseq_reg; - unsigned int bit = reg & (1 << (17 - 1)); - - if (bit) - { - reg = ((reg ^ mask) << 1) | 1; - } - else - { - reg = reg << 1; - } - - info->mseq_reg = reg; - - return (reg & 1); + if (i & 0x80) + x = -x; + c->mulaw[i] = (short)x; + } } -/* ctr: this function gets the next sample for the lerp. If the sample position pointer is adjacent to the sample end pointer, - then lerping the sample with the "nextsample" variable causes clicks. To prevent this, simply check if the next sample is - the final sample and if so go to the beginning sample. - - If bidi samples causes problems, add a case for that as well. (they might) - */ -char getnextsample(c352_state *chip, c352_ch_t* c352ch, UINT32 pos) +void C352_fetch_sample(C352 *c, int i) { - INT32 flag = c352ch->flag; - UINT32 bank = c352ch->bank << 16; - - if( flag & C352_FLG_REVERSE) - return (char) chip->c352_rom_samples[pos+1]; // todo: Bidi samples + C352_Voice *v = &c->v[i]; + v->last_sample = v->sample; + + if(v->flags & C352_FLG_NOISE) + { + c->random = (c->random>>1) ^ (-(c->random&1)) & 0xfff6; + v->sample = (c->random&4) ? 0xc000 : 0x3fff; + + v->last_sample = v->sample; // No interpolation for noise samples + } + else + { + INT8 s; + UINT16 pos; - pos++; - if ( - (((pos&0xFFFF) > c352ch->end_addr) && ((pos&0xFFFF) < c352ch->start) && (c352ch->start > c352ch->end_addr) ) || - (((pos&0xFFFF) > c352ch->end_addr) && ((pos&0xFFFF) > c352ch->start) && (c352ch->start < c352ch->end_addr) ) || - ((pos > (bank|0xFFFF)) && (c352ch->end_addr == 0xFFFF)) - ) - { - if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) ) - pos = ((c352ch->start_addr & 0xFF)<<16) + c352ch->repeat_addr; - else if (flag & C352_FLG_LOOP) - pos = (pos & 0xFF0000) + c352ch->repeat; - else - { - // key off at this point, just return the previous value - return (char) chip->c352_rom_samples[pos-1]; - } - } - return (char) chip->c352_rom_samples[pos]; + s = (INT8)c->wave[v->pos&0xffffff]; + + if(v->flags & C352_FLG_MULAW) + v->sample = c->mulaw[(uint8_t)s]; + else + v->sample = s<<8; + + pos = v->pos&0xffff; + + if((v->flags & C352_FLG_LOOP) && v->flags & C352_FLG_REVERSE) + { + // backwards>forwards + if((v->flags & C352_FLG_LDIR) && pos == v->wave_loop) + v->flags &= ~C352_FLG_LDIR; + // forwards>backwards + else if(!(v->flags & C352_FLG_LDIR) && pos == v->wave_end) + v->flags |= C352_FLG_LDIR; + + v->pos += (v->flags&C352_FLG_LDIR) ? -1 : 1; + } + else if(pos == v->wave_end) + { + if((v->flags & C352_FLG_LINK) && (v->flags & C352_FLG_LOOP)) + { + v->pos = (v->wave_start<<16) | v->wave_loop; + v->flags |= C352_FLG_LOOPHIST; + } + else if(v->flags & C352_FLG_LOOP) + { + v->pos = (v->pos&0xff0000) | v->wave_loop; + v->flags |= C352_FLG_LOOPHIST; + } + else + { + v->flags |= C352_FLG_KEYOFF; + v->flags &= ~C352_FLG_BUSY; + v->sample=0; + v->last_sample=0; + } + } + else + { + v->pos += (v->flags&C352_FLG_REVERSE) ? -1 : 1; + } + } } -static void c352_mix_one_channel(c352_state *info, unsigned long ch, stream_sample_t **outputs, long sample_count) +UINT16 C352_update_voice(C352 *c, int i) { - c352_ch_t* c352ch; - int i; + C352_Voice *v = &c->v[i]; + INT32 temp; - signed short sample, nextsample; - signed short noisebuf; - UINT16 noisecnt; - INT32 delta, offset, cnt, flag; - UINT32 bank; - UINT32 pos; + if((v->flags & C352_FLG_BUSY) == 0) + return 0; - c352ch = &info->c352_ch[ch]; - delta = c352ch->pitch; + v->counter += v->freq; + + if(v->counter > 0x10000) + { + v->counter &= 0xffff; + C352_fetch_sample(c,i); + } + + temp = v->sample; + + if((v->flags & C352_FLG_FILTER) == 0) + temp = v->last_sample + (v->counter*(v->sample-v->last_sample)>>16); - pos = c352ch->current_addr; // sample pointer - offset = c352ch->pos; // 16.16 fixed-point offset into the sample - flag = c352ch->flag; - bank = c352ch->bank << 16; - - noisecnt = c352ch->noisecnt; - noisebuf = c352ch->noisebuf; - - for(i = 0 ; (i < sample_count) && (flag & C352_FLG_BUSY) ; i++) - { - offset += delta; - cnt = (offset>>16)&0x7fff; - if (cnt) // if there is a whole sample part, chop it off now that it's been applied - { - offset &= 0xffff; - } - - if (pos >= info->c352_rom_length) // pretty sure this should be >= instead of > -Valley Bell - { - c352ch->flag &= ~C352_FLG_BUSY; - //return; - break; // ensure that it saves the variables - } - - sample = (char)info->c352_rom_samples[pos]; - //nextsample = (char)info->c352_rom_samples[pos+cnt]; - nextsample = getnextsample(info, c352ch, pos); - - // sample is muLaw, not 8-bit linear (Fighting Layer uses this extensively) - if (flag & C352_FLG_MULAW) - { - sample = info->mulaw_table[(unsigned char)sample]; - nextsample = info->mulaw_table[(unsigned char)nextsample]; - } - else - { - sample <<= 8; - nextsample <<= 8; - } - - // play noise instead of sample data - if (flag & C352_FLG_NOISE) - { - int noise_level = 0x8000; - sample = c352ch->noise = (c352ch->noise << 1) | get_mseq_bit(info); - sample = (sample & (noise_level - 1)) - (noise_level >> 1); - if (sample > 0x7f) - { - sample = 0x7f; - } - else if (sample < 0) - { - sample = 0xff; - } - sample = info->mulaw_table[(unsigned char)sample]; - - if ( (pos+cnt) == pos ) - { - noisebuf += sample; - noisecnt++; - //sample = noisebuf / noisecnt; - if (noisecnt) // avoid Divide By Zero crash -Valley Bell - sample = noisebuf / noisecnt; - else - sample = info->mulaw_table[0x7f]; - } - else - { - if ( noisecnt ) - { - sample = noisebuf / noisecnt; - } - else - { - sample = info->mulaw_table[0x7f]; // Nearest sound(s) is here. - } - noisebuf = 0; - noisecnt = ( flag & C352_FLG_FILTER ) ? 0 : 1; - } - } - - // apply linear interpolation - if ( (flag & (C352_FLG_FILTER | C352_FLG_NOISE)) == 0 ) - { - sample = (short)(sample + ((nextsample-sample) * (((double)(0x0000ffff&offset) )/0x10000))); - } - - if ( flag & C352_FLG_PHASEFL ) - { - //info->channel_l[i] += ((-sample * c352ch->vol_l)>>8); - outputs[0][i] += ((-sample * c352ch->vol_l)>>8); - } - else - { - //info->channel_l[i] += ((sample * c352ch->vol_l)>>8); - outputs[0][i] += ((sample * c352ch->vol_l)>>8); - } - - if ( flag & C352_FLG_PHASEFR ) - { - //info->channel_r[i] += ((-sample * c352ch->vol_r)>>8); - outputs[1][i] += ((-sample * c352ch->vol_r)>>8); - } - else - { - //info->channel_r[i] += ((sample * c352ch->vol_r)>>8); - outputs[1][i] += ((sample * c352ch->vol_r)>>8); - } - - if ( flag & C352_FLG_PHASERL ) - { - //info->channel_l2[i] += ((-sample * c352ch->vol_l2)>>8); - outputs[0][i] += ((-sample * c352ch->vol_l2)>>8); - } - else - { - //info->channel_l2[i] += ((sample * c352ch->vol_l2)>>8); - outputs[0][i] += ((sample * c352ch->vol_l2)>>8); - } - //info->channel_r2[i] += ((sample * c352ch->vol_r2)>>8); - outputs[1][i] += ((sample * c352ch->vol_r2)>>8); - - if ( (flag & C352_FLG_REVERSE) && (flag & C352_FLG_LOOP) ) - { - if ( !(flag & C352_FLG_LDIR) ) - { - pos += cnt; - if ( - (((pos&0xFFFF) > c352ch->end_addr) && ((pos&0xFFFF) < c352ch->start) && (c352ch->start > c352ch->end_addr) ) || - (((pos&0xFFFF) > c352ch->end_addr) && ((pos&0xFFFF) > c352ch->start) && (c352ch->start < c352ch->end_addr) ) || - ((pos > (bank|0xFFFF)) && (c352ch->end_addr == 0xFFFF)) - ) - { - c352ch->flag |= C352_FLG_LDIR; - c352ch->flag |= C352_FLG_LOOPHIST; - } - } - else - { - pos -= cnt; - if ( - (((pos&0xFFFF) < c352ch->repeat) && ((pos&0xFFFF) < c352ch->end_addr) && (c352ch->end_addr > c352ch->start) ) || - (((pos&0xFFFF) < c352ch->repeat) && ((pos&0xFFFF) > c352ch->end_addr) && (c352ch->end_addr < c352ch->start) ) || - ((pos < bank) && (c352ch->repeat == 0x0000)) - ) - { - c352ch->flag &= ~C352_FLG_LDIR; - c352ch->flag |= C352_FLG_LOOPHIST; - } - } - } - else if ( flag & C352_FLG_REVERSE ) - { - pos -= cnt; - if ( - (((pos&0xFFFF) < c352ch->end_addr) && ((pos&0xFFFF) < c352ch->start) && (c352ch->start > c352ch->end_addr) ) || - (((pos&0xFFFF) < c352ch->end_addr) && ((pos&0xFFFF) > c352ch->start) && (c352ch->start < c352ch->end_addr) ) || - ((pos < bank) && (c352ch->end_addr == 0x0000)) - ) - { - if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) ) - { - c352ch->bank = c352ch->start_addr & 0xFF; - c352ch->start_addr = c352ch->repeat_addr; - c352ch->start = c352ch->start_addr; - c352ch->repeat = c352ch->repeat_addr; - pos = (c352ch->bank<<16) + c352ch->start_addr; - c352ch->flag |= C352_FLG_LOOPHIST; - } - else if (flag & C352_FLG_LOOP) - { - pos = (pos & 0xFF0000) + c352ch->repeat; - c352ch->flag |= C352_FLG_LOOPHIST; - } - else - { - c352ch->flag |= C352_FLG_KEYOFF; - c352ch->flag &= ~C352_FLG_BUSY; - //return; - break; - } - } - } else { - pos += cnt; - if ( - (((pos&0xFFFF) > c352ch->end_addr) && ((pos&0xFFFF) < c352ch->start) && (c352ch->start > c352ch->end_addr) ) || - (((pos&0xFFFF) > c352ch->end_addr) && ((pos&0xFFFF) > c352ch->start) && (c352ch->start < c352ch->end_addr) ) || - ((pos > (bank|0xFFFF)) && (c352ch->end_addr == 0xFFFF)) - ) - { - if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) ) - { - c352ch->bank = c352ch->start_addr & 0xFF; - c352ch->start_addr = c352ch->repeat_addr; - c352ch->start = c352ch->start_addr; - c352ch->repeat = c352ch->repeat_addr; - pos = (c352ch->bank<<16) + c352ch->start_addr; - c352ch->flag |= C352_FLG_LOOPHIST; - } - else if (flag & C352_FLG_LOOP) - { - pos = (pos & 0xFF0000) + c352ch->repeat; - c352ch->flag |= C352_FLG_LOOPHIST; - } - else - { - c352ch->flag |= C352_FLG_KEYOFF; - c352ch->flag &= ~C352_FLG_BUSY; - //return; - break; - } - } - } - } - - c352ch->noisecnt = noisecnt; - c352ch->noisebuf = noisebuf; - c352ch->pos = offset; - c352ch->current_addr = pos; + return temp; } - -//static STREAM_UPDATE( c352_update ) -void c352_update(void *param, stream_sample_t **outputs, int samples) +void c352_update(void *_info, stream_sample_t **outputs, int samples) { - c352_state *info = (c352_state *)param; - int j; - /*stream_sample_t *bufferl = outputs[0]; - stream_sample_t *bufferr = outputs[1]; - stream_sample_t *bufferl2 = outputs[2]; - stream_sample_t *bufferr2 = outputs[3]; - - for(i = 0 ; i < samples ; i++) - { - info->channel_l[i] = info->channel_r[i] = info->channel_l2[i] = info->channel_r2[i] = 0; - }*/ - memset(outputs[0], 0x00, samples * sizeof(stream_sample_t)); - memset(outputs[1], 0x00, samples * sizeof(stream_sample_t)); - - for (j = 0 ; j < 32 ; j++) - { - //c352_mix_one_channel(info, j, samples); - if ((info->c352_ch[j].flag & C352_FLG_BUSY) && ! info->c352_ch[j].Muted) - c352_mix_one_channel(info, j, outputs, samples); - } - - /*for(i = 0 ; i < samples ; i++) - { - *bufferl++ = (short) (info->channel_l[i] >>3); - *bufferr++ = (short) (info->channel_r[i] >>3); - *bufferl2++ = (short) (info->channel_l2[i] >>3); - *bufferr2++ = (short) (info->channel_r2[i] >>3); - }*/ + C352 *c = (C352 *) _info; + int i, j; + INT16 s; + memset(outputs[0], 0x00, samples * sizeof(stream_sample_t)); + memset(outputs[1], 0x00, samples * sizeof(stream_sample_t)); + + for(i=0;iv[j].mute) + { + // Left + outputs[0][i] += (c->v[j].flags & C352_FLG_PHASEFL) ? (-s * (c->v[j].vol_f>>8) )>>8 + : ( s * (c->v[j].vol_f>>8) )>>8; + if (!c->muteRear) + outputs[0][i] += (c->v[j].flags & C352_FLG_PHASERL) ? (-s * (c->v[j].vol_r>>8) )>>8 + : ( s * (c->v[j].vol_r>>8) )>>8; + + // Right + outputs[1][i] += (c->v[j].flags & C352_FLG_PHASEFR) ? (-s * (c->v[j].vol_f&0xff))>>8 + : ( s * (c->v[j].vol_f&0xff))>>8; + if (!c->muteRear) + outputs[1][i] += ( s * (c->v[j].vol_r&0xff))>>8; + } + } + + } } -static unsigned short c352_read_reg16(c352_state *info, unsigned long address) -{ - unsigned long chan; - unsigned short val; - - //stream_update(info->stream); - - chan = (address >> 4) & 0xfff; - if (chan > 31) - { - val = 0; - } - else - { - if ((address & 0xf) == 6) - { - val = info->c352_ch[chan].flag; - } - else - { - val = 0; - } - } - return val; -} - -static void c352_write_reg16(c352_state *info, unsigned long address, unsigned short val) -{ - unsigned long chan; - int i; - - //stream_update(info->stream); - - chan = (address >> 4) & 0xfff; - - if ( address >= 0x400 ) - { - switch(address) - { - case 0x404: // execute key-ons/offs - for ( i = 0 ; i <= 31 ; i++ ) - { - if ( info->c352_ch[i].flag & C352_FLG_KEYON ) - { - if (info->c352_ch[i].start_addr != info->c352_ch[i].end_addr) - { - info->c352_ch[i].current_addr = (info->c352_ch[i].bank << 16) + info->c352_ch[i].start_addr; - info->c352_ch[i].start = info->c352_ch[i].start_addr; - info->c352_ch[i].repeat = info->c352_ch[i].repeat_addr; - info->c352_ch[i].noisebuf = 0; - info->c352_ch[i].noisecnt = 0; - info->c352_ch[i].flag &= ~(C352_FLG_KEYON | C352_FLG_LOOPHIST); - info->c352_ch[i].flag |= C352_FLG_BUSY; - } - } - else if ( info->c352_ch[i].flag & C352_FLG_KEYOFF ) - { - info->c352_ch[i].flag &= ~C352_FLG_BUSY; - info->c352_ch[i].flag &= ~(C352_FLG_KEYOFF); - } - } - break; - default: - break; - } - return; - } - - if (chan > 31) - { - LOG(("C352 CTRL %08lx %04x\n", address, val)); - return; - } - switch(address & 0xf) - { - case 0x0: - // volumes (output 1) - LOG(("CH %02ld LVOL %02x RVOL %02x\n", chan, val & 0xff, val >> 8)); - info->c352_ch[chan].vol_l = val & 0xff; - info->c352_ch[chan].vol_r = val >> 8; - break; - - case 0x2: - // volumes (output 2) - LOG(("CH %02ld RLVOL %02x RRVOL %02x\n", chan, val & 0xff, val >> 8)); - info->c352_ch[chan].vol_l2 = val & 0xff; - info->c352_ch[chan].vol_r2 = val >> 8; - break; - - case 0x4: - // pitch - LOG(("CH %02ld PITCH %04x\n", chan, val)); - info->c352_ch[chan].pitch = val; - break; - - case 0x6: - // flags - LOG(("CH %02ld FLAG %02x\n", chan, val)); - info->c352_ch[chan].flag = val; - break; - - case 0x8: - // bank (bits 16-31 of address); - info->c352_ch[chan].bank = val & 0xff; - LOG(("CH %02ld BANK %02x", chan, info->c352_ch[chan].bank)); - break; - - case 0xa: - // start address - LOG(("CH %02ld SADDR %04x\n", chan, val)); - info->c352_ch[chan].start_addr = val; - break; - - case 0xc: - // end address - LOG(("CH %02ld EADDR %04x\n", chan, val)); - info->c352_ch[chan].end_addr = val; - break; - - case 0xe: - // loop address - LOG(("CH %02ld LADDR %04x\n", chan, val)); - info->c352_ch[chan].repeat_addr = val; - break; - - default: - LOG(("CH %02ld UNKN %01lx %04x", chan, address & 0xf, val)); - break; - } -} - -//static DEVICE_START( c352 ) int device_start_c352(void **_info, int clock, int clkdiv) { - //c352_state *info = get_safe_token(device); - c352_state *info; - int i; - double x_max = 32752.0; - double y_max = 127.0; - double u = 10.0; + C352 *c = calloc(1, sizeof(C352)); + *_info = (void *) c; - info = (c352_state *) calloc(1, sizeof(c352_state)); - *_info = (void *) info; + c->wave = NULL; + c->wavesize = 0x00; - //info->c352_rom_samples = *device->region(); - //info->c352_rom_length = device->region()->bytes(); - info->c352_rom_samples = NULL; - info->c352_rom_length = 0x00; + if(!clkdiv) + clkdiv = 288; - if (! clkdiv) - clkdiv = 288; - //info->sample_rate_base = device->clock() / 288; - info->sample_rate_base = clock / clkdiv; + c->rate = (clock&0x7FFFFFFF)/clkdiv; + c->muteRear = (clock&0x80000000)>>31; - //info->stream = stream_create(device, 0, 4, info->sample_rate_base, info, c352_update); + memset(c->v,0,sizeof(C352_Voice)*C352_VOICES); - // generate mulaw table for mulaw format samples - for (i = 0; i < 256; i++) - { - double y = (double) (i & 0x7f); - double x = (exp (y / y_max * log (1.0 + u)) - 1.0) * x_max / u; + c->control1 = 0; + c->control2 = 0; + c->random = 0x1234; - if (i & 0x80) - { - x = -x; - } - info->mulaw_table[i] = (short)x; - } - - // register save state info - for (i = 0; i < 32; i++) - { - /*state_save_register_device_item(device, i, info->c352_ch[i].vol_l); - state_save_register_device_item(device, i, info->c352_ch[i].vol_r); - state_save_register_device_item(device, i, info->c352_ch[i].vol_l2); - state_save_register_device_item(device, i, info->c352_ch[i].vol_r2); - state_save_register_device_item(device, i, info->c352_ch[i].bank); - state_save_register_device_item(device, i, info->c352_ch[i].noise); - state_save_register_device_item(device, i, info->c352_ch[i].noisebuf); - state_save_register_device_item(device, i, info->c352_ch[i].noisecnt); - state_save_register_device_item(device, i, info->c352_ch[i].pitch); - state_save_register_device_item(device, i, info->c352_ch[i].start_addr); - state_save_register_device_item(device, i, info->c352_ch[i].end_addr); - state_save_register_device_item(device, i, info->c352_ch[i].repeat_addr); - state_save_register_device_item(device, i, info->c352_ch[i].flag); - state_save_register_device_item(device, i, info->c352_ch[i].start); - state_save_register_device_item(device, i, info->c352_ch[i].repeat); - state_save_register_device_item(device, i, info->c352_ch[i].current_addr); - state_save_register_device_item(device, i, info->c352_ch[i].pos);*/ - info->c352_ch[i].Muted = 0x00; - } - - return info->sample_rate_base; + C352_generate_mulaw(c); + + return c->rate; } void device_stop_c352(void *_info) { - c352_state *info = (c352_state *)_info; - - free(info->c352_rom_samples); - info->c352_rom_samples = NULL; + C352 *c = (C352 *)_info; + + free(c->wave); + c->wave = NULL; - free(info); - - return; + free(c); + + return; } void device_reset_c352(void *_info) { - c352_state *info = (c352_state *)_info; - - // clear all channels states - memset(info->c352_ch, 0, sizeof(c352_ch_t)*32); - - // init noise generator - info->mseq_reg = 0x12345678; - - return; + C352 *c = (C352 *) _info; + + memset(c->v,0,sizeof(C352_Voice)*C352_VOICES); + + return; } +static const UINT16 C352RegMap[8] = { + offsetof(C352_Voice,vol_f) / sizeof(UINT16), + offsetof(C352_Voice,vol_r) / sizeof(UINT16), + offsetof(C352_Voice,freq) / sizeof(UINT16), + offsetof(C352_Voice,flags) / sizeof(UINT16), + offsetof(C352_Voice,wave_bank) / sizeof(UINT16), + offsetof(C352_Voice,wave_start) / sizeof(UINT16), + offsetof(C352_Voice,wave_end) / sizeof(UINT16), + offsetof(C352_Voice,wave_loop) / sizeof(UINT16), +}; -//READ16_DEVICE_HANDLER( c352_r ) UINT16 c352_r(void *_info, offs_t offset) { - c352_state *info = (c352_state *)_info; - return(c352_read_reg16(info, offset*2)); - //return(c352_read_reg16(get_safe_token(device), offset*2)); + C352 *c = (C352 *) _info; + + if(offset < 0x100) + return *((UINT16*)&c->v[offset/8]+C352RegMap[offset%8]); + else + return 0; } -//WRITE16_DEVICE_HANDLER( c352_w ) void c352_w(void *_info, offs_t offset, UINT16 data) { - c352_state *info = (c352_state *)_info; - /*if (mem_mask == 0xffff) - { - c352_write_reg16(get_safe_token(device), offset*2, data); - } - else - { - logerror("C352: byte-wide write unsupported at this time!\n"); - }*/ - c352_write_reg16(info, offset*2, data); + C352 *c = (C352 *) _info; + + int i; + + if(offset < 0x100) // Channel registers, see map above. + *((UINT16*)&c->v[offset/8]+C352RegMap[offset%8]) = data; + else if(offset == 0x200) // Unknown purpose. + c->control1 = data; + else if(offset == 0x201) + c->control2 = data; + else if(offset == 0x202) // execute keyons/keyoffs + { + for(i=0;iv[i].flags & C352_FLG_KEYON)) + { + c->v[i].pos = (c->v[i].wave_bank<<16) | c->v[i].wave_start; + + c->v[i].sample = 0; + c->v[i].last_sample = 0; + c->v[i].counter = 0x10000; // Immediate update + + c->v[i].flags |= C352_FLG_BUSY; + c->v[i].flags &= ~(C352_FLG_KEYON|C352_FLG_LOOPHIST); + } + else if(c->v[i].flags & C352_FLG_KEYOFF) + { + c->v[i].sample=0; + c->v[i].last_sample=0; + c->v[i].flags &= ~(C352_FLG_BUSY|C352_FLG_KEYOFF); + } + } + } } void c352_write_rom(void *_info, offs_t ROMSize, offs_t DataStart, offs_t DataLength, - const UINT8* ROMData) + const UINT8* ROMData) { - c352_state *info = (c352_state *)_info; - - if (info->c352_rom_length != ROMSize) - { - info->c352_rom_samples = (UINT8*)realloc(info->c352_rom_samples, ROMSize); - info->c352_rom_length = ROMSize; - memset(info->c352_rom_samples, 0xFF, ROMSize); - } - if (DataStart > ROMSize) - return; - if (DataStart + DataLength > ROMSize) - DataLength = ROMSize - DataStart; - - memcpy(info->c352_rom_samples + DataStart, ROMData, DataLength); - - return; + C352 *c = (C352 *) _info; + + if (c->wavesize != ROMSize) + { + c->wave = (UINT8*)realloc(c->wave, ROMSize); + c->wavesize = ROMSize; + memset(c->wave, 0xFF, ROMSize); + } + if (DataStart > ROMSize) + return; + if (DataStart + DataLength > ROMSize) + DataLength = ROMSize - DataStart; + + memcpy(c->wave + DataStart, ROMData, DataLength); + + return; } - void c352_set_mute_mask(void *_info, UINT32 MuteMask) { - c352_state *info = (c352_state *)_info; - UINT8 CurChn; - - for (CurChn = 0; CurChn < 32; CurChn ++) - info->c352_ch[CurChn].Muted = (MuteMask >> CurChn) & 0x01; - - return; + C352 *c = (C352 *) _info; + UINT8 CurChn; + + for (CurChn = 0; CurChn < 32; CurChn ++) + c->v[CurChn].mute = (MuteMask >> CurChn) & 0x01; + + return; } - - - - - -/************************************************************************** - * Generic get_info - **************************************************************************/ - -/*DEVICE_GET_INFO( c352 ) -{ - switch (state) - { - // --- the following bits of info are returned as 64-bit signed integers --- - case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(c352_state); break; - - // --- the following bits of info are returned as pointers to data or functions --- - case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( c352 ); break; - case DEVINFO_FCT_STOP: // nothing // break; - case DEVINFO_FCT_RESET: // nothing // break; - - // --- the following bits of info are returned as NULL-terminated strings --- - case DEVINFO_STR_NAME: strcpy(info->s, "C352"); break; - case DEVINFO_STR_FAMILY: strcpy(info->s, "Namco PCM"); break; - case DEVINFO_STR_VERSION: strcpy(info->s, "1.1"); break; - case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; - case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; - } -} - - -DEFINE_LEGACY_SOUND_DEVICE(C352, c352);*/ diff --git a/Frameworks/GME/vgmplay/chips/c6280.c b/Frameworks/GME/vgmplay/chips/c6280.c index 53ca3e15f..3fa906341 100644 --- a/Frameworks/GME/vgmplay/chips/c6280.c +++ b/Frameworks/GME/vgmplay/chips/c6280.c @@ -55,7 +55,7 @@ //#include "emu.h" #include // for rand() -#include // for memset() +#include // for memset() #include // for pow() #include "mamedef.h" #include "c6280.h" @@ -397,6 +397,8 @@ UINT8 c6280m_r(void* chip, offs_t offset) //c6280_t *info = get_safe_token(device); c6280_t *info = (c6280_t *)chip; //return h6280io_get_buffer(info->cpudevice); + if (offset == 0) + return info->select; return 0; } diff --git a/Frameworks/GME/vgmplay/chips/c6280intf.c b/Frameworks/GME/vgmplay/chips/c6280intf.c index ed0db9dc2..f5c914c28 100644 --- a/Frameworks/GME/vgmplay/chips/c6280intf.c +++ b/Frameworks/GME/vgmplay/chips/c6280intf.c @@ -10,7 +10,9 @@ #endif #define EC_OOTAKE 0x00 +#ifndef NULL #define NULL ((void *)0) +#endif typedef struct _c6280_state { diff --git a/Frameworks/GME/vgmplay/chips/dac_control.c b/Frameworks/GME/vgmplay/chips/dac_control.c index 47fb55682..778e70501 100644 --- a/Frameworks/GME/vgmplay/chips/dac_control.c +++ b/Frameworks/GME/vgmplay/chips/dac_control.c @@ -5,7 +5,7 @@ // (Custom Driver to handle PCM Streams of YM2612 DAC and PWM.) // // Written on 3 February 2011 by Valley Bell -// Last Update: 13 April 2014 +// Last Update: 04 October 2015 // // Only for usage in non-commercial, VGM file related software. @@ -21,8 +21,7 @@ #include "mamedef.h" #include "dac_control.h" -//#include "../ChipMapper.h" -void chip_reg_write(void *param, UINT8 ChipType, UINT8 ChipID, UINT8 Port, UINT8 Offset, UINT8 Data); +#include "../ChipMapper.h" #define DAC_SMPL_RATE chip->SampleRate @@ -58,7 +57,9 @@ typedef struct _dac_control UINT32 SampleRate; } dac_control; +#ifndef NULL #define NULL (void*)0 +#endif INLINE void daccontrol_SendCommand(dac_control *chip) { @@ -176,10 +177,31 @@ INLINE void daccontrol_SendCommand(dac_control *chip) Command = (chip->DstCommand & 0x00FF) >> 0; Data = ChipData[0x00]; - if (Port != 0xFF) // Send Channel Select + if (Port == 0xFF) + { + chip_reg_write(chip->param, chip->DstChipType, chip->DstChipID, 0x00, Command & 0x0F, Data); + } + else + { + UINT8 prevChn; + + prevChn = Port; // by default don't restore channel + // get current channel for supported chips + if (chip->DstChipType == 0x05) + ; // TODO + else if (chip->DstChipType == 0x05) + ; // TODO + else if (chip->DstChipType == 0x1B) + prevChn = chip_reg_read(chip->param, 0x1B, chip->DstChipID, 0x00, 0x00); + + // Send Channel Select chip_reg_write(chip->param, chip->DstChipType, chip->DstChipID, 0x00, Command >> 4, Port); - // Send Data - chip_reg_write(chip->param, chip->DstChipType, chip->DstChipID, 0x00, Command & 0x0F, Data); + // Send Data + chip_reg_write(chip->param, chip->DstChipType, chip->DstChipID, 0x00, Command & 0x0F, Data); + // restore old channel + if (prevChn != Port) + chip_reg_write(chip->param, chip->DstChipType, chip->DstChipID, 0x00, Command >> 4, prevChn); + } break; // Generic support: 8-bit Register, 16-bit Data case 0x1F: // QSound diff --git a/Frameworks/GME/vgmplay/chips/emu2413.c b/Frameworks/GME/vgmplay/chips/emu2413.c index b368f192a..e41753fd9 100644 --- a/Frameworks/GME/vgmplay/chips/emu2413.c +++ b/Frameworks/GME/vgmplay/chips/emu2413.c @@ -1870,8 +1870,8 @@ calc_stereo (OPLL * opll, e_int32 out[2], e_int32 ch) { /* Maxim: added stereo control (multiply each side by a float in opll->pan[ch][side]) */ e_int32 l=0,r=0; -/* e_int32 b[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ -/* e_int32 r[4] = { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ +/* e_int32 b[4] = { 0, 0, 0, 0 };*/ /* Ignore, Right, Left, Center */ +/* e_int32 r[4] = { 0, 0, 0, 0 };*/ /* Ignore, Right, Left, Center */ e_int32 i; e_int32 channel; diff --git a/Frameworks/GME/vgmplay/chips/emuconfig.h b/Frameworks/GME/vgmplay/chips/emuconfig.h new file mode 100644 index 000000000..4028a6f58 --- /dev/null +++ b/Frameworks/GME/vgmplay/chips/emuconfig.h @@ -0,0 +1,101 @@ +///////////////////////////////////////////////////////////////////////////// +// +// Configuration for emulation libraries +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __EMUCONFIG_H__ +#define __EMUCONFIG_H__ + +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////// +// +// One of these has to be defined when compiling the library. +// Shouldn't be necessary for using it. +// +#if defined(EMU_COMPILE) && !defined(EMU_BIG_ENDIAN) && !defined(EMU_LITTLE_ENDIAN) +#error "Hi I forgot to set EMU_x_ENDIAN" +#endif +#if defined(EMU_COMPILE) && defined(EMU_BIG_ENDIAN) && defined(EMU_LITTLE_ENDIAN) +#error "Both byte orders should not be defined" +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// WIN32 native project definitions +// +///////////////////////////////////////////////////////////////////////////// +#if defined(WIN32) && !defined(__GNUC__) + +#define EMU_CALL __fastcall +#define EMU_CALL_ __cdecl +#define EMU_INLINE __inline + +#define uint8 unsigned char +#define uint16 unsigned short +#define uint32 unsigned int +#define uint64 unsigned __int64 +#define sint8 signed char +#define sint16 signed short +#define sint32 signed int +#define sint64 signed __int64 + +///////////////////////////////////////////////////////////////////////////// +// +// LINUX / other platform definitions +// +///////////////////////////////////////////////////////////////////////////// +#else + +//#if defined(__GNUC__) && defined(__i386__) +//#define EMU_CALL __attribute__((__regparm__(2))) +//#else +#define EMU_CALL +//#endif + +#define EMU_CALL_ +#define EMU_INLINE __inline + +#ifdef HAVE_STDINT_H +#include +#define uint8 uint8_t +#define uint16 uint16_t +#define uint32 uint32_t +#define uint64 uint64_t +#define sint8 int8_t +#define sint16 int16_t +#define sint32 int32_t +#define sint64 int64_t +#else +#define uint8 unsigned char +#define uint16 unsigned short +#define uint32 unsigned int +#define uint64 unsigned long long +#define sint8 signed char +#define sint16 signed short +#define sint32 signed int +#define sint64 signed long long +#endif + +#endif + +#ifdef EMU_BIG_ENDIAN +#define EMU_ENDIAN_XOR_L2H(x) (x) +#define EMU_ENDIAN_XOR_B2H(x) (0) +#else +#define EMU_ENDIAN_XOR_L2H(x) (0) +#define EMU_ENDIAN_XOR_B2H(x) (x) +#endif + +// deprecated +#define EMU_ENDIAN_XOR(x) EMU_ENDIAN_XOR_L2H(x) + +///////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/Frameworks/GME/vgmplay/chips/es5503.c b/Frameworks/GME/vgmplay/chips/es5503.c index 894ea7ef1..d5ffe6512 100644 --- a/Frameworks/GME/vgmplay/chips/es5503.c +++ b/Frameworks/GME/vgmplay/chips/es5503.c @@ -117,7 +117,7 @@ static void es5503_halt_osc(ES5503Chip *chip, int onum, int type, UINT32 *accumu ES5503Osc *pOsc = &chip->oscillators[onum]; ES5503Osc *pPartner = &chip->oscillators[onum^1]; int mode = (pOsc->control>>1) & 3; - int omode = (pPartner->control>>1) & 3; + //int omode = (pPartner->control>>1) & 3; // if 0 found in sample data or mode is not free-run, halt this oscillator if ((mode != MODE_FREE) || (type != 0)) @@ -143,7 +143,7 @@ static void es5503_halt_osc(ES5503Chip *chip, int onum, int type, UINT32 *accumu // if swap mode, start the partner // Note: The swap mode fix breaks Silpheed and other games. - if ((mode == MODE_SWAP) /*|| (omode == MODE_SWAP)*/) + if (/*(*/mode == MODE_SWAP/*)*/ /*|| (omode == MODE_SWAP)*/) { pPartner->control &= ~1; // clear the halt bit pPartner->accumulator = 0; // and make sure it starts from the top (does this also need phase preservation?) diff --git a/Frameworks/GME/vgmplay/chips/es5506.c b/Frameworks/GME/vgmplay/chips/es5506.c index c4d430af7..c7fdbdab4 100644 --- a/Frameworks/GME/vgmplay/chips/es5506.c +++ b/Frameworks/GME/vgmplay/chips/es5506.c @@ -617,6 +617,9 @@ reverse: while (samples--) { /* fetch two samples */ +#ifdef VGM_BIG_ENDIAN + #warning "ES5506 sound emulation not Endian-Safe!" +#endif INT32 val1 = base[accum >> 11]; INT32 val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; @@ -655,6 +658,9 @@ reverse: while (samples--) { /* fetch two samples */ +#ifdef VGM_BIG_ENDIAN + #warning "ES5506 sound emulation not Endian-Safe!" +#endif INT32 val1 = base[accum >> 11]; INT32 val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; @@ -723,6 +729,9 @@ reverse: while (samples--) { /* fetch two samples */ +#ifdef VGM_BIG_ENDIAN + #warning "ES5506 sound emulation not Endian-Safe!" +#endif INT32 val1 = (INT16)base[accum >> 11]; INT32 val2 = (INT16)base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; @@ -757,6 +766,9 @@ reverse: while (samples--) { /* fetch two samples */ +#ifdef VGM_BIG_ENDIAN + #warning "ES5506 sound emulation not Endian-Safe!" +#endif INT32 val1 = (INT16)base[accum >> 11]; INT32 val2 = (INT16)base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; @@ -852,7 +864,9 @@ static void generate_samples(es5506_state *chip, INT32 **outputs, int offset, in /* does this voice have it's IRQ bit raised? */ if (voice->control&CONTROL_IRQ) { +#ifdef _DEBUG logerror("es5506: IRQ raised on voice %d!!\n",v); +#endif /* only update voice vector if existing IRQ is acked by host */ if (chip->irqv&0x80) { @@ -925,7 +939,7 @@ static void es5506_start_common(es5506_state *chip, int clock, UINT8 sndtype) chip->sndtype = sndtype; /* only override the number of channels if the value is in the valid range 1 .. 6 */ max_chns = chip->sndtype ? 6 : 4; // 6 for ES5506, 4 for ES5505 - if (chip->channels < 1|| chip->channels > max_chns) + if (chip->channels < 1 || chip->channels > max_chns) chip->channels = 1; /* 1 channel by default, for backward compatibility */ /* debugging */ @@ -2141,7 +2155,9 @@ INLINE UINT16 es5505_reg_read_high(es5506_state *chip, es5506_voice *voice, offs if ((voice->control & CONTROL_STOPMASK) && chip->region_base[voice->control >> 14]) { voice->o1n1 = chip->region_base[voice->control >> 14][voice->exbank + (voice->accum >> 11)]; +#ifdef _DEBUG logerror("%02x %08x ==> %08x\n",voice->o1n1,voice->control >> 14,voice->exbank + (voice->accum >> 11)); +#endif } result = voice->o1n1; break; diff --git a/Frameworks/GME/vgmplay/chips/fm.c b/Frameworks/GME/vgmplay/chips/fm.c index 7b3131f0e..4b1b45217 100644 --- a/Frameworks/GME/vgmplay/chips/fm.c +++ b/Frameworks/GME/vgmplay/chips/fm.c @@ -2480,111 +2480,6 @@ typedef YM2610 YM2608; /* Algorithm and tables verified on real YM2608 and YM2610 */ - -#ifdef __clang__ -#define Init_ADPCMATable() -static const int jedi_table[49 * 16] = -{ - 2, 6, 10, 14, 18, 22, 26, 30, - -2, -6, -10, -14, -18, -22, -26, -30, - 2, 6, 10, 14, 19, 23, 27, 31, - -2, -6, -10, -14, -19, -23, -27, -31, - 2, 7, 11, 16, 21, 26, 30, 35, - -2, -7, -11, -16, -21, -26, -30, -35, - 2, 7, 13, 18, 23, 28, 34, 39, - -2, -7, -13, -18, -23, -28, -34, -39, - 2, 8, 14, 20, 25, 31, 37, 43, - -2, -8, -14, -20, -25, -31, -37, -43, - 3, 9, 15, 21, 28, 34, 40, 46, - -3, -9, -15, -21, -28, -34, -40, -46, - 3, 10, 17, 24, 31, 38, 45, 52, - -3, -10, -17, -24, -31, -38, -45, -52, - 3, 11, 19, 27, 34, 42, 50, 58, - -3, -11, -19, -27, -34, -42, -50, -58, - 4, 12, 21, 29, 38, 46, 55, 63, - -4, -12, -21, -29, -38, -46, -55, -63, - 4, 13, 23, 32, 41, 50, 60, 69, - -4, -13, -23, -32, -41, -50, -60, -69, - 5, 15, 25, 35, 46, 56, 66, 76, - -5, -15, -25, -35, -46, -56, -66, -76, - 5, 16, 28, 39, 50, 61, 73, 84, - -5, -16, -28, -39, -50, -61, -73, -84, - 6, 18, 31, 43, 56, 68, 81, 93, - -6, -18, -31, -43, -56, -68, -81, -93, - 6, 20, 34, 48, 61, 75, 89, 103, - -6, -20, -34, -48, -61, -75, -89, -103, - 7, 22, 37, 52, 67, 82, 97, 112, - -7, -22, -37, -52, -67, -82, -97, -112, - 8, 24, 41, 57, 74, 90, 107, 123, - -8, -24, -41, -57, -74, -90, -107, -123, - 9, 27, 45, 63, 82, 100, 118, 136, - -9, -27, -45, -63, -82, -100, -118, -136, - 10, 30, 50, 70, 90, 110, 130, 150, - -10, -30, -50, -70, -90, -110, -130, -150, - 11, 33, 55, 77, 99, 121, 143, 165, - -11, -33, -55, -77, -99, -121, -143, -165, - 12, 36, 60, 84, 109, 133, 157, 181, - -12, -36, -60, -84, -109, -133, -157, -181, - 13, 40, 66, 93, 120, 147, 173, 200, - -13, -40, -66, -93, -120, -147, -173, -200, - 14, 44, 73, 103, 132, 162, 191, 221, - -14, -44, -73, -103, -132, -162, -191, -221, - 16, 48, 81, 113, 146, 178, 211, 243, - -16, -48, -81, -113, -146, -178, -211, -243, - 17, 53, 89, 125, 160, 196, 232, 268, - -17, -53, -89, -125, -160, -196, -232, -268, - 19, 58, 98, 137, 176, 215, 255, 294, - -19, -58, -98, -137, -176, -215, -255, -294, - 21, 64, 108, 151, 194, 237, 281, 324, - -21, -64, -108, -151, -194, -237, -281, -324, - 23, 71, 118, 166, 213, 261, 308, 356, - -23, -71, -118, -166, -213, -261, -308, -356, - 26, 78, 130, 182, 235, 287, 339, 391, - -26, -78, -130, -182, -235, -287, -339, -391, - 28, 86, 143, 201, 258, 316, 373, 431, - -28, -86, -143, -201, -258, -316, -373, -431, - 31, 94, 158, 221, 284, 347, 411, 474, - -31, -94, -158, -221, -284, -347, -411, -474, - 34, 104, 174, 244, 313, 383, 453, 523, - -34, -104, -174, -244, -313, -383, -453, -523, - 38, 115, 191, 268, 345, 422, 498, 575, - -38, -115, -191, -268, -345, -422, -498, -575, - 42, 126, 210, 294, 379, 463, 547, 631, - -42, -126, -210, -294, -379, -463, -547, -631, - 46, 139, 231, 324, 417, 510, 602, 695, - -46, -139, -231, -324, -417, -510, -602, -695, - 51, 153, 255, 357, 459, 561, 663, 765, - -51, -153, -255, -357, -459, -561, -663, -765, - 56, 168, 280, 392, 505, 617, 729, 841, - -56, -168, -280, -392, -505, -617, -729, -841, - 61, 185, 308, 432, 555, 679, 802, 926, - -61, -185, -308, -432, -555, -679, -802, -926, - 68, 204, 340, 476, 612, 748, 884, 1020, - -68, -204, -340, -476, -612, -748, -884, -1020, - 74, 224, 373, 523, 672, 822, 971, 1121, - -74, -224, -373, -523, -672, -822, -971, -1121, - 82, 246, 411, 575, 740, 904, 1069, 1233, - -82, -246, -411, -575, -740, -904, -1069, -1233, - 90, 271, 452, 633, 814, 995, 1176, 1357, - -90, -271, -452, -633, -814, -995, -1176, -1357, - 99, 298, 497, 696, 895, 1094, 1293, 1492, - -99, -298, -497, -696, -895, -1094, -1293, -1492, - 109, 328, 547, 766, 985, 1204, 1423, 1642, - -109, -328, -547, -766, -985, -1204, -1423, -1642, - 120, 361, 601, 842, 1083, 1324, 1564, 1805, - -120, -361, -601, -842, -1083, -1324, -1564, -1805, - 132, 397, 662, 927, 1192, 1457, 1722, 1987, - -132, -397, -662, -927, -1192, -1457, -1722, -1987, - 145, 437, 728, 1020, 1311, 1603, 1894, 2186, - -145, -437, -728, -1020, -1311, -1603, -1894, -2186, - 160, 480, 801, 1121, 1442, 1762, 2083, 2403, - -160, -480, -801, -1121, -1442, -1762, -2083, -2403, - 176, 529, 881, 1234, 1587, 1940, 2292, 2645, - -176, -529, -881, -1234, -1587, -1940, -2292, -2645, - 194, 582, 970, 1358, 1746, 2134, 2522, 2910, - -194, -582, -970, -1358, -1746, -2134, -2522, -2910, -}; -#else /* usual ADPCM table (16 * 1.1^N) */ static const int steps[49] = { @@ -2597,29 +2492,27 @@ static const int steps[49] = 876, 963, 1060, 1166, 1282, 1411, 1552 }; -/* speedup purposes only */ -static int jedi_table[ 49*16 ]; - -/* clang with Xcode 7.2.1 mis-optimizes the !(nib&0x08) steps to zero when compiled with -Os */ -static void Init_ADPCMATable(void) -{ - int step, nib; - - for (step = 0; step < 49; step++) - { - /* loop over all nibbles and compute the difference */ - for (nib = 0; nib < 16; nib++) - { - int value = (2*(nib & 0x07) + 1) * steps[step] / 8; - jedi_table[step*16 + nib] = (nib&0x08) ? -value : value; - } - } -} -#endif - /* different from the usual ADPCM table */ static const int step_inc[8] = { -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 }; +/* speedup purposes only */ +static int jedi_table[ 49*16 ]; + + +static void Init_ADPCMATable(void) +{ + int step, nib; + + for (step = 0; step < 49; step++) + { + /* loop over all nibbles and compute the difference */ + for (nib = 0; nib < 16; nib++) + { + int value = (2*(nib & 0x07) + 1) * steps[step] / 8; + jedi_table[step*16 + nib] = (nib&0x08) ? -value : value; + } + } +} /* ADPCM A (Non control type) : calculate one channel output */ INLINE void ADPCMA_calc_chan( YM2610 *F2610, ADPCM_CH *ch ) @@ -4072,12 +3965,16 @@ void ym2610_update_one(void *chip, FMSAMPLE **buffer, int length) /* Check YM2610B warning message */ if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) ) { +#ifdef _DEBUG LOG(LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.param,0)); +#endif FM_KEY_IS(&F2610->CH[0].SLOT[3]) = 0; } if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) ) { +#ifdef _DEBUG LOG(LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.param,3)); +#endif FM_KEY_IS(&F2610->CH[3].SLOT[3]) = 0; } #endif @@ -4532,11 +4429,6 @@ void ym2610_reset_chip(void *chip) } else F2610->deltaT.memory_size = dev->machine->region(name)->bytes();*/ - F2610->pcmbuf = NULL; - F2610->pcm_size = 0x00; - F2610->deltaT.memory = NULL; - F2610->deltaT.memory_size = 0x00; - F2610->deltaT.memory_mask = 0x00; /* Reset Prescaler */ OPNSetPres( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */ diff --git a/Frameworks/GME/vgmplay/chips/fm2612.c b/Frameworks/GME/vgmplay/chips/fm2612.c index 44ff0fa70..124577da9 100644 --- a/Frameworks/GME/vgmplay/chips/fm2612.c +++ b/Frameworks/GME/vgmplay/chips/fm2612.c @@ -130,12 +130,14 @@ //#include "emu.h" #include -#include +#include #include #include "mamedef.h" #include "fm.h" +#ifndef NULL #define NULL ((void *)0) +#endif /* shared function building option */ #define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B||BUILD_YM2612||BUILD_YM3438) diff --git a/Frameworks/GME/vgmplay/chips/fmopl.c b/Frameworks/GME/vgmplay/chips/fmopl.c index 4a5e143c7..f6487d2de 100644 --- a/Frameworks/GME/vgmplay/chips/fmopl.c +++ b/Frameworks/GME/vgmplay/chips/fmopl.c @@ -73,7 +73,7 @@ Revision History: #include #endif #include -#include +#include //#include "sndintrf.h" #include "fmopl.h" #if BUILD_Y8950 @@ -81,7 +81,9 @@ Revision History: #endif +#ifndef NULL #define NULL ((void *)0) +#endif /* output final shift */ @@ -2546,6 +2548,10 @@ void *y8950_init(UINT32 clock, UINT32 rate) FM_OPL *Y8950 = OPLCreate(clock,rate,OPL_TYPE_Y8950); if (Y8950) { + Y8950->deltat->memory = NULL; + Y8950->deltat->memory_size = 0x00; + Y8950->deltat->memory_mask = 0x00; + Y8950->deltat->status_set_handler = Y8950_deltat_status_set; Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset; Y8950->deltat->status_change_which_chip = Y8950; diff --git a/Frameworks/GME/vgmplay/chips/gb.c b/Frameworks/GME/vgmplay/chips/gb.c index 281816c7b..b2f78340f 100644 --- a/Frameworks/GME/vgmplay/chips/gb.c +++ b/Frameworks/GME/vgmplay/chips/gb.c @@ -41,7 +41,7 @@ #include "mamedef.h" #include // for rand -#include // for memset +#include // for memset //#include "emu.h" #include "gb.h" //#include "streams.h" diff --git a/Frameworks/GME/vgmplay/chips/iremga20.c b/Frameworks/GME/vgmplay/chips/iremga20.c index 34024b8a4..f2d882d94 100644 --- a/Frameworks/GME/vgmplay/chips/iremga20.c +++ b/Frameworks/GME/vgmplay/chips/iremga20.c @@ -28,7 +28,7 @@ Revisions: //#include "emu.h" #include -#include +#include #include // for NULL #include "mamedef.h" #include "iremga20.h" @@ -213,7 +213,9 @@ UINT8 irem_ga20_r(void *_info, offs_t offset) return chip->channel[channel].play ? 1 : 0; default: +#ifdef _DEBUG logerror("GA20: read unk. register %d, channel %d\n", offset & 0xf, channel); +#endif break; } diff --git a/Frameworks/GME/vgmplay/chips/k051649.c b/Frameworks/GME/vgmplay/chips/k051649.c index 705779526..b820fa6aa 100644 --- a/Frameworks/GME/vgmplay/chips/k051649.c +++ b/Frameworks/GME/vgmplay/chips/k051649.c @@ -24,7 +24,7 @@ #include "mamedef.h" #include -#include +#include //#include "emu.h" //#include "streams.h" #include "k051649.h" @@ -153,10 +153,10 @@ int device_start_k051649(void **_info, int clock) /* get stream channels */ //info->rate = device->clock()/16; - info->rate = clock/16; //info->stream = stream_create(device, 0, 1, info->rate, info, k051649_update); //info->mclock = device->clock(); - info->mclock = clock; + info->mclock = clock & 0x7FFFFFFF; + info->rate = info->mclock / 16; /* allocate a buffer to mix into - 1 second's worth should be more than enough */ //info->mixer_buffer = auto_alloc_array(device->machine, short, 2 * info->rate); diff --git a/Frameworks/GME/vgmplay/chips/k053260.c b/Frameworks/GME/vgmplay/chips/k053260.c index aafa06d19..9d2e3efcd 100644 --- a/Frameworks/GME/vgmplay/chips/k053260.c +++ b/Frameworks/GME/vgmplay/chips/k053260.c @@ -10,10 +10,12 @@ #include #endif #include -#include +#include #include "k053260.h" +#ifndef NULL #define NULL ((void *)0) +#endif /* 2004-02-28: Fixed PPCM decoding. Games sound much better now.*/ @@ -319,7 +321,9 @@ INLINE void check_bounds( k053260_state *ic, int channel ) int channel_end = channel_start + ic->channels[channel].size - 1; if ( channel_start > ic->rom_size ) { +#ifdef _DEBUG logerror("K53260: Attempting to start playing past the end of the ROM ( start = %06x, end = %06x ).\n", channel_start, channel_end ); +#endif ic->channels[channel].play = 0; @@ -327,11 +331,15 @@ INLINE void check_bounds( k053260_state *ic, int channel ) } if ( channel_end > ic->rom_size ) { +#ifdef _DEBUG logerror("K53260: Attempting to play past the end of the ROM ( start = %06x, end = %06x ).\n", channel_start, channel_end ); +#endif ic->channels[channel].size = ic->rom_size - channel_start; } +#ifdef _DEBUG if (LOG) logerror("K053260: Sample Start = %06x, Sample End = %06x, Sample rate = %04x, PPCM = %s\n", channel_start, channel_end, ic->channels[channel].rate, ic->channels[channel].ppcm ? "yes" : "no" ); +#endif } //WRITE8_DEVICE_HANDLER( k053260_w ) @@ -345,7 +353,9 @@ void k053260_w(void *_info, offs_t offset, UINT8 data) k053260_state *ic = (k053260_state *)_info; if ( r > 0x2f ) { +#ifdef _DEBUG logerror("K053260: Writing past registers\n" ); +#endif return; } @@ -480,7 +490,9 @@ UINT8 k053260_r(void *_info, offs_t offset) if ( offs > ic->rom_size ) { //logerror("%s: K53260: Attempting to read past ROM size in ROM Read Mode (offs = %06x, size = %06x).\n", device->machine().describe_context(),offs,ic->rom_size ); +#ifdef _DEBUG logerror("K53260: Attempting to read past ROM size in ROM Read Mode (offs = %06x, size = %06x).\n", offs,ic->rom_size ); +#endif return 0; } diff --git a/Frameworks/GME/vgmplay/chips/k054539.c b/Frameworks/GME/vgmplay/chips/k054539.c index 0ceabbd7e..76acd9c5e 100644 --- a/Frameworks/GME/vgmplay/chips/k054539.c +++ b/Frameworks/GME/vgmplay/chips/k054539.c @@ -9,7 +9,7 @@ //#include "emu.h" #include -#include +#include #include #include "mamedef.h" #ifdef _DEBUG @@ -17,7 +17,9 @@ #endif #include "k054539.h" +#ifndef NULL #define NULL ((void *)0) +#endif #define VERBOSE 0 #define LOG(x) do { if (VERBOSE) logerror x; } while (0) @@ -149,7 +151,7 @@ void k054539_update(void *param, stream_sample_t **outputs, int samples) static const INT16 dpcm[16] = { 0<<8, 1<<8, 4<<8, 9<<8, 16<<8, 25<<8, 36<<8, 49<<8, - -64<<8, -49<<8, -36<<8, -25<<8, -16<<8, -9<<8, -4<<8, -1<<8 + -64*(1<<8), -49*(1<<8), -36*(1<<8), -25*(1<<8), -16*(1<<8), -9*(1<<8), -4*(1<<8), -1*(1<<8) }; INT16 *rbase = (INT16 *)info->ram; @@ -331,7 +333,9 @@ void k054539_update(void *param, stream_sample_t **outputs, int samples) break; } default: +#ifdef _DEBUG LOG(("Unknown sample type %x for channel %d\n", base2[0] & 0xc, ch)); +#endif break; } lval += cur_val * lvol; @@ -553,12 +557,12 @@ void k054539_w(void *_info, offs_t offset, UINT8 data) regbase[offset] = data; } -static void reset_zones(k054539_state *info) +/*static void reset_zones(k054539_state *info) { int data = info->regs[0x22e]; info->cur_zone = data == 0x80 ? info->ram : info->rom + 0x20000*data; info->cur_limit = data == 0x80 ? 0x4000 : 0x20000; -} +}*/ //READ8_DEVICE_HANDLER( k054539_r ) UINT8 k054539_r(void *_info, offs_t offset) @@ -578,7 +582,9 @@ UINT8 k054539_r(void *_info, offs_t offset) case 0x22c: break; default: +#ifdef _DEBUG LOG(("K054539 read %03x\n", offset)); +#endif break; } return info->regs[offset]; diff --git a/Frameworks/GME/vgmplay/chips/mamedef.h b/Frameworks/GME/vgmplay/chips/mamedef.h index f3e8dffdc..bc6cfbf59 100644 --- a/Frameworks/GME/vgmplay/chips/mamedef.h +++ b/Frameworks/GME/vgmplay/chips/mamedef.h @@ -47,7 +47,9 @@ typedef INT32 stream_sample_t; #else #define INLINE static inline #endif +#ifndef M_PI #define M_PI 3.14159265358979323846 +#endif #ifdef _DEBUG #define logerror printf diff --git a/Frameworks/GME/vgmplay/chips/multipcm.c b/Frameworks/GME/vgmplay/chips/multipcm.c index 753b37f65..64469da33 100644 --- a/Frameworks/GME/vgmplay/chips/multipcm.c +++ b/Frameworks/GME/vgmplay/chips/multipcm.c @@ -35,11 +35,13 @@ //#include "streams.h" #include "mamedef.h" #include -#include +#include #include #include "multipcm.h" +#ifndef NULL #define NULL ((void *)0) +#endif //???? #define MULTIPCM_CLOCKDIV (180.0) diff --git a/Frameworks/GME/vgmplay/chips/nes_apu.c b/Frameworks/GME/vgmplay/chips/nes_apu.c index 70fef2cc8..df48883b5 100644 --- a/Frameworks/GME/vgmplay/chips/nes_apu.c +++ b/Frameworks/GME/vgmplay/chips/nes_apu.c @@ -46,7 +46,7 @@ #include "mamedef.h" #include -#include +#include #include // for NULL //#include "emu.h" //#include "streams.h" diff --git a/Frameworks/GME/vgmplay/chips/nes_intf.c b/Frameworks/GME/vgmplay/chips/nes_intf.c index 66d726da8..901875313 100644 --- a/Frameworks/GME/vgmplay/chips/nes_intf.c +++ b/Frameworks/GME/vgmplay/chips/nes_intf.c @@ -5,7 +5,7 @@ ****************************************************************/ #include "mamedef.h" -#include // for memset +#include // for memset #include // for free #include // for NULL #include "../stdbool.h" diff --git a/Frameworks/GME/vgmplay/chips/np_nes_apu.c b/Frameworks/GME/vgmplay/chips/np_nes_apu.c index 4953a7cd1..36152564c 100644 --- a/Frameworks/GME/vgmplay/chips/np_nes_apu.c +++ b/Frameworks/GME/vgmplay/chips/np_nes_apu.c @@ -8,7 +8,7 @@ //#include #include -#include // for memset() +#include // for memset() #include // for NULL #include "mamedef.h" #include "../stdbool.h" diff --git a/Frameworks/GME/vgmplay/chips/np_nes_dmc.c b/Frameworks/GME/vgmplay/chips/np_nes_dmc.c index a4f4aa1c0..790daf8a5 100644 --- a/Frameworks/GME/vgmplay/chips/np_nes_dmc.c +++ b/Frameworks/GME/vgmplay/chips/np_nes_dmc.c @@ -4,7 +4,7 @@ // (Note: Encoding is UTF-8) #include // for rand() -#include // for memset() +#include // for memset() #include // for NULL #include "mamedef.h" #include "../stdbool.h" @@ -532,7 +532,8 @@ void NES_DMC_np_SetClock(void* chip, double c) dmc->clock = (UINT32)(c); - if (abs(dmc->clock - DEFAULT_CLK_PAL) <= 1000) // check for approximately DEFAULT_CLK_PAL + /* abs not needed, values are unsigned */ + if (/*abs*/(dmc->clock - DEFAULT_CLK_PAL) <= 1000) // check for approximately DEFAULT_CLK_PAL NES_DMC_np_SetPal(dmc, true); else NES_DMC_np_SetPal(dmc, false); diff --git a/Frameworks/GME/vgmplay/chips/np_nes_fds.c b/Frameworks/GME/vgmplay/chips/np_nes_fds.c index 18c8089dd..fad3eedbf 100644 --- a/Frameworks/GME/vgmplay/chips/np_nes_fds.c +++ b/Frameworks/GME/vgmplay/chips/np_nes_fds.c @@ -2,7 +2,7 @@ // by Valley Bell on 26 September 2013 #include // for rand() -#include // for memset() +#include // for memset() #include // for NULL #include // for exp() #include "mamedef.h" diff --git a/Frameworks/GME/vgmplay/chips/okim6258.c b/Frameworks/GME/vgmplay/chips/okim6258.c index c79fc2d49..fad41eb22 100644 --- a/Frameworks/GME/vgmplay/chips/okim6258.c +++ b/Frameworks/GME/vgmplay/chips/okim6258.c @@ -19,7 +19,9 @@ #include #include "okim6258.h" +#ifndef NULL #define NULL ((void *)0) +#endif #define COMMAND_STOP (1 << 0) #define COMMAND_PLAY (1 << 1) @@ -403,7 +405,7 @@ void okim6258_set_divider(void *_info, int val) { //okim6258_state *info = get_safe_token(device); okim6258_state *info = (okim6258_state *)_info; - int divider = dividers[val]; + //int divider = dividers[val]; info->divider = dividers[val]; //stream_set_sample_rate(info->stream, info->master_clock / divider); @@ -500,7 +502,9 @@ static void okim6258_data_w(void *_info, /*offs_t offset, */UINT8 data) info->data_buf_pos &= 0xF3; if ((info->data_buf_pos >> 4) == (info->data_buf_pos & 0x0F)) { +#ifdef _DEBUG logerror("Warning: FIFO full!\n"); +#endif info->data_buf_pos = (info->data_buf_pos & 0xF0) | ((info->data_buf_pos-1) & 0x03); } info->data_empty = 0x00; @@ -556,7 +560,9 @@ static void okim6258_ctrl_w(void *_info, /*offs_t offset, */UINT8 data) if (data & COMMAND_RECORD) { +#ifdef _DEBUG logerror("M6258: Record enabled\n"); +#endif info->status |= STATUS_RECORDING; } else diff --git a/Frameworks/GME/vgmplay/chips/okim6295.c b/Frameworks/GME/vgmplay/chips/okim6295.c index 60a77c309..d5314fdab 100644 --- a/Frameworks/GME/vgmplay/chips/okim6295.c +++ b/Frameworks/GME/vgmplay/chips/okim6295.c @@ -26,7 +26,7 @@ //#include "streams.h" #include #include -#include +#include #include #include "okim6295.h" @@ -661,7 +661,9 @@ void okim6295_write_command(okim6295_state *info, UINT8 data) else { //logerror("OKIM6295:'%s' requested to play invalid sample %02x\n",device->tag(),info->command); +#ifdef _DEBUG logerror("OKIM6295: Voice %u requested to play invalid sample %02x\n",i,info->command); +#endif voice->playing = 0; } } diff --git a/Frameworks/GME/vgmplay/chips/opl.c b/Frameworks/GME/vgmplay/chips/opl.c index a053feb84..061417513 100644 --- a/Frameworks/GME/vgmplay/chips/opl.c +++ b/Frameworks/GME/vgmplay/chips/opl.c @@ -29,7 +29,7 @@ #include #include // rand() -#include // for memset() +#include // for memset() //#include "dosbox.h" #include "../stdbool.h" #include "opl.h" @@ -1158,7 +1158,7 @@ static void adlib_write(void *chip, Bitu idx, Bit8u val) } -UINT32 ADLIBEMU(reg_read)(void *chip, UINT32 port) +Bitu ADLIBEMU(reg_read)(void *chip, UINT32 port) { OPL_DATA* OPL = (OPL_DATA*)chip; diff --git a/Frameworks/GME/vgmplay/chips/opl.h b/Frameworks/GME/vgmplay/chips/opl.h index 6dd303345..ec1789fc1 100644 --- a/Frameworks/GME/vgmplay/chips/opl.h +++ b/Frameworks/GME/vgmplay/chips/opl.h @@ -30,6 +30,7 @@ /* define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here */ +/* #include typedef uintptr_t Bitu; typedef intptr_t Bits; @@ -39,6 +40,16 @@ typedef uint16_t Bit16u; typedef int16_t Bit16s; typedef uint8_t Bit8u; typedef int8_t Bit8s; +*/ + +typedef UINT32 Bitu; +typedef INT32 Bits; +typedef UINT32 Bit32u; +typedef INT32 Bit32s; +typedef UINT16 Bit16u; +typedef INT16 Bit16s; +typedef UINT8 Bit8u; +typedef INT8 Bit8s; /* define attribution that inlines/forces inlining of a function (optional) diff --git a/Frameworks/GME/vgmplay/chips/pokey.c b/Frameworks/GME/vgmplay/chips/pokey.c index a8b5ef05a..c047544d2 100644 --- a/Frameworks/GME/vgmplay/chips/pokey.c +++ b/Frameworks/GME/vgmplay/chips/pokey.c @@ -553,11 +553,15 @@ static void poly_init(UINT8 *poly, int size, int left, int right, int add) int mask = (1 << size) - 1; int i, x = 0; +#ifdef _DEBUG LOG_POLY(("poly %d\n", size)); +#endif for( i = 0; i < mask; i++ ) { *poly++ = x & 1; +#ifdef _DEBUG LOG_POLY(("%05x: %d\n", x, x&1)); +#endif /* calculate next bit */ x = ((x << left) + (x >> right) + add) & mask; } @@ -568,14 +572,18 @@ static void rand_init(UINT8 *rng, int size, int left, int right, int add) int mask = (1 << size) - 1; int i, x = 0; +#ifdef _DEBUG LOG_RAND(("rand %d\n", size)); +#endif for( i = 0; i < mask; i++ ) { if (size == 17) *rng = x >> 6; /* use bits 6..13 */ else *rng = x; /* use bits 0..7 */ +#ifdef _DEBUG LOG_RAND(("%05x: %02x\n", x, *rng)); +#endif rng++; /* calculate next bit */ x = ((x << left) + (x >> right) + add) & mask; diff --git a/Frameworks/GME/vgmplay/chips/qsound.c b/Frameworks/GME/vgmplay/chips/qsound.c index aa3069e2a..217eb4f22 100644 --- a/Frameworks/GME/vgmplay/chips/qsound.c +++ b/Frameworks/GME/vgmplay/chips/qsound.c @@ -36,12 +36,14 @@ #ifdef _DEBUG #include #endif -#include +#include #include #include #include "qsound.h" +#ifndef NULL #define NULL ((void *)0) +#endif /* Debug defines @@ -223,7 +225,9 @@ void qsound_w(void *_info, offs_t offset, UINT8 data) default: //logerror("%s: unexpected qsound write to offset %d == %02X\n", device->machine().describe_context(), offset, data); +#ifdef _DEBUG logerror("QSound: unexpected qsound write to offset %d == %02X\n", offset, data); +#endif break; } } @@ -478,7 +482,7 @@ void qsound_set_mute_mask(void *_info, UINT32 MuteMask) case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; } -}// +}*/ /**************** end of file ****************/ diff --git a/Frameworks/GME/vgmplay/chips/rf5c68.c b/Frameworks/GME/vgmplay/chips/rf5c68.c index 672017013..e15d01a64 100644 --- a/Frameworks/GME/vgmplay/chips/rf5c68.c +++ b/Frameworks/GME/vgmplay/chips/rf5c68.c @@ -3,14 +3,16 @@ /*********************************************************/ #include "mamedef.h" -#include +#include #include //#include "sndintrf.h" //#include "streams.h" #include "rf5c68.h" #include +#ifndef NULL #define NULL ((void *)0) +#endif #define NUM_CHANNELS (8) diff --git a/Frameworks/GME/vgmplay/chips/saa1099.c b/Frameworks/GME/vgmplay/chips/saa1099.c index ef9836e78..a78862f1e 100644 --- a/Frameworks/GME/vgmplay/chips/saa1099.c +++ b/Frameworks/GME/vgmplay/chips/saa1099.c @@ -66,7 +66,7 @@ //#include "emu.h" #include "mamedef.h" #include -#include +#include #include "saa1099.h" @@ -448,7 +448,9 @@ void saa1099_control_w(void *_info, offs_t offset, UINT8 data) { /* Error! */ //logerror("%s: (SAA1099 '%s') Unknown register selected\n",device->machine().describe_context(), device->tag()); +#ifdef _DEBUG logerror("SAA1099: Unknown register selected\n"); +#endif } saa->selected_reg = data & 0x1f; @@ -537,7 +539,9 @@ void saa1099_data_w(void *_info, offs_t offset, UINT8 data) /* Synch & Reset generators */ //logerror("%s: (SAA1099 '%s') -reg 0x1c- Chip reset\n",device->machine().describe_context(), device->tag()); +#ifdef _DEBUG logerror("SAA1099: -reg 0x1c- Chip reset\n"); +#endif for (i = 0; i < 6; i++) { saa->channels[i].level = 0; @@ -545,9 +549,11 @@ void saa1099_data_w(void *_info, offs_t offset, UINT8 data) } } break; +#ifdef _DEBUG default: /* Error! */ //logerror("%s: (SAA1099 '%s') Unknown operation (reg:%02x, data:%02x)\n",device->machine().describe_context(), device->tag(), reg, data); logerror("SAA1099: Unknown operation (reg:%02x, data:%02x)\n",reg, data); +#endif } } diff --git a/Frameworks/GME/vgmplay/chips/scsp.c b/Frameworks/GME/vgmplay/chips/scsp.c index d150a9a0a..0e9abbffb 100644 --- a/Frameworks/GME/vgmplay/chips/scsp.c +++ b/Frameworks/GME/vgmplay/chips/scsp.c @@ -1,1526 +1,63 @@ -/* - Sega/Yamaha YMF292-F (SCSP = Saturn Custom Sound Processor) emulation - By ElSemi - MAME/M1 conversion and cleanup by R. Belmont - Additional code and bugfixes by kingshriek - - This chip has 32 voices. Each voice can play a sample or be part of - an FM construct. Unlike traditional Yamaha FM chips, the base waveform - for the FM still comes from the wavetable RAM. - - ChangeLog: - * November 25, 2003 (ES) Fixed buggy timers and envelope overflows. - (RB) Improved sample rates other than 44100, multiple - chips now works properly. - * December 02, 2003 (ES) Added DISDL register support, improves mix. - * April 28, 2004 (ES) Corrected envelope rates, added key-rate scaling, - added ringbuffer support. - * January 8, 2005 (RB) Added ability to specify region offset for RAM. - * January 26, 2007 (ES) Added on-board DSP capability - * September 24, 2007 (RB+ES) Removed fake reverb. Rewrote timers and IRQ handling. - Fixed case where voice frequency is updated while looping. - Enabled DSP again. - * December 16, 2007 (kingshriek) Many EG bug fixes, implemented effects mixer, - implemented FM. - * January 5, 2008 (kingshriek+RB) Working, good-sounding FM, removed obsolete non-USEDSP code. - * April 22, 2009 ("PluginNinja") Improved slot monitor, misc cleanups - * June 6, 2011 (AS) Rewrote DMA from scratch, Darius 2 relies on it. -*/ - //#include "emu.h" #include "mamedef.h" -#include // for pow() in scsplfo.c -#include -//#include -#include // for memset +#include // for malloc/free +#include // for memset + #include "scsp.h" -#include "scspdsp.h" +#include "yam.h" -#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) +enum { SCSPRAM_LENGTH = 0x80000 }; -#define SHIFT 12 -#define FIX(v) ((UINT32) ((float) (1<udata.data[0x0]>>0x0)&0x1000) -#define KEYONB(slot) ((slot->udata.data[0x0]>>0x0)&0x0800) -#define SBCTL(slot) ((slot->udata.data[0x0]>>0x9)&0x0003) -#define SSCTL(slot) ((slot->udata.data[0x0]>>0x7)&0x0003) -#define LPCTL(slot) ((slot->udata.data[0x0]>>0x5)&0x0003) -#define PCM8B(slot) ((slot->udata.data[0x0]>>0x0)&0x0010) - -#define SA(slot) (((slot->udata.data[0x0]&0xF)<<16)|(slot->udata.data[0x1])) - -#define LSA(slot) (slot->udata.data[0x2]) - -#define LEA(slot) (slot->udata.data[0x3]) - -#define D2R(slot) ((slot->udata.data[0x4]>>0xB)&0x001F) -#define D1R(slot) ((slot->udata.data[0x4]>>0x6)&0x001F) -#define EGHOLD(slot) ((slot->udata.data[0x4]>>0x0)&0x0020) -#define AR(slot) ((slot->udata.data[0x4]>>0x0)&0x001F) - -#define LPSLNK(slot) ((slot->udata.data[0x5]>>0x0)&0x4000) -#define KRS(slot) ((slot->udata.data[0x5]>>0xA)&0x000F) -#define DL(slot) ((slot->udata.data[0x5]>>0x5)&0x001F) -#define RR(slot) ((slot->udata.data[0x5]>>0x0)&0x001F) - -#define STWINH(slot) ((slot->udata.data[0x6]>>0x0)&0x0200) -#define SDIR(slot) ((slot->udata.data[0x6]>>0x0)&0x0100) -#define TL(slot) ((slot->udata.data[0x6]>>0x0)&0x00FF) - -#define MDL(slot) ((slot->udata.data[0x7]>>0xC)&0x000F) -#define MDXSL(slot) ((slot->udata.data[0x7]>>0x6)&0x003F) -#define MDYSL(slot) ((slot->udata.data[0x7]>>0x0)&0x003F) - -#define OCT(slot) ((slot->udata.data[0x8]>>0xB)&0x000F) -#define FNS(slot) ((slot->udata.data[0x8]>>0x0)&0x03FF) - -#define LFORE(slot) ((slot->udata.data[0x9]>>0x0)&0x8000) -#define LFOF(slot) ((slot->udata.data[0x9]>>0xA)&0x001F) -#define PLFOWS(slot) ((slot->udata.data[0x9]>>0x8)&0x0003) -#define PLFOS(slot) ((slot->udata.data[0x9]>>0x5)&0x0007) -#define ALFOWS(slot) ((slot->udata.data[0x9]>>0x3)&0x0003) -#define ALFOS(slot) ((slot->udata.data[0x9]>>0x0)&0x0007) - -#define ISEL(slot) ((slot->udata.data[0xA]>>0x3)&0x000F) -#define IMXL(slot) ((slot->udata.data[0xA]>>0x0)&0x0007) - -#define DISDL(slot) ((slot->udata.data[0xB]>>0xD)&0x0007) -#define DIPAN(slot) ((slot->udata.data[0xB]>>0x8)&0x001F) -#define EFSDL(slot) ((slot->udata.data[0xB]>>0x5)&0x0007) -#define EFPAN(slot) ((slot->udata.data[0xB]>>0x0)&0x001F) - -//Envelope times in ms -static const double ARTimes[64]={100000/*infinity*/,100000/*infinity*/,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0, - 1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0, - 76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4, - 2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0}; -static const double DRTimes[64]={100000/*infinity*/,100000/*infinity*/,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0, - 14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0, - 920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0, - 28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1}; - -typedef enum {ATTACK,DECAY1,DECAY2,RELEASE} _STATE; -struct _EG -{ - int volume; // - _STATE state; - int step; - //step vals - int AR; //Attack - int D1R; //Decay1 - int D2R; //Decay2 - int RR; //Release - - int DL; //Decay level - UINT8 EGHOLD; - UINT8 LPLINK; -}; - -struct _SLOT -{ - union - { - UINT16 data[0x10]; //only 0x1a bytes used - UINT8 datab[0x20]; - } udata; - UINT8 Backwards; //the wave is playing backwards - UINT8 active; //this slot is currently playing - UINT8 Muted; - UINT8 *base; //samples base address - UINT32 cur_addr; //current play address (24.8) - UINT32 nxt_addr; //next play address - UINT32 step; //pitch step (24.8) - struct _EG EG; //Envelope - struct _LFO PLFO; //Phase LFO - struct _LFO ALFO; //Amplitude LFO - int slot; - signed short Prev; //Previous sample (for interpolation) -}; - - -#define MEM4B(scsp) ((scsp->udata.data[0]>>0x0)&0x0200) -#define DAC18B(scsp) ((scsp->udata.data[0]>>0x0)&0x0100) -#define MVOL(scsp) ((scsp->udata.data[0]>>0x0)&0x000F) -#define RBL(scsp) ((scsp->udata.data[1]>>0x7)&0x0003) -#define RBP(scsp) ((scsp->udata.data[1]>>0x0)&0x003F) -#define MOFULL(scsp) ((scsp->udata.data[2]>>0x0)&0x1000) -#define MOEMPTY(scsp) ((scsp->udata.data[2]>>0x0)&0x0800) -#define MIOVF(scsp) ((scsp->udata.data[2]>>0x0)&0x0400) -#define MIFULL(scsp) ((scsp->udata.data[2]>>0x0)&0x0200) -#define MIEMPTY(scsp) ((scsp->udata.data[2]>>0x0)&0x0100) - -#define SCILV0(scsp) ((scsp->udata.data[0x24/2]>>0x0)&0xff) -#define SCILV1(scsp) ((scsp->udata.data[0x26/2]>>0x0)&0xff) -#define SCILV2(scsp) ((scsp->udata.data[0x28/2]>>0x0)&0xff) - -#define SCIEX0 0 -#define SCIEX1 1 -#define SCIEX2 2 -#define SCIMID 3 -#define SCIDMA 4 -#define SCIIRQ 5 -#define SCITMA 6 -#define SCITMB 7 - -#define USEDSP - -typedef struct _scsp_state scsp_state; -struct _scsp_state -{ - union - { - UINT16 data[0x30/2]; - UINT8 datab[0x30]; - } udata; - struct _SLOT Slots[32]; - signed short RINGBUF[128]; - unsigned char BUFPTR; -#if FM_DELAY - signed short DELAYBUF[FM_DELAY]; - unsigned char DELAYPTR; -#endif - unsigned char *SCSPRAM; - UINT32 SCSPRAM_LENGTH; - //char Master; - //void (*Int68kCB)(device_t *device, int irq); - //sound_stream * stream; - int clock; - int rate; - - //INT32 *buffertmpl,*buffertmpr; - - /*UINT32 IrqTimA; - UINT32 IrqTimBC; - UINT32 IrqMidi;*/ - - UINT8 MidiOutW,MidiOutR; - UINT8 MidiStack[32]; - UINT8 MidiW,MidiR; - - INT32 EG_TABLE[0x400]; - - int LPANTABLE[0x10000]; - int RPANTABLE[0x10000]; - - int TimPris[3]; - int TimCnt[3]; - - // timers - //emu_timer *timerA, *timerB, *timerC; - - // DMA stuff - struct - { - UINT32 dmea; - UINT16 drga; - UINT16 dtlg; - UINT8 dgate; - UINT8 ddir; - } dma; - - UINT16 mcieb; - UINT16 mcipd; - - int ARTABLE[64], DRTABLE[64]; - - struct _SCSPDSP DSP; - //devcb_resolved_write_line main_irq; - - //device_t *device; - - signed short *RBUFDST; - - UINT8 BypassDSP; -}; - -//static void SCSP_exec_dma(address_space *space, scsp_state *scsp); /*state DMA transfer function*/ -/* TODO */ -//#define dma_transfer_end ((scsp_regs[0x24/2] & 0x10)>>4)|(((scsp_regs[0x26/2] & 0x10)>>4)<<1)|(((scsp_regs[0x28/2] & 0x10)>>4)<<2) - -static const float SDLT[8]={-1000000.0f,-36.0f,-30.0f,-24.0f,-18.0f,-12.0f,-6.0f,0.0f}; - -//static stream_sample_t *bufferl; -//static stream_sample_t *bufferr; - -//static int length; - - -/*INLINE scsp_state *get_safe_token(device_t *device) -{ - assert(device != NULL); - assert(device->type() == SCSP); - return (scsp_state *)downcast(device)->token(); -}*/ - -static unsigned char DecodeSCI(scsp_state *scsp,unsigned char irq) -{ - unsigned char SCI=0; - unsigned char v; - v=(SCILV0((scsp))&(1<udata.data[0x20/2]; - UINT32 en=scsp->udata.data[0x1e/2]; - - if(scsp->MidiW!=scsp->MidiR) - { - scsp->udata.data[0x20/2] |= 8; - pend |= 8; - } - if(!pend) - return; - if(pend&0x40) - if(en&0x40) - { - scsp->Int68kCB(scsp->device, scsp->IrqTimA); - return; - } - if(pend&0x80) - if(en&0x80) - { - scsp->Int68kCB(scsp->device, scsp->IrqTimBC); - return; - } - if(pend&0x100) - if(en&0x100) - { - scsp->Int68kCB(scsp->device, scsp->IrqTimBC); - return; - } - if(pend&8) - if (en&8) - { - scsp->Int68kCB(scsp->device, scsp->IrqMidi); - scsp->udata.data[0x20/2] &= ~8; - return; - } - - scsp->Int68kCB(scsp->device, 0); -} - -static void ResetInterrupts(scsp_state *scsp) -{ - UINT32 reset = scsp->udata.data[0x22/2]; - - if (reset & 0x40) - { - scsp->Int68kCB(scsp->device, -scsp->IrqTimA); - } - if (reset & 0x180) - { - scsp->Int68kCB(scsp->device, -scsp->IrqTimBC); - } - if (reset & 0x8) - { - scsp->Int68kCB(scsp->device, -scsp->IrqMidi); - } - - CheckPendingIRQ(scsp); -} - -static TIMER_CALLBACK( timerA_cb ) -{ - scsp_state *scsp = (scsp_state *)ptr; - - scsp->TimCnt[0] = 0xFFFF; - scsp->udata.data[0x20/2]|=0x40; - scsp->udata.data[0x18/2]&=0xff00; - scsp->udata.data[0x18/2]|=scsp->TimCnt[0]>>8; - - CheckPendingIRQ(scsp); -} - -static TIMER_CALLBACK( timerB_cb ) -{ - scsp_state *scsp = (scsp_state *)ptr; - - scsp->TimCnt[1] = 0xFFFF; - scsp->udata.data[0x20/2]|=0x80; - scsp->udata.data[0x1a/2]&=0xff00; - scsp->udata.data[0x1a/2]|=scsp->TimCnt[1]>>8; - - CheckPendingIRQ(scsp); -} - -static TIMER_CALLBACK( timerC_cb ) -{ - scsp_state *scsp = (scsp_state *)ptr; - - scsp->TimCnt[2] = 0xFFFF; - scsp->udata.data[0x20/2]|=0x100; - scsp->udata.data[0x1c/2]&=0xff00; - scsp->udata.data[0x1c/2]|=scsp->TimCnt[2]>>8; - - CheckPendingIRQ(scsp); -}*/ - -static int Get_AR(scsp_state *scsp,int base,int R) -{ - int Rate=base+(R<<1); - if(Rate>63) Rate=63; - if(Rate<0) Rate=0; - return scsp->ARTABLE[Rate]; -} - -static int Get_DR(scsp_state *scsp,int base,int R) -{ - int Rate=base+(R<<1); - if(Rate>63) Rate=63; - if(Rate<0) Rate=0; - return scsp->DRTABLE[Rate]; -} - -static int Get_RR(scsp_state *scsp,int base,int R) -{ - int Rate=base+(R<<1); - if(Rate>63) Rate=63; - if(Rate<0) Rate=0; - return scsp->DRTABLE[Rate]; -} - -static void Compute_EG(scsp_state *scsp,struct _SLOT *slot) -{ - int octave=(OCT(slot)^8)-8; - int rate; - if(KRS(slot)!=0xf) - rate=octave+2*KRS(slot)+((FNS(slot)>>9)&1); - else - rate=0; //rate=((FNS(slot)>>9)&1); - - slot->EG.volume=0x17F<EG.AR=Get_AR(scsp,rate,AR(slot)); - slot->EG.D1R=Get_DR(scsp,rate,D1R(slot)); - slot->EG.D2R=Get_DR(scsp,rate,D2R(slot)); - slot->EG.RR=Get_RR(scsp,rate,RR(slot)); - slot->EG.DL=0x1f-DL(slot); - slot->EG.EGHOLD=EGHOLD(slot); -} - -static void SCSP_StopSlot(struct _SLOT *slot,int keyoff); - -static int EG_Update(struct _SLOT *slot) -{ - switch(slot->EG.state) - { - case ATTACK: - slot->EG.volume+=slot->EG.AR; - if(slot->EG.volume>=(0x3ff<EG.state=DECAY1; - if(slot->EG.D1R>=(1024<EG.state=DECAY2; - } - slot->EG.volume=0x3ff<EG.EGHOLD) - return 0x3ff<<(SHIFT-10); - break; - case DECAY1: - slot->EG.volume-=slot->EG.D1R; - if(slot->EG.volume<=0) - slot->EG.volume=0; - if(slot->EG.volume>>(EG_SHIFT+5)<=slot->EG.DL) - slot->EG.state=DECAY2; - break; - case DECAY2: - if(D2R(slot)==0) - return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10); - slot->EG.volume-=slot->EG.D2R; - if(slot->EG.volume<=0) - slot->EG.volume=0; - - break; - case RELEASE: - slot->EG.volume-=slot->EG.RR; - if(slot->EG.volume<=0) - { - slot->EG.volume=0; - SCSP_StopSlot(slot,0); - //slot->EG.volume=0x17F<EG.state=ATTACK; - } - break; - default: - return 1<EG.volume>>EG_SHIFT)<<(SHIFT-10); -} - -static UINT32 SCSP_Step(struct _SLOT *slot) -{ - int octave=(OCT(slot)^8)-8+SHIFT-10; - UINT32 Fn=FNS(slot)+(1 << 10); - if (octave >= 0) - { - Fn<<=octave; - } - else - { - Fn>>=-octave; - } - - return Fn; -} - - -static void Compute_LFO(struct _SLOT *slot) -{ - if(PLFOS(slot)!=0) - LFO_ComputeStep(&(slot->PLFO),LFOF(slot),PLFOWS(slot),PLFOS(slot),0); - if(ALFOS(slot)!=0) - LFO_ComputeStep(&(slot->ALFO),LFOF(slot),ALFOWS(slot),ALFOS(slot),1); -} - -static void SCSP_StartSlot(scsp_state *scsp, struct _SLOT *slot) -{ - UINT32 start_offset; - - slot->active=1; - start_offset = PCM8B(slot) ? SA(slot) : SA(slot) & 0x7FFFE; - slot->base=scsp->SCSPRAM + start_offset; - slot->cur_addr=0; - slot->nxt_addr=1<step=SCSP_Step(slot); - Compute_EG(scsp,slot); - slot->EG.state=ATTACK; - slot->EG.volume=0x17F<Prev=0; - slot->Backwards=0; - - Compute_LFO(slot); - -// printf("StartSlot[%p]: SA %x PCM8B %x LPCTL %x ALFOS %x STWINH %x TL %x EFSDL %x\n", slot, SA(slot), PCM8B(slot), LPCTL(slot), ALFOS(slot), STWINH(slot), TL(slot), EFSDL(slot)); -} - -static void SCSP_StopSlot(struct _SLOT *slot,int keyoff) -{ - if(keyoff /*&& slot->EG.state!=RELEASE*/) - { - slot->EG.state=RELEASE; - } - else - { - slot->active=0; - } - slot->udata.data[0]&=~0x800; -} - -#define log_base_2(n) (log((double)(n))/log(2.0)) - -//static void SCSP_Init(device_t *device, scsp_state *scsp, const scsp_interface *intf) -static void SCSP_Init(scsp_state *scsp, int clock) -{ - int i; - - memset(scsp,0,sizeof(*scsp)); - - SCSPDSP_Init(&scsp->DSP); - - //scsp->device = device; - scsp->clock = clock; - scsp->rate = clock / 512; - - //scsp->IrqTimA = scsp->IrqTimBC = scsp->IrqMidi = 0; - scsp->MidiR=scsp->MidiW=0; - scsp->MidiOutR=scsp->MidiOutW=0; - - // get SCSP RAM - /*if (strcmp(device->tag(), "scsp") == 0 || strcmp(device->tag(), "scsp1") == 0) - { - scsp->Master=1; - } - else - { - scsp->Master=0; - }*/ - - /*scsp->SCSPRAM = *device->region(); - if (scsp->SCSPRAM) - { - scsp->SCSPRAM_LENGTH = device->region()->bytes(); - scsp->DSP.SCSPRAM = (UINT16 *)scsp->SCSPRAM; - scsp->DSP.SCSPRAM_LENGTH = scsp->SCSPRAM_LENGTH/2; - scsp->SCSPRAM += intf->roffset; - }*/ - scsp->SCSPRAM_LENGTH = 0x80000; // 512 KB - scsp->SCSPRAM = (unsigned char*)malloc(scsp->SCSPRAM_LENGTH); - scsp->DSP.SCSPRAM_LENGTH = scsp->SCSPRAM_LENGTH / 2; - scsp->DSP.SCSPRAM = (UINT16*)scsp->SCSPRAM; - - /*scsp->timerA = device->machine().scheduler().timer_alloc(FUNC(timerA_cb), scsp); - scsp->timerB = device->machine().scheduler().timer_alloc(FUNC(timerB_cb), scsp); - scsp->timerC = device->machine().scheduler().timer_alloc(FUNC(timerC_cb), scsp);*/ - - for(i=0;i<0x400;++i) - { - float envDB=((float)(3*(i-0x3ff)))/32.0f; - float scale=(float)(1<EG_TABLE[i]=(INT32)(pow(10.0,envDB/20.0)*scale); - } - - for(i=0;i<0x10000;++i) - { - int iTL =(i>>0x0)&0xff; - int iPAN=(i>>0x8)&0x1f; - int iSDL=(i>>0xD)&0x07; - float TL=1.0f; - float SegaDB=0.0f; - float fSDL=1.0f; - float PAN=1.0f; - float LPAN,RPAN; - - if(iTL&0x01) SegaDB-=0.4f; - if(iTL&0x02) SegaDB-=0.8f; - if(iTL&0x04) SegaDB-=1.5f; - if(iTL&0x08) SegaDB-=3.0f; - if(iTL&0x10) SegaDB-=6.0f; - if(iTL&0x20) SegaDB-=12.0f; - if(iTL&0x40) SegaDB-=24.0f; - if(iTL&0x80) SegaDB-=48.0f; - - TL=pow(10.0,SegaDB/20.0); - - SegaDB=0; - if(iPAN&0x1) SegaDB-=3.0f; - if(iPAN&0x2) SegaDB-=6.0f; - if(iPAN&0x4) SegaDB-=12.0f; - if(iPAN&0x8) SegaDB-=24.0f; - - if((iPAN&0xf)==0xf) PAN=0.0; - else PAN=pow(10.0,SegaDB/20.0); - - if(iPAN<0x10) - { - LPAN=PAN; - RPAN=1.0; - } - else - { - RPAN=PAN; - LPAN=1.0; - } - - if(iSDL) - fSDL=pow(10.0,(SDLT[iSDL])/20.0); - else - fSDL=0.0; - - scsp->LPANTABLE[i]=FIX((4.0*LPAN*TL*fSDL)); - scsp->RPANTABLE[i]=FIX((4.0*RPAN*TL*fSDL)); - } - - scsp->ARTABLE[0]=scsp->DRTABLE[0]=0; //Infinite time - scsp->ARTABLE[1]=scsp->DRTABLE[1]=0; //Infinite time - for(i=2;i<64;++i) - { - double t,step,scale; - t=ARTimes[i]; //In ms - if(t!=0.0) - { - step=(1023*1000.0)/((float) 44100.0f*t); - scale=(double) (1<ARTABLE[i]=(int) (step*scale); - } - else - scsp->ARTABLE[i]=1024<DRTABLE[i]=(int) (step*scale); - } - - // make sure all the slots are off - for(i=0;i<32;++i) - { - scsp->Slots[i].slot=i; - scsp->Slots[i].active=0; - scsp->Slots[i].base=NULL; - scsp->Slots[i].EG.state=RELEASE; - } - - //LFO_Init(device->machine()); - LFO_Init(); - //scsp->buffertmpl=auto_alloc_array_clear(device->machine(), signed int, 44100); - //scsp->buffertmpr=auto_alloc_array_clear(device->machine(), signed int, 44100); - - // no "pend" - scsp->udata.data[0x20/2] = 0; - scsp->TimCnt[0] = 0xffff; - scsp->TimCnt[1] = 0xffff; - scsp->TimCnt[2] = 0xffff; -} - -INLINE void SCSP_UpdateSlotReg(scsp_state *scsp,int s,int r) -{ - struct _SLOT *slot=scsp->Slots+s; - int sl; - switch(r&0x3f) - { - case 0: - case 1: - if(KEYONEX(slot)) - { - for(sl=0;sl<32;++sl) - { - struct _SLOT *s2=scsp->Slots+sl; - { - if(KEYONB(s2) && s2->EG.state==RELEASE/*&& !s2->active*/) - { - SCSP_StartSlot(scsp, s2); - } - if(!KEYONB(s2) /*&& s2->active*/) - { - SCSP_StopSlot(s2,1); - } - } - } - slot->udata.data[0]&=~0x1000; - } - break; - case 0x10: - case 0x11: - slot->step=SCSP_Step(slot); - break; - case 0xA: - case 0xB: - slot->EG.RR=Get_RR(scsp,0,RR(slot)); - slot->EG.DL=0x1f-DL(slot); - break; - case 0x12: - case 0x13: - Compute_LFO(slot); - break; - } -} - -INLINE void SCSP_UpdateReg(scsp_state *scsp, /*address_space &space,*/ int reg) -{ - switch(reg&0x3f) - { - case 0x0: - // TODO: Make this work in VGMPlay - //scsp->stream->set_output_gain(0,MVOL(scsp) / 15.0); - //scsp->stream->set_output_gain(1,MVOL(scsp) / 15.0); - break; - case 0x2: - case 0x3: - { - unsigned int v=RBL(scsp); - scsp->DSP.RBP=RBP(scsp); - if(v==0) - scsp->DSP.RBL=8*1024; - else if(v==1) - scsp->DSP.RBL=16*1024; - else if(v==2) - scsp->DSP.RBL=32*1024; - else if(v==3) - scsp->DSP.RBL=64*1024; - } - break; - case 0x6: - case 0x7: - //scsp_midi_in(space->machine().device("scsp"), 0, scsp->udata.data[0x6/2]&0xff, 0); - break; - case 8: - case 9: - /* Only MSLC could be written. */ - scsp->udata.data[0x8/2] &= 0x7800; - break; - case 0x12: - case 0x13: - //scsp->dma.dmea = (scsp->udata.data[0x12/2] & 0xfffe) | (scsp->dma.dmea & 0xf0000); - break; - case 0x14: - case 0x15: - //scsp->dma.dmea = ((scsp->udata.data[0x14/2] & 0xf000) << 4) | (scsp->dma.dmea & 0xfffe); - //scsp->dma.drga = (scsp->udata.data[0x14/2] & 0x0ffe); - break; - case 0x16: - case 0x17: - //scsp->dma.dtlg = (scsp->udata.data[0x16/2] & 0x0ffe); - //scsp->dma.ddir = (scsp->udata.data[0x16/2] & 0x2000) >> 13; - //scsp->dma.dgate = (scsp->udata.data[0x16/2] & 0x4000) >> 14; - //if(scsp->udata.data[0x16/2] & 0x1000) // dexe - // SCSP_exec_dma(space, scsp); - break; - case 0x18: - case 0x19: - /*if(scsp->Master) - { - UINT32 time; - - scsp->TimPris[0]=1<<((scsp->udata.data[0x18/2]>>8)&0x7); - scsp->TimCnt[0]=(scsp->udata.data[0x18/2]&0xff)<<8; - - if ((scsp->udata.data[0x18/2]&0xff) != 255) - { - time = (44100 / scsp->TimPris[0]) / (255-(scsp->udata.data[0x18/2]&0xff)); - if (time) - { - scsp->timerA->adjust(attotime::from_hz(time)); - } - } - }*/ - break; - case 0x1a: - case 0x1b: - /*if(scsp->Master) - { - UINT32 time; - - scsp->TimPris[1]=1<<((scsp->udata.data[0x1A/2]>>8)&0x7); - scsp->TimCnt[1]=(scsp->udata.data[0x1A/2]&0xff)<<8; - - if ((scsp->udata.data[0x1A/2]&0xff) != 255) - { - time = (44100 / scsp->TimPris[1]) / (255-(scsp->udata.data[0x1A/2]&0xff)); - if (time) - { - scsp->timerB->adjust(attotime::from_hz(time)); - } - } - }*/ - break; - case 0x1C: - case 0x1D: - /*if(scsp->Master) - { - UINT32 time; - - scsp->TimPris[2]=1<<((scsp->udata.data[0x1C/2]>>8)&0x7); - scsp->TimCnt[2]=(scsp->udata.data[0x1C/2]&0xff)<<8; - - if ((scsp->udata.data[0x1C/2]&0xff) != 255) - { - time = (44100 / scsp->TimPris[2]) / (255-(scsp->udata.data[0x1C/2]&0xff)); - if (time) - { - scsp->timerC->adjust(attotime::from_hz(time)); - } - } - }*/ - break; - case 0x1e: // SCIEB - case 0x1f: - /*if(scsp->Master) - { - CheckPendingIRQ(scsp); - - if(scsp->udata.data[0x1e/2] & 0x610) - popmessage("SCSP SCIEB enabled %04x, contact MAMEdev",scsp->udata.data[0x1e/2]); - }*/ - break; - case 0x20: // SCIPD - case 0x21: - /*if(scsp->Master) - { - if(scsp->udata.data[0x1e/2] & scsp->udata.data[0x20/2] & 0x20) - popmessage("SCSP SCIPD write %04x, contact MAMEdev",scsp->udata.data[0x20/2]); - }*/ - break; - case 0x22: //SCIRE - case 0x23: - - /*if(scsp->Master) - { - scsp->udata.data[0x20/2]&=~scsp->udata.data[0x22/2]; - ResetInterrupts(scsp); - - // behavior from real hardware: if you SCIRE a timer that's expired, - // it'll immediately pop up again in SCIPD. ask Sakura Taisen on the Saturn... - if (scsp->TimCnt[0] == 0xffff) - { - scsp->udata.data[0x20/2] |= 0x40; - } - if (scsp->TimCnt[1] == 0xffff) - { - scsp->udata.data[0x20/2] |= 0x80; - } - if (scsp->TimCnt[2] == 0xffff) - { - scsp->udata.data[0x20/2] |= 0x100; - } - }*/ - break; - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - /*if(scsp->Master) - { - scsp->IrqTimA=DecodeSCI(scsp,SCITMA); - scsp->IrqTimBC=DecodeSCI(scsp,SCITMB); - scsp->IrqMidi=DecodeSCI(scsp,SCIMID); - }*/ - break; - case 0x2a: - case 0x2b: - scsp->mcieb = scsp->udata.data[0x2a/2]; - - /*MainCheckPendingIRQ(scsp, 0); - if(scsp->mcieb & ~0x60) - popmessage("SCSP MCIEB enabled %04x, contact MAMEdev",scsp->mcieb);*/ - break; - case 0x2c: - case 0x2d: - //if(scsp->udata.data[0x2c/2] & 0x20) - // MainCheckPendingIRQ(scsp, 0x20); - break; - case 0x2e: - case 0x2f: - scsp->mcipd &= ~scsp->udata.data[0x2e/2]; - //MainCheckPendingIRQ(scsp, 0); - break; - - } -} - -static void SCSP_UpdateSlotRegR(scsp_state *scsp, int slot,int reg) -{ - -} - -static void SCSP_UpdateRegR(scsp_state *scsp, int reg) -{ - switch(reg&0x3f) - { - case 4: - case 5: - { - unsigned short v=scsp->udata.data[0x5/2]; - v&=0xff00; - v|=scsp->MidiStack[scsp->MidiR]; - /*scsp->Int68kCB(scsp->device, -scsp->IrqMidi); // cancel the IRQ - logerror("Read %x from SCSP MIDI\n", v);*/ - if(scsp->MidiR!=scsp->MidiW) - { - ++scsp->MidiR; - scsp->MidiR&=31; - } - scsp->udata.data[0x5/2]=v; - } - break; - case 8: - case 9: - { - // MSLC | CA |SGC|EG - // f e d c b a 9 8 7 6 5 4 3 2 1 0 - unsigned char MSLC=(scsp->udata.data[0x8/2]>>11)&0x1f; - struct _SLOT *slot=scsp->Slots + MSLC; - unsigned int SGC = (slot->EG.state) & 3; - unsigned int CA = (slot->cur_addr>>(SHIFT+12)) & 0xf; - unsigned int EG = (0x1f - (slot->EG.volume>>(EG_SHIFT+5))) & 0x1f; - /* note: according to the manual MSLC is write only, CA, SGC and EG read only. */ - scsp->udata.data[0x8/2] = /*(MSLC << 11) |*/ (CA << 7) | (SGC << 5) | EG; - } - break; - - case 0x18: - case 0x19: - break; - - case 0x1a: - case 0x1b: - break; - - case 0x1c: - case 0x1d: - break; - - case 0x2a: - case 0x2b: - scsp->udata.data[0x2a/2] = scsp->mcieb; - break; - - case 0x2c: - case 0x2d: - scsp->udata.data[0x2c/2] = scsp->mcipd; - break; - } -} - -INLINE void SCSP_w16(scsp_state *scsp,unsigned int addr,unsigned short val) -{ - addr&=0xffff; - if(addr<0x400) - { - int slot=addr/0x20; - addr&=0x1f; - *((unsigned short *) (scsp->Slots[slot].udata.datab+(addr))) = val; - SCSP_UpdateSlotReg(scsp,slot,addr&0x1f); - } - else if(addr<0x600) - { - if (addr < 0x430) - { - *((unsigned short *) (scsp->udata.datab+((addr&0x3f)))) = val; - SCSP_UpdateReg(scsp, addr&0x3f); - } - } - else if(addr<0x700) - scsp->RINGBUF[(addr-0x600)/2]=val; - else - { - //DSP - if(addr<0x780) //COEF - *((unsigned short *) (scsp->DSP.COEF+(addr-0x700)/2))=val; - else if(addr<0x7c0) - *((unsigned short *) (scsp->DSP.MADRS+(addr-0x780)/2))=val; - else if(addr<0x800) // MADRS is mirrored twice - *((unsigned short *) (scsp->DSP.MADRS+(addr-0x7c0)/2))=val; - else if(addr<0xC00) - { - *((unsigned short *) (scsp->DSP.MPRO+(addr-0x800)/2))=val; - - if(addr==0xBF0) - { - SCSPDSP_Start(&scsp->DSP); - } - } - } -} - -INLINE unsigned short SCSP_r16(scsp_state *scsp, unsigned int addr) -{ - unsigned short v=0; - addr&=0xffff; - if(addr<0x400) - { - int slot=addr/0x20; - addr&=0x1f; - SCSP_UpdateSlotRegR(scsp, slot,addr&0x1f); - v=*((unsigned short *) (scsp->Slots[slot].udata.datab+(addr))); - } - else if(addr<0x600) - { - if (addr < 0x430) - { - SCSP_UpdateRegR(scsp, addr&0x3f); - v= *((unsigned short *) (scsp->udata.datab+((addr&0x3f)))); - } - } - else if(addr<0x700) - v=scsp->RINGBUF[(addr-0x600)/2]; -#if 1 // disabled by default until I get the DSP to work correctly - // can be enabled using separate option - else - { - //DSP - if(addr<0x780) //COEF - v= *((unsigned short *) (scsp->DSP.COEF+(addr-0x700)/2)); - else if(addr<0x7c0) - v= *((unsigned short *) (scsp->DSP.MADRS+(addr-0x780)/2)); - else if(addr<0x800) - v= *((unsigned short *) (scsp->DSP.MADRS+(addr-0x7c0)/2)); - else if(addr<0xC00) - v= *((unsigned short *) (scsp->DSP.MPRO+(addr-0x800)/2)); - else if(addr<0xE00) - { - if(addr & 2) - v= scsp->DSP.TEMP[(addr >> 2) & 0x7f] & 0xffff; - else - v= scsp->DSP.TEMP[(addr >> 2) & 0x7f] >> 16; - } - else if(addr<0xE80) - { - if(addr & 2) - v= scsp->DSP.MEMS[(addr >> 2) & 0x1f] & 0xffff; - else - v= scsp->DSP.MEMS[(addr >> 2) & 0x1f] >> 16; - } - else if(addr<0xEC0) - { - if(addr & 2) - v= scsp->DSP.MIXS[(addr >> 2) & 0xf] & 0xffff; - else - v= scsp->DSP.MIXS[(addr >> 2) & 0xf] >> 16; - } - else if(addr<0xEE0) - v= *((unsigned short *) (scsp->DSP.EFREG+(addr-0xec0)/2)); - else - { - /* - Kyuutenkai reads from 0xee0/0xee2, it's tied with EXTS register(s) also used for CD-Rom Player equalizer. - This port is actually an external parallel port, directly connected from the CD Block device, hence code is a bit of an hack. - */ - logerror("SCSP: Reading from EXTS register %08x\n",addr); - //if(addr == 0xee0) - // v = space.machine().device("cdda")->get_channel_volume(0); - //if(addr == 0xee2) - // v = space.machine().device("cdda")->get_channel_volume(1); - v = 0xFFFF; - } - } -#endif - return v; -} - - -#define REVSIGN(v) ((~v)+1) - -INLINE INT32 SCSP_UpdateSlot(scsp_state *scsp, struct _SLOT *slot) -{ - INT32 sample; - int step=slot->step; - UINT32 addr1,addr2,addr_select; // current and next sample addresses - UINT32 *addr[2] = {&addr1, &addr2}; // used for linear interpolation - UINT32 *slot_addr[2] = {&(slot->cur_addr), &(slot->nxt_addr)}; // - - if(SSCTL(slot)!=0) //no FM or noise yet - return 0; - - if(PLFOS(slot)!=0) - { - step=step*PLFO_Step(&(slot->PLFO)); - step>>=SHIFT; - } - - if(PCM8B(slot)) - { - addr1=slot->cur_addr>>SHIFT; - addr2=slot->nxt_addr>>SHIFT; - } - else - { - addr1=(slot->cur_addr>>(SHIFT-1))&0x7fffe; - addr2=(slot->nxt_addr>>(SHIFT-1))&0x7fffe; - } - - if(MDL(slot)!=0 || MDXSL(slot)!=0 || MDYSL(slot)!=0) - { - INT32 smp=(scsp->RINGBUF[(scsp->BUFPTR+MDXSL(slot))&63]+scsp->RINGBUF[(scsp->BUFPTR+MDYSL(slot))&63])/2; - - smp<<=0xA; // associate cycle with 1024 - smp>>=0x1A-MDL(slot); // ex. for MDL=0xF, sample range corresponds to +/- 64 pi (32=2^5 cycles) so shift by 11 (16-5 == 0x1A-0xF) - if(!PCM8B(slot)) smp<<=1; - - addr1+=smp; addr2+=smp; - } - -#if 0 - // Since the SCSP is for Big Endian platforms, this code expects the data in - // byte order 1 0 3 2 5 4 .... - if(PCM8B(slot)) //8 bit signed - { - INT8 *p1=(signed char *) (scsp->SCSPRAM+BYTE_XOR_BE(((SA(slot)+addr1))&0x7FFFF)); - INT8 *p2=(signed char *) (scsp->SCSPRAM+BYTE_XOR_BE(((SA(slot)+addr2))&0x7FFFF)); - //sample=(p[0])<<8; - INT32 s; - INT32 fpart=slot->cur_addr&((1<>SHIFT); - } - else //16 bit signed (endianness?) - { - INT16 *p1=(signed short *) (scsp->SCSPRAM+((SA(slot)+addr1)&0x7FFFE)); - INT16 *p2=(signed short *) (scsp->SCSPRAM+((SA(slot)+addr2)&0x7FFFE)); - INT32 s; - INT32 fpart=slot->cur_addr&((1<>SHIFT); - } -#else -#define READ_BE16(ptr) (((ptr)[0] << 8) | (ptr)[1]) - // I prefer the byte order 0 1 2 3 4 5 ... - // also, I won't use pointers here, since they only used [0] on them anyway. - if(PCM8B(slot)) //8 bit signed - { - INT8 p1=(INT8)scsp->SCSPRAM[(SA(slot)+addr1)&0x7FFFF]; - INT8 p2=(INT8)scsp->SCSPRAM[(SA(slot)+addr2)&0x7FFFF]; - INT32 s; - INT32 fpart=slot->cur_addr&((1<>SHIFT); - } - else //16 bit signed - { - UINT8 *pp1 = &scsp->SCSPRAM[(SA(slot)+addr1)&0x7FFFE]; - UINT8 *pp2 = &scsp->SCSPRAM[(SA(slot)+addr2)&0x7FFFE]; - INT16 p1 = (INT16)READ_BE16(pp1); - INT16 p2 = (INT16)READ_BE16(pp2); - INT32 s; - INT32 fpart=slot->cur_addr&((1<>SHIFT); - } -#endif - - if(SBCTL(slot)&0x1) - sample ^= 0x7FFF; - if(SBCTL(slot)&0x2) - sample = (INT16)(sample^0x8000); - - if(slot->Backwards) - slot->cur_addr-=step; - else - slot->cur_addr+=step; - slot->nxt_addr=slot->cur_addr+(1<cur_addr>>SHIFT; - addr2=slot->nxt_addr>>SHIFT; - - if(addr1>=LSA(slot) && !(slot->Backwards)) - { - if(LPSLNK(slot) && slot->EG.state==ATTACK) - slot->EG.state = DECAY1; - } - - for (addr_select=0;addr_select<2;addr_select++) - { - INT32 rem_addr; - switch(LPCTL(slot)) - { - case 0: //no loop - if(*addr[addr_select]>=LSA(slot) && *addr[addr_select]>=LEA(slot)) - { - //slot->active=0; - SCSP_StopSlot(slot,0); - } - break; - case 1: //normal loop - if(*addr[addr_select]>=LEA(slot)) - { - rem_addr = *slot_addr[addr_select] - (LEA(slot)<=LSA(slot)) && !(slot->Backwards)) - { - rem_addr = *slot_addr[addr_select] - (LSA(slot)<Backwards=1; - } - else if((*addr[addr_select]Backwards) - { - rem_addr = (LSA(slot)<=LEA(slot)) //reached end, reverse till start - { - rem_addr = *slot_addr[addr_select] - (LEA(slot)<Backwards=1; - } - else if((*addr[addr_select]Backwards)//reached start or negative - { - rem_addr = (LSA(slot)<Backwards=0; - } - break; - } - } - - if(!SDIR(slot)) - { - if(ALFOS(slot)!=0) - { - sample=sample*ALFO_Step(&(slot->ALFO)); - sample>>=SHIFT; - } - - if(slot->EG.state==ATTACK) - sample=(sample*EG_Update(slot))>>SHIFT; - else - sample=(sample*scsp->EG_TABLE[EG_Update(slot)>>(SHIFT-10)])>>SHIFT; - } - - if(!STWINH(slot)) - { - if(!SDIR(slot)) - { - unsigned short Enc=((TL(slot))<<0x0)|(0x7<<0xd); - *scsp->RBUFDST=(sample*scsp->LPANTABLE[Enc])>>(SHIFT+1); - } - else - { - unsigned short Enc=(0<<0x0)|(0x7<<0xd); - *scsp->RBUFDST=(sample*scsp->LPANTABLE[Enc])>>(SHIFT+1); - } - } - - return sample; -} - -INLINE void SCSP_DoMasterSamples(scsp_state *scsp, stream_sample_t **outputs, int nsamples) -{ - stream_sample_t *bufr,*bufl; - int sl, s, i; - - //bufr=bufferr; - //bufl=bufferl; - bufl = outputs[0]; - bufr = outputs[1]; - - for(s=0;sRBUFDST=scsp->DELAYBUF+scsp->DELAYPTR; -#else - scsp->RBUFDST=scsp->RINGBUF+scsp->BUFPTR; -#endif - if(scsp->Slots[sl].active && ! scsp->Slots[sl].Muted) - { - struct _SLOT *slot=scsp->Slots+sl; - unsigned short Enc; - signed int sample; - - sample=SCSP_UpdateSlot(scsp, slot); - - if (! scsp->BypassDSP) - { - Enc=((TL(slot))<<0x0)|((IMXL(slot))<<0xd); - SCSPDSP_SetSample(&scsp->DSP,(sample*scsp->LPANTABLE[Enc])>>(SHIFT-2),ISEL(slot),IMXL(slot)); - } - Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((DISDL(slot))<<0xd); - { - smpl+=(sample*scsp->LPANTABLE[Enc])>>SHIFT; - smpr+=(sample*scsp->RPANTABLE[Enc])>>SHIFT; - } - } - -#if FM_DELAY - scsp->RINGBUF[(scsp->BUFPTR+64-(FM_DELAY-1))&63] = scsp->DELAYBUF[(scsp->DELAYPTR+FM_DELAY-(FM_DELAY-1))%FM_DELAY]; -#endif - ++scsp->BUFPTR; - scsp->BUFPTR&=63; -#if FM_DELAY - ++scsp->DELAYPTR; - if(scsp->DELAYPTR>FM_DELAY-1) scsp->DELAYPTR=0; -#endif - } - - if (! scsp->BypassDSP) - { - SCSPDSP_Step(&scsp->DSP); - - for(i=0;i<16;++i) - { - struct _SLOT *slot=scsp->Slots+i; - if(EFSDL(slot)) - { - unsigned short Enc=((EFPAN(slot))<<0x8)|((EFSDL(slot))<<0xd); - smpl+=(scsp->DSP.EFREG[i]*scsp->LPANTABLE[Enc])>>SHIFT; - smpr+=(scsp->DSP.EFREG[i]*scsp->RPANTABLE[Enc])>>SHIFT; - } - } - } - - //*bufl++ = ICLIP16(smpl>>2); - //*bufr++ = ICLIP16(smpr>>2); - *bufl++ = smpl>>3; - *bufr++ = smpr>>3; - } -} - -/* TODO: this needs to be timer-ized */ -/*static void SCSP_exec_dma(address_space *space, scsp_state *scsp) -{ - static UINT16 tmp_dma[3]; - int i; - - logerror("SCSP: DMA transfer START\n" - "DMEA: %04x DRGA: %04x DTLG: %04x\n" - "DGATE: %d DDIR: %d\n",scsp->dma.dmea,scsp->dma.drga,scsp->dma.dtlg,scsp->dma.dgate ? 1 : 0,scsp->dma.ddir ? 1 : 0); - - // Copy the dma values in a temp storage for resuming later - // (DMA *can't* overwrite its parameters) - if(!(dma.ddir)) - { - for(i=0;i<3;i++) - tmp_dma[i] = scsp->udata.data[(0x12+(i*2))/2]; - } - - // note: we don't use space.read_word / write_word because it can happen that SH-2 enables the DMA instead of m68k. - // TODO: don't know if params auto-updates, I guess not ... - if(dma.ddir) - { - if(dma.dgate) - { - popmessage("Check: SCSP DMA DGATE enabled, contact MAME/MESSdev"); - for(i=0;i < scsp->dma.dtlg;i+=2) - { - scsp->SCSPRAM[scsp->dma.dmea] = 0; - scsp->SCSPRAM[scsp->dma.dmea+1] = 0; - scsp->dma.dmea+=2; - } - } - else - { - for(i=0;i < scsp->dma.dtlg;i+=2) - { - UINT16 tmp; - tmp = SCSP_r16(scsp, space, scsp->dma.drga); - scsp->SCSPRAM[scsp->dma.dmea] = tmp & 0xff; - scsp->SCSPRAM[scsp->dma.dmea+1] = tmp>>8; - scsp->dma.dmea+=2; - scsp->dma.drga+=2; - } - } - } - else - { - if(dma.dgate) - { - popmessage("Check: SCSP DMA DGATE enabled, contact MAME/MESSdev"); - for(i=0;i < scsp->dma.dtlg;i+=2) - { - SCSP_w16(scsp, space, scsp->dma.drga, 0); - scsp->dma.drga+=2; - } - } - else - { - for(i=0;i < scsp->dma.dtlg;i+=2) - { - UINT16 tmp; - tmp = scsp->SCSPRAM[scsp->dma.dmea]; - tmp|= scsp->SCSPRAM[scsp->dma.dmea+1]<<8; - SCSP_w16(scsp, space, scsp->dma.drga, tmp); - scsp->dma.dmea+=2; - scsp->dma.drga+=2; - } - } - } - - //Resume the values - if(!(dma.ddir)) - { - for(i=0;i<3;i++) - scsp->udata.data[(0x12+(i*2))/2] = tmp_dma[i]; - } - - // Job done - scsp->udata.data[0x16/2] &= ~0x1000; - // request a dma end irq (TODO: make it inside the interface) - if(scsp->udata.data[0x1e/2] & 0x10) - { - popmessage("SCSP DMA IRQ triggered, contact MAMEdev"); - device_set_input_line(space->machine().device("audiocpu"),DecodeSCI(scsp,SCIDMA),HOLD_LINE); - } -}*/ - -#ifdef UNUSED_FUNCTION -int SCSP_IRQCB(void *param) -{ - CheckPendingIRQ(param); - return -1; -} -#endif +#undef YAMSTATE +#define SCSPRAM ((unsigned char *)info) +#define YAMSTATE ((void*)(SCSPRAM+SCSPRAM_LENGTH)) //static STREAM_UPDATE( SCSP_Update ) -void SCSP_Update(void *_info, stream_sample_t **outputs, int samples) +void SCSP_Update(void *info, stream_sample_t **outputs, int samples) { - //scsp_state *scsp = (scsp_state *)param; - scsp_state *scsp = (scsp_state *)_info; - //bufferl = outputs[0]; - //bufferr = outputs[1]; - //length = samples; - SCSP_DoMasterSamples(scsp, outputs, samples); + sint16 buffer[400]; + stream_sample_t *bufferleft = outputs[0]; + stream_sample_t *bufferright = outputs[1]; + while (samples) { + int i; + int samplesnow = samples>200 ? 200 : samples; + yam_beginbuffer(YAMSTATE, buffer); + yam_advance(YAMSTATE, samplesnow); + yam_flush(YAMSTATE); + for (i = 0; i < samplesnow; ++i) { + *bufferleft++ = buffer[i * 2] << 8; + *bufferright++ = buffer[i * 2 + 1] << 8; + } + samples -= samplesnow; + } } //static DEVICE_START( scsp ) + int device_start_scsp(void **_info, int clock, int Flags) { - /*const scsp_interface *intf; - - scsp_state *scsp = get_safe_token(device); - - intf = (const scsp_interface *)device->static_config();*/ - scsp_state *scsp; - - scsp = (scsp_state *) calloc(1, sizeof(scsp_state)); - *_info = (void *) scsp; - - scsp->BypassDSP = (Flags & 0x01) >> 0; - - if (clock < 1000000) // if < 1 MHz, then it's the sample rate, not the clock - clock *= 512; // (for backwards compatibility with old VGM logs) - - // init the emulation - //SCSP_Init(device, scsp, intf); - SCSP_Init(scsp, clock); - - // set up the IRQ callbacks - /*{ - scsp->Int68kCB = intf->irq_callback; - - scsp->stream = device->machine().sound().stream_alloc(*device, 0, 2, 44100, scsp, SCSP_Update); + void * info = malloc(SCSPRAM_LENGTH + yam_get_state_size(1)); + if (info) { + memset(SCSPRAM, 0, SCSPRAM_LENGTH); + device_reset_scsp(info); + *_info = info; } - - scsp->main_irq.resolve(intf->main_irq, *device);*/ - - return scsp->rate; // 44100 + return 44100; } -void device_stop_scsp(void *_info) +void device_stop_scsp(void *info) { - scsp_state *scsp = (scsp_state *)_info; - - free(scsp->SCSPRAM); scsp->SCSPRAM = NULL; - - free(scsp); - - return; + free(info); } -void device_reset_scsp(void *_info) +void device_reset_scsp(void *info) { - scsp_state *scsp = (scsp_state *)_info; - int i; - - // make sure all the slots are off - for(i=0;i<32;++i) - { - scsp->Slots[i].slot=i; - scsp->Slots[i].active=0; - scsp->Slots[i].base=NULL; - scsp->Slots[i].EG.state=RELEASE; - } - - SCSPDSP_Init(&scsp->DSP); - scsp->DSP.SCSPRAM_LENGTH = scsp->SCSPRAM_LENGTH / 2; - scsp->DSP.SCSPRAM = (UINT16*)scsp->SCSPRAM; - - return; + yam_clear_state(YAMSTATE, 1); + yam_setram(YAMSTATE, (uint32*)info, SCSPRAM_LENGTH, 0, EMU_ENDIAN_XOR(1) ^ 1); + yam_enable_dry(YAMSTATE, 1); + yam_enable_dsp(YAMSTATE, 1); + yam_enable_dsp_dynarec(YAMSTATE, 0); } @@ -1538,32 +75,24 @@ void device_reset_scsp(void *_info) //READ16_DEVICE_HANDLER( scsp_r ) -UINT16 scsp_r(void *_info, offs_t offset) +UINT16 scsp_r(void *info, offs_t offset) { - //scsp_state *scsp = get_safe_token(device); - scsp_state *scsp = (scsp_state *)_info; - - //scsp->stream->update(); - - return SCSP_r16(scsp, offset*2); + return yam_scsp_load_reg(YAMSTATE, offset*2, 0xFFFF); } //WRITE16_DEVICE_HANDLER( scsp_w ) -void scsp_w(void *_info, offs_t offset, UINT8 data) +void scsp_w(void *info, offs_t offset, UINT8 data) { - //scsp_state *scsp = get_safe_token(device); - scsp_state *scsp = (scsp_state *)_info; + UINT8 tmp8; UINT16 tmp; - //scsp->stream->update(); - - tmp = SCSP_r16(scsp, offset & 0xFFFE); + tmp = yam_scsp_load_reg(YAMSTATE, offset & 0xFFFE, 0xFFFF); //COMBINE_DATA(&tmp); if (offset & 1) tmp = (tmp & 0xFF00) | (data << 0); else tmp = (tmp & 0x00FF) | (data << 8); - SCSP_w16(scsp,offset & 0xFFFE, tmp); + yam_scsp_store_reg(YAMSTATE, offset & 0xFFFE, tmp, 0xFFFF, &tmp8); } /*WRITE16_DEVICE_HANDLER( scsp_midi_in ) @@ -1612,30 +141,24 @@ READ16_DEVICE_HANDLER( scsp_midi_out_r ) return; }*/ -void scsp_write_ram(void *_info, offs_t DataStart, offs_t DataLength, const UINT8* RAMData) +void scsp_write_ram(void *info, offs_t DataStart, offs_t DataLength, const UINT8* RAMData) { - scsp_state *scsp = (scsp_state *)_info; - - if (DataStart >= scsp->SCSPRAM_LENGTH) + if (DataStart >= SCSPRAM_LENGTH) return; - if (DataStart + DataLength > scsp->SCSPRAM_LENGTH) - DataLength = scsp->SCSPRAM_LENGTH - DataStart; + if (DataStart + DataLength > SCSPRAM_LENGTH) + DataLength = SCSPRAM_LENGTH - DataStart; - memcpy(scsp->SCSPRAM + DataStart, RAMData, DataLength); + memcpy(SCSPRAM + DataStart, RAMData, DataLength); return; } -void scsp_set_mute_mask(void *_info, UINT32 MuteMask) +void scsp_set_mute_mask(void *info, UINT32 MuteMask) { - scsp_state *scsp = (scsp_state *)_info; - UINT8 CurChn; - + int CurChn; for (CurChn = 0; CurChn < 32; CurChn ++) - scsp->Slots[CurChn].Muted = (MuteMask >> CurChn) & 0x01; - - return; + yam_set_mute(YAMSTATE, CurChn, (MuteMask >> CurChn) & 0x01); } /*UINT8 scsp_get_channels(void *_info, UINT32* ChannelMask) diff --git a/Frameworks/GME/vgmplay/chips/scspdsp.c b/Frameworks/GME/vgmplay/chips/scspdsp.c deleted file mode 100644 index 830ab7fff..000000000 --- a/Frameworks/GME/vgmplay/chips/scspdsp.c +++ /dev/null @@ -1,356 +0,0 @@ -//#include "emu.h" -#include // for memset -#include "mamedef.h" -#include "scsp.h" -#include "scspdsp.h" - -static UINT16 PACK(INT32 val) -{ - UINT32 temp; - int sign,exponent,k; - - sign = (val >> 23) & 0x1; - temp = (val ^ (val << 1)) & 0xFFFFFF; - exponent = 0; - for (k=0; k<12; k++) - { - if (temp & 0x800000) - break; - temp <<= 1; - exponent += 1; - } - if (exponent < 12) - val = (val << exponent) & 0x3FFFFF; - else - val <<= 11; - val >>= 11; - val &= 0x7FF; - val |= sign << 15; - val |= exponent << 11; - - return (UINT16)val; -} - -static INT32 UNPACK(UINT16 val) -{ - int sign,exponent,mantissa; - INT32 uval; - - sign = (val >> 15) & 0x1; - exponent = (val >> 11) & 0xF; - mantissa = val & 0x7FF; - uval = mantissa << 11; - if (exponent > 11) - { - exponent = 11; - uval |= sign << 22; - } - else - uval |= (sign ^ 1) << 22; - uval |= sign << 23; - uval <<= 8; - uval >>= 8; - uval >>= exponent; - - return uval; -} - -void SCSPDSP_Init(struct _SCSPDSP *DSP) -{ - memset(DSP,0,sizeof(struct _SCSPDSP)); - DSP->RBL=0x8000; - DSP->Stopped=1; -} - -void SCSPDSP_Step(struct _SCSPDSP *DSP) -{ - INT32 ACC=0; //26 bit - INT32 SHIFTED=0; //24 bit - INT32 X=0; //24 bit - INT32 Y=0; //13 bit - INT32 B=0; //26 bit - INT32 INPUTS=0; //24 bit - INT32 MEMVAL=0; - INT32 FRC_REG=0; //13 bit - INT32 Y_REG=0; //24 bit - UINT32 ADDR=0; - UINT32 ADRS_REG=0; //13 bit - int step; - - if(DSP->Stopped) - return; - - memset(DSP->EFREG,0,2*16); -#if 0 - int dump=0; - FILE *f=NULL; - if(dump) - f=fopen("dsp.txt","wt"); -#endif - for(step=0;stepLastStep;++step) - { - UINT16 *IPtr=DSP->MPRO+step*4; - -// if(IPtr[0]==0 && IPtr[1]==0 && IPtr[2]==0 && IPtr[3]==0) -// break; - - UINT32 TRA=(IPtr[0]>>8)&0x7F; - UINT32 TWT=(IPtr[0]>>7)&0x01; - UINT32 TWA=(IPtr[0]>>0)&0x7F; - - UINT32 XSEL=(IPtr[1]>>15)&0x01; - UINT32 YSEL=(IPtr[1]>>13)&0x03; - UINT32 IRA=(IPtr[1]>>6)&0x3F; - UINT32 IWT=(IPtr[1]>>5)&0x01; - UINT32 IWA=(IPtr[1]>>0)&0x1F; - - UINT32 TABLE=(IPtr[2]>>15)&0x01; - UINT32 MWT=(IPtr[2]>>14)&0x01; - UINT32 MRD=(IPtr[2]>>13)&0x01; - UINT32 EWT=(IPtr[2]>>12)&0x01; - UINT32 EWA=(IPtr[2]>>8)&0x0F; - UINT32 ADRL=(IPtr[2]>>7)&0x01; - UINT32 FRCL=(IPtr[2]>>6)&0x01; - UINT32 SHIFT=(IPtr[2]>>4)&0x03; - UINT32 YRL=(IPtr[2]>>3)&0x01; - UINT32 NEGB=(IPtr[2]>>2)&0x01; - UINT32 ZERO=(IPtr[2]>>1)&0x01; - UINT32 BSEL=(IPtr[2]>>0)&0x01; - - UINT32 NOFL=(IPtr[3]>>15)&1; //???? - UINT32 COEF=(IPtr[3]>>9)&0x3f; - - UINT32 MASA=(IPtr[3]>>2)&0x1f; //??? - UINT32 ADREB=(IPtr[3]>>1)&0x1; - UINT32 NXADR=(IPtr[3]>>0)&0x1; - - INT64 v; - - //operations are done at 24 bit precision -#if 0 - if(MASA) - int a=1; - if(NOFL) - int a=1; - -// int dump=0; - - if(f) - { -#define DUMP(v) fprintf(f," " #v ": %04X",v); - - fprintf(f,"%d: ",step); - DUMP(ACC); - DUMP(SHIFTED); - DUMP(X); - DUMP(Y); - DUMP(B); - DUMP(INPUTS); - DUMP(MEMVAL); - DUMP(FRC_REG); - DUMP(Y_REG); - DUMP(ADDR); - DUMP(ADRS_REG); - fprintf(f,"\n"); - } -#endif - //INPUTS RW -// colmns97 hits this -// assert(IRA<0x32); - if(IRA<=0x1f) - INPUTS=DSP->MEMS[IRA]; - else if(IRA<=0x2F) - INPUTS=DSP->MIXS[IRA-0x20]<<4; //MIXS is 20 bit - else if(IRA<=0x31) - INPUTS=0; - else - return; - - INPUTS<<=8; - INPUTS>>=8; - //if(INPUTS&0x00800000) - // INPUTS|=0xFF000000; - - if(IWT) - { - DSP->MEMS[IWA]=MEMVAL; //MEMVAL was selected in previous MRD - if(IRA==IWA) - INPUTS=MEMVAL; - } - - //Operand sel - //B - if(!ZERO) - { - if(BSEL) - B=ACC; - else - { - B=DSP->TEMP[(TRA+DSP->DEC)&0x7F]; - B<<=8; - B>>=8; - //if(B&0x00800000) - // B|=0xFF000000; //Sign extend - } - if(NEGB) - B=0-B; - } - else - B=0; - - //X - if(XSEL) - X=INPUTS; - else - { - X=DSP->TEMP[(TRA+DSP->DEC)&0x7F]; - X<<=8; - X>>=8; - //if(X&0x00800000) - // X|=0xFF000000; - } - - //Y - if(YSEL==0) - Y=FRC_REG; - else if(YSEL==1) - Y=DSP->COEF[COEF]>>3; //COEF is 16 bits - else if(YSEL==2) - Y=(Y_REG>>11)&0x1FFF; - else if(YSEL==3) - Y=(Y_REG>>4)&0x0FFF; - - if(YRL) - Y_REG=INPUTS; - - //Shifter - if(SHIFT==0) - { - SHIFTED=ACC; - if(SHIFTED>0x007FFFFF) - SHIFTED=0x007FFFFF; - if(SHIFTED<(-0x00800000)) - SHIFTED=-0x00800000; - } - else if(SHIFT==1) - { - SHIFTED=ACC*2; - if(SHIFTED>0x007FFFFF) - SHIFTED=0x007FFFFF; - if(SHIFTED<(-0x00800000)) - SHIFTED=-0x00800000; - } - else if(SHIFT==2) - { - SHIFTED=ACC*2; - SHIFTED<<=8; - SHIFTED>>=8; - //SHIFTED&=0x00FFFFFF; - //if(SHIFTED&0x00800000) - // SHIFTED|=0xFF000000; - } - else if(SHIFT==3) - { - SHIFTED=ACC; - SHIFTED<<=8; - SHIFTED>>=8; - //SHIFTED&=0x00FFFFFF; - //if(SHIFTED&0x00800000) - // SHIFTED|=0xFF000000; - } - - //ACCUM - Y<<=19; - Y>>=19; - //if(Y&0x1000) - // Y|=0xFFFFF000; - - v=(((INT64) X*(INT64) Y)>>12); - ACC=(int) v+B; - - if(TWT) - DSP->TEMP[(TWA+DSP->DEC)&0x7F]=SHIFTED; - - if(FRCL) - { - if(SHIFT==3) - FRC_REG=SHIFTED&0x0FFF; - else - FRC_REG=(SHIFTED>>11)&0x1FFF; - } - - if(MRD || MWT) - //if(0) - { - ADDR=DSP->MADRS[MASA]; - if(!TABLE) - ADDR+=DSP->DEC; - if(ADREB) - ADDR+=ADRS_REG&0x0FFF; - if(NXADR) - ADDR++; - if(!TABLE) - ADDR&=DSP->RBL-1; - else - ADDR&=0xFFFF; - //ADDR<<=1; - //ADDR+=DSP->RBP<<13; - //MEMVAL=DSP->SCSPRAM[ADDR>>1]; - ADDR+=DSP->RBP<<12; - if (ADDR > 0x7ffff) ADDR = 0; - if(MRD && (step&1)) //memory only allowed on odd? DoA inserts NOPs on even - { - if(NOFL) - MEMVAL=DSP->SCSPRAM[ADDR]<<8; - else - MEMVAL=UNPACK(DSP->SCSPRAM[ADDR]); - } - if(MWT && (step&1)) - { - if(NOFL) - DSP->SCSPRAM[ADDR]=SHIFTED>>8; - else - DSP->SCSPRAM[ADDR]=PACK(SHIFTED); - } - } - - if(ADRL) - { - if(SHIFT==3) - ADRS_REG=(SHIFTED>>12)&0xFFF; - else - ADRS_REG=(INPUTS>>16); - } - - if(EWT) - DSP->EFREG[EWA]+=SHIFTED>>8; - - } - --DSP->DEC; - memset(DSP->MIXS,0,4*16); -// if(f) -// fclose(f); -} - -void SCSPDSP_SetSample(struct _SCSPDSP *DSP,INT32 sample,int SEL,int MXL) -{ - //DSP->MIXS[SEL]+=sample<<(MXL+1)/*7*/; - DSP->MIXS[SEL]+=sample; -// if(MXL) -// int a=1; -} - -void SCSPDSP_Start(struct _SCSPDSP *DSP) -{ - int i; - DSP->Stopped=0; - for(i=127;i>=0;--i) - { - UINT16 *IPtr=DSP->MPRO+i*4; - - if(IPtr[0]!=0 || IPtr[1]!=0 || IPtr[2]!=0 || IPtr[3]!=0) - break; - } - DSP->LastStep=i+1; - -} diff --git a/Frameworks/GME/vgmplay/chips/scspdsp.h b/Frameworks/GME/vgmplay/chips/scspdsp.h deleted file mode 100644 index 5040aa17c..000000000 --- a/Frameworks/GME/vgmplay/chips/scspdsp.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#ifndef __SCSPDSP_H__ -#define __SCSPDSP_H__ - -//the DSP Context -struct _SCSPDSP -{ -//Config - UINT16 *SCSPRAM; - UINT32 SCSPRAM_LENGTH; - UINT32 RBP; //Ring buf pointer - UINT32 RBL; //Delay ram (Ring buffer) size in words - -//context - - INT16 COEF[64]; //16 bit signed - UINT16 MADRS[32]; //offsets (in words), 16 bit - UINT16 MPRO[128*4]; //128 steps 64 bit - INT32 TEMP[128]; //TEMP regs,24 bit signed - INT32 MEMS[32]; //MEMS regs,24 bit signed - UINT32 DEC; - -//input - INT32 MIXS[16]; //MIXS, 24 bit signed - INT16 EXTS[2]; //External inputs (CDDA) 16 bit signed - -//output - INT16 EFREG[16]; //EFREG, 16 bit signed - - int Stopped; - int LastStep; -}; - -void SCSPDSP_Init(struct _SCSPDSP *DSP); -void SCSPDSP_SetSample(struct _SCSPDSP *DSP, INT32 sample, INT32 SEL, INT32 MXL); -void SCSPDSP_Step(struct _SCSPDSP *DSP); -void SCSPDSP_Start(struct _SCSPDSP *DSP); - -#endif /* __SCSPDSP_H__ */ diff --git a/Frameworks/GME/vgmplay/chips/scsplfo.c b/Frameworks/GME/vgmplay/chips/scsplfo.c deleted file mode 100644 index fde300da8..000000000 --- a/Frameworks/GME/vgmplay/chips/scsplfo.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - SCSP LFO handling - - Part of the SCSP (YMF292-F) emulator package. - (not compiled directly, #included from scsp.c) - - By ElSemi - MAME/M1 conversion and cleanup by R. Belmont -*/ - -#define LFO_SHIFT 8 - -struct _LFO -{ - unsigned short phase; - UINT32 phase_step; - int *table; - int *scale; -}; - -#define LFIX(v) ((unsigned int) ((float) (1<phase+=LFO->phase_step; -#if LFO_SHIFT!=8 - LFO->phase&=(1<<(LFO_SHIFT+8))-1; -#endif - p=LFO->table[LFO->phase>>LFO_SHIFT]; - p=LFO->scale[p+128]; - return p<<(SHIFT-LFO_SHIFT); -} - -INLINE signed int ALFO_Step(struct _LFO *LFO) -{ - int p; - LFO->phase+=LFO->phase_step; -#if LFO_SHIFT!=8 - LFO->phase&=(1<<(LFO_SHIFT+8))-1; -#endif - p=LFO->table[LFO->phase>>LFO_SHIFT]; - p=LFO->scale[p]; - return p<<(SHIFT-LFO_SHIFT); -} - -static void LFO_ComputeStep(struct _LFO *LFO,UINT32 LFOF,UINT32 LFOWS,UINT32 LFOS,int ALFO) -{ - float step=(float) LFOFreq[LFOF]*256.0/(float)44100; - LFO->phase_step=(unsigned int) ((float) (1<table=ALFO_SAW; break; - case 1: LFO->table=ALFO_SQR; break; - case 2: LFO->table=ALFO_TRI; break; - case 3: LFO->table=ALFO_NOI; break; - } - LFO->scale=ASCALES[LFOS]; - } - else - { - switch(LFOWS) - { - case 0: LFO->table=PLFO_SAW; break; - case 1: LFO->table=PLFO_SQR; break; - case 2: LFO->table=PLFO_TRI; break; - case 3: LFO->table=PLFO_NOI; break; - } - LFO->scale=PSCALES[LFOS]; - } -} diff --git a/Frameworks/GME/vgmplay/chips/segapcm.c b/Frameworks/GME/vgmplay/chips/segapcm.c index 154e06e04..4deabb030 100644 --- a/Frameworks/GME/vgmplay/chips/segapcm.c +++ b/Frameworks/GME/vgmplay/chips/segapcm.c @@ -3,7 +3,7 @@ /*********************************************************/ #include "mamedef.h" -#include +#include #include #include //#include "sndintrf.h" diff --git a/Frameworks/GME/vgmplay/chips/sn76489.c b/Frameworks/GME/vgmplay/chips/sn76489.c index 4f9fd7f8a..5b90611de 100644 --- a/Frameworks/GME/vgmplay/chips/sn76489.c +++ b/Frameworks/GME/vgmplay/chips/sn76489.c @@ -32,7 +32,7 @@ static const int PSGVolumeValues[16] = { /* These values are taken from a real SMS2's output */ -/* {892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */ +/* {892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0},*/ /* I can't remember why 892... :P some scaling I did at some point */ /* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1) */ /*1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0*/ // The MAME core uses 0x2000 as maximum volume (0x1000 for bipolar output) diff --git a/Frameworks/GME/vgmplay/chips/sn76496.c b/Frameworks/GME/vgmplay/chips/sn76496.c index 854b3e49d..99d0b2a4d 100644 --- a/Frameworks/GME/vgmplay/chips/sn76496.c +++ b/Frameworks/GME/vgmplay/chips/sn76496.c @@ -124,11 +124,13 @@ #endif //#include "emu.h" //#include "streams.h" -#include +#include #include #include "sn76496.h" +#ifndef NULL #define NULL ((void *)0) +#endif //#define MAX_OUTPUT 0x7fff @@ -418,7 +420,7 @@ void SN76496Update(void *chip, stream_sample_t **outputs, int samples) out += vol[i] * R->Volume[i] * ggst[0]; out2 += vol[i] * R->Volume[i] * ggst[1]; } - else + else if (R->MuteMsk[i]) { // Make Bipolar Output with PCM possible //out += (2 * R->Volume[i] - R->VolTable[5]) * ggst[0]; @@ -458,7 +460,7 @@ void SN76496Update(void *chip, stream_sample_t **outputs, int samples) out += vol[i] * R->Volume[i] * ggst[0]; out2 += vol[i] * R2->Volume[i] * ggst[1]; } - else + else if (R->MuteMsk[i]) { // Make Bipolar Output with PCM possible out += R->Volume[i] * ggst[0]; @@ -870,7 +872,7 @@ DEVICE_GET_INFO( smsiii ) case DEVINFO_STR_NAME: strcpy(info->s, "SMSIII PSG"); break; default: DEVICE_GET_INFO_CALL(sn76496); break; } -} +}*/ /*DEFINE_LEGACY_SOUND_DEVICE(SN76496, sn76496); diff --git a/Frameworks/GME/vgmplay/chips/sn764intf.c b/Frameworks/GME/vgmplay/chips/sn764intf.c index 2177e892c..225f143bf 100644 --- a/Frameworks/GME/vgmplay/chips/sn764intf.c +++ b/Frameworks/GME/vgmplay/chips/sn764intf.c @@ -18,7 +18,9 @@ #define EC_MAXIM 0x01 // SN76489 core by Maxim (from in_vgm) #endif +#ifndef NULL #define NULL ((void *)0) +#endif /* for stream system */ typedef struct _sn764xx_state sn764xx_state; diff --git a/Frameworks/GME/vgmplay/chips/upd7759.c b/Frameworks/GME/vgmplay/chips/upd7759.c index 9b6e80289..f7a1fe35d 100644 --- a/Frameworks/GME/vgmplay/chips/upd7759.c +++ b/Frameworks/GME/vgmplay/chips/upd7759.c @@ -102,12 +102,14 @@ #ifdef _DEBUG #include #endif -#include +#include #include #include "mamedef.h" #include "upd7759.h" +#ifndef NULL #define NULL ((void *)0) +#endif #define DEBUG_STATES (0) @@ -279,7 +281,9 @@ static void get_fifo_data(upd7759_state *chip) { if (chip->dbuf_pos_read == chip->dbuf_pos_write) { +#ifdef _DEBUG logerror("Warning: UPD7759 reading empty FIFO!\n"); +#endif return; } @@ -312,7 +316,9 @@ static void advance_state(upd7759_state *chip) /* Start state: we begin here as soon as a sample is triggered */ case STATE_START: chip->req_sample = chip->rom ? chip->fifo_in : 0x10; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: req_sample = %02X\n", chip->req_sample); +#endif /* 35+ cycles after we get here, the /DRQ goes low * (first byte (number of samples in ROM) should be sent in response) @@ -328,7 +334,9 @@ static void advance_state(upd7759_state *chip) /* First request state: issue a request for the first byte */ /* The expected response will be the index of the last sample */ case STATE_FIRST_REQ: +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: first data request\n"); +#endif chip->drq = 1; /* 44 cycles later, we will latch this value and request another byte */ @@ -340,7 +348,9 @@ static void advance_state(upd7759_state *chip) /* The second byte read will be just a dummy */ case STATE_LAST_SAMPLE: chip->last_sample = chip->rom ? chip->rom[0] : chip->fifo_in; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: last_sample = %02X, requesting dummy 1\n", chip->last_sample); +#endif chip->drq = 1; /* 28 cycles later, we will latch this value and request another byte */ @@ -351,7 +361,9 @@ static void advance_state(upd7759_state *chip) /* First dummy state: ignore any data here and issue a request for the third byte */ /* The expected response will be the MSB of the sample address */ case STATE_DUMMY1: +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: dummy1, requesting offset_hi\n"); +#endif chip->drq = 1; /* 32 cycles later, we will latch this value and request another byte */ @@ -363,7 +375,9 @@ static void advance_state(upd7759_state *chip) /* The expected response will be the LSB of the sample address */ case STATE_ADDR_MSB: chip->offset = (chip->rom ? chip->rom[chip->req_sample * 2 + 5] : chip->fifo_in) << 9; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: offset_hi = %02X, requesting offset_lo\n", chip->offset >> 9); +#endif chip->drq = 1; /* 44 cycles later, we will latch this value and request another byte */ @@ -375,7 +389,9 @@ static void advance_state(upd7759_state *chip) /* The expected response will be just a dummy */ case STATE_ADDR_LSB: chip->offset |= (chip->rom ? chip->rom[chip->req_sample * 2 + 6] : chip->fifo_in) << 1; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: offset_lo = %02X, requesting dummy 2\n", (chip->offset >> 1) & 0xff); +#endif chip->drq = 1; /* 36 cycles later, we will latch this value and request another byte */ @@ -388,7 +404,9 @@ static void advance_state(upd7759_state *chip) case STATE_DUMMY2: chip->offset++; chip->first_valid_header = 0; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: dummy2, requesting block header\n"); +#endif chip->drq = 1; /* 36?? cycles later, we will latch this value and request another byte */ @@ -406,7 +424,9 @@ static void advance_state(upd7759_state *chip) chip->offset = chip->repeat_offset; } chip->block_header = chip->rom ? chip->rom[chip->offset++ & 0x1ffff] : chip->fifo_in; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: header (@%05X) = %02X, requesting next byte\n", chip->offset, chip->block_header); +#endif chip->drq = 1; /* our next step depends on the top two bits */ @@ -449,7 +469,9 @@ static void advance_state(upd7759_state *chip) /* The expected response will be the first data byte */ case STATE_NIBBLE_COUNT: chip->nibbles_left = (chip->rom ? chip->rom[chip->offset++ & 0x1ffff] : chip->fifo_in) + 1; +#ifdef _DEBUG if (DEBUG_STATES) DEBUG_METHOD("UPD7759: nibble_count = %u, requesting next byte\n", (unsigned)chip->nibbles_left); +#endif chip->drq = 1; /* 36?? cycles later, we will latch this value and request another byte */ @@ -684,11 +706,11 @@ void device_reset_upd7759(void *_info) //static STATE_POSTLOAD( upd7759_postload ) -static void upd7759_postload(void* param) +/*static void upd7759_postload(void* param) { upd7759_state *chip = (upd7759_state *)param; chip->rom = chip->rombase + chip->romoffset; -} +}*/ /*static void register_for_save(upd7759_state *chip, running_device *device) @@ -727,9 +749,9 @@ static void upd7759_postload(void* param) //static DEVICE_START( upd7759 ) int device_start_upd7759(void **_info, int clock) { - static const upd7759_interface defintrf = { 0 }; + //static const upd7759_interface defintrf = { 0 }; //const upd7759_interface *intf = (device->baseconfig().static_config() != NULL) ? (const upd7759_interface *)device->baseconfig().static_config() : &defintrf; - const upd7759_interface *intf = &defintrf; + //const upd7759_interface *intf = &defintrf; //upd7759_state *chip = get_safe_token(device); upd7759_state *chip; @@ -820,7 +842,9 @@ void upd7759_start_w(void *_info, UINT8 data) UINT8 oldstart = chip->start; chip->start = (data != 0); +#ifdef _DEBUG if (DEBUG_STATES) logerror("upd7759_start_w: %d->%d\n", oldstart, chip->start); +#endif /* update the stream first */ //stream_update(chip->channel); diff --git a/Frameworks/GME/vgmplay/chips/vsu.c b/Frameworks/GME/vgmplay/chips/vsu.c index 87fab949a..5df92acb9 100644 --- a/Frameworks/GME/vgmplay/chips/vsu.c +++ b/Frameworks/GME/vgmplay/chips/vsu.c @@ -16,7 +16,7 @@ */ //#include "vb.h" -#include +#include #include #include "mamedef.h" #include "vsu.h" diff --git a/Frameworks/GME/vgmplay/chips/ws_audio.c b/Frameworks/GME/vgmplay/chips/ws_audio.c index 28e9b0f0d..747e2bee6 100644 --- a/Frameworks/GME/vgmplay/chips/ws_audio.c +++ b/Frameworks/GME/vgmplay/chips/ws_audio.c @@ -1,6 +1,6 @@ #include -#include +#include #include // for NULL #include "mamedef.h" diff --git a/Frameworks/GME/vgmplay/chips/x1_010.c b/Frameworks/GME/vgmplay/chips/x1_010.c index 5da0df5b5..f6e0b932a 100644 --- a/Frameworks/GME/vgmplay/chips/x1_010.c +++ b/Frameworks/GME/vgmplay/chips/x1_010.c @@ -50,7 +50,7 @@ Registers: //#include "emu.h" #include -#include +#include #include // for NULL #include "mamedef.h" #include "x1_010.h" @@ -66,7 +66,8 @@ Registers: #define SETA_NUM_CHANNELS 16 -#define FREQ_BASE_BITS 8 // Frequency fixed decimal shift bits +//#define FREQ_BASE_BITS 8 // Frequency fixed decimal shift bits +#define FREQ_BASE_BITS 14 // Frequency fixed decimal shift bits #define ENV_BASE_BITS 16 // wave form envelope fixed decimal shift bits #define VOL_BASE (2*32*256/30) // Volume base @@ -148,17 +149,19 @@ void seta_update(void *param, stream_sample_t **outputs, int samples) // Meta Fox does write the frequency register, but this is a hack to make it "work" with the current setup // This is broken for Arbalester (it writes 8), but that'll be fixed later. if( freq == 0 ) freq = 4; - smp_step = (UINT32)((float)info->base_clock/8192.0 - *freq*(1<rate); + smp_step = (UINT32)((float)info->base_clock/8192.0f + *freq*(1<rate+0.5f); +#ifdef _DEBUG if( smp_offs == 0 ) { LOG_SOUND(( "Play sample %p - %p, channel %X volume %d:%d freq %X step %X offset %X\n", start, end, ch, volL, volR, freq, smp_step, smp_offs )); } +#endif for( i = 0; i < samples; i++ ) { delta = smp_offs>>FREQ_BASE_BITS; // sample ended? if( start+delta >= end ) { - reg->status &= 0xfe; // Key off + reg->status &= ~0x01; // Key off break; } data = *(start+delta); @@ -171,22 +174,24 @@ void seta_update(void *param, stream_sample_t **outputs, int samples) start = (INT8 *)&(info->reg[reg->volume*128+0x1000]); smp_offs = info->smp_offset[ch]; freq = ((reg->pitch_hi<<8)+reg->frequency)>>div; - smp_step = (UINT32)((float)info->base_clock/128.0/1024.0/4.0*freq*(1<rate); + smp_step = (UINT32)((float)info->base_clock/128.0/1024.0/4.0*freq*(1<rate+0.5f); env = (UINT8 *)&(info->reg[reg->end*128]); env_offs = info->env_offset[ch]; - env_step = (UINT32)((float)info->base_clock/128.0/1024.0/4.0*reg->start*(1<rate); + env_step = (UINT32)((float)info->base_clock/128.0/1024.0/4.0*reg->start*(1<rate+0.5f); /* Print some more debug info */ +#ifdef _DEBUG if( smp_offs == 0 ) { LOG_SOUND(( "Play waveform %X, channel %X volume %X freq %4X step %X offset %X\n", reg->volume, ch, reg->end, freq, smp_step, smp_offs )); } +#endif for( i = 0; i < samples; i++ ) { int vol; delta = env_offs>>ENV_BASE_BITS; // Envelope one shot mode if( (reg->status&4) != 0 && delta >= 0x80 ) { - reg->status &= 0xfe; // Key off + reg->status &= ~0x01; // Key off break; } vol = *(env+(delta&0x7f)); diff --git a/Frameworks/GME/vgmplay/chips/yam.c b/Frameworks/GME/vgmplay/chips/yam.c new file mode 100644 index 000000000..8b7db7b3f --- /dev/null +++ b/Frameworks/GME/vgmplay/chips/yam.c @@ -0,0 +1,3076 @@ +///////////////////////////////////////////////////////////////////////////// +// +// yam - Emulates Yamaha SCSP and AICA +// +///////////////////////////////////////////////////////////////////////////// + +#define EMU_COMPILE + +#ifdef VGMPLAY_BIG_ENDIAN +#define EMU_BIG_ENDIAN +#else +#define EMU_LITTLE_ENDIAN +#endif + +#ifndef EMU_COMPILE +#error "Hi I forgot to set EMU_COMPILE" +#endif + +#include "yam.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#elif defined(HAVE_MPROTECT) +#include +#include +#include +#endif + +#include +#include + +#ifndef _WIN32 +#define __cdecl +#define __fastcall __attribute__((regparm(3))) +#endif + +/* No dynarec for x86_64 yet */ +#if defined(_WIN32) || defined(__i386__) +#define ENABLE_DYNAREC +#endif +#if defined(_WIN64) || defined(__amd64__) +#undef ENABLE_DYNAREC +#endif + +// no 'conversion from _blah_ possible loss of data' warnings +#ifdef _MSC_VER +#pragma warning (disable: 4244) +#endif + +///////////////////////////////////////////////////////////////////////////// + +#define RENDERMAX (200) +#define RINGMAX (256) // should be nearest power of two that's at least one greater than RENDERMAX + +///////////////////////////////////////////////////////////////////////////// + +#define INT_ONE_SAMPLE (10) +#define INT_MIDI_OUTPUT (9) +#define INT_TIMER_C (8) +#define INT_TIMER_B (7) +#define INT_TIMER_A (6) +#define INT_CPU (5) +#define INT_DMA_END (4) +#define INT_MIDI_INPUT (3) +#define INT_RESERVED_2 (2) +#define INT_RESERVED_1 (1) +#define INT_EXTERNAL (0) + +///////////////////////////////////////////////////////////////////////////// +// +// Static information +// + +#define MAKELFOPHASEINC(x) (((uint64)(0x100000000)) / ((uint64)(x))) + +static uint32 lfophaseinctable[0x20] = { +MAKELFOPHASEINC(0x3FC00),MAKELFOPHASEINC(0x37C00),MAKELFOPHASEINC(0x2FC00),MAKELFOPHASEINC(0x27C00), +MAKELFOPHASEINC(0x1FC00),MAKELFOPHASEINC(0x1BC00),MAKELFOPHASEINC(0x17C00),MAKELFOPHASEINC(0x13C00), +MAKELFOPHASEINC(0x0FC00),MAKELFOPHASEINC(0x0BC00),MAKELFOPHASEINC(0x0DC00),MAKELFOPHASEINC(0x09C00), +MAKELFOPHASEINC(0x07C00),MAKELFOPHASEINC(0x06C00),MAKELFOPHASEINC(0x05C00),MAKELFOPHASEINC(0x04C00), +MAKELFOPHASEINC(0x03C00),MAKELFOPHASEINC(0x03400),MAKELFOPHASEINC(0x02C00),MAKELFOPHASEINC(0x02400), +MAKELFOPHASEINC(0x01C00),MAKELFOPHASEINC(0x01800),MAKELFOPHASEINC(0x01400),MAKELFOPHASEINC(0x01000), +MAKELFOPHASEINC(0x00C00),MAKELFOPHASEINC(0x00A00),MAKELFOPHASEINC(0x00800),MAKELFOPHASEINC(0x00600), +MAKELFOPHASEINC(0x00400),MAKELFOPHASEINC(0x00300),MAKELFOPHASEINC(0x00200),MAKELFOPHASEINC(0x00100) +}; + +static uint8 envattackshift[0x3D][4] = { +/* 00-07 */ {4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}, +/* 08-0F */ {4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}, +/* 10-17 */ {4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}, +/* 18-1F */ {4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}, +/* 20-27 */ {4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}, +/* 28-2F */ {4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}, +/* 30-37 */ {4,4,4,4},{3,4,4,4},{3,4,3,4},{3,3,3,4},{3,3,3,3},{2,3,3,3},{2,3,2,3},{2,2,2,3}, +/* 38-3C */ {2,2,2,2},{1,2,2,2},{1,2,1,2},{1,1,1,2},{1,1,1,1} +}; + +static uint8 envdecayvalue[0x3D][4] = { +/* 00-07 */ {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, +/* 08-0F */ {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, +/* 10-17 */ {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, +/* 18-1F */ {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, +/* 20-27 */ {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, +/* 28-2F */ {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, +/* 30-37 */ {1,1,1,1},{2,1,1,1},{2,1,2,1},{2,2,2,1},{2,2,2,2},{4,2,2,2},{4,2,4,2},{4,4,4,2}, +/* 38-3C */ {4,4,4,4},{8,4,4,4},{8,4,8,4},{8,8,8,4},{8,8,8,8} +}; + +static sint32 adpcmscale[8] = { + 0x0E6, 0x0E6, 0x0E6, 0x0E6, 0x133, 0x199, 0x200, 0x266 +}; + +static sint32 adpcmdiff[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, +-1,-3,-5,-7,-9,-11,-13,-15 +}; + +static sint32 qtable[32] = { +0x0E00,0x0E80,0x0F00,0x0F80, +0x1000,0x1080,0x1100,0x1180, +0x1200,0x1280,0x1300,0x1280, +0x1400,0x1480,0x1500,0x1580, +0x1600,0x1680,0x1700,0x1780, +0x1800,0x1880,0x1900,0x1980, +0x1A00,0x1A80,0x1B00,0x1B80, +0x1C00,0x1D00,0x1E00,0x1F00 +}; + +static uint8 pan_att_l[32] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +static uint8 pan_att_r[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,32 }; + +static void convert_stereo_send_level( + uint8 sdl, uint8 pan, + uint8 *att_l, uint8 *att_r, + sint32 *lin_l, sint32 *lin_r +) { + uint8 al = 0, ar = 0; + sint32 ll = 0, lr = 0; + sdl &= 0xF; + if(sdl) { + pan &= 0x1F; + al = sdl ^ 0xF; + ar = sdl ^ 0xF; + al += pan_att_l[pan]; + ar += pan_att_r[pan]; + ll = 4 - (al & 1); + lr = 4 - (ar & 1); + al >>= 1; al += 2; + ar >>= 1; ar += 2; + if(al >= 16) { al = 0; ll = 0; } + if(ar >= 16) { ar = 0; lr = 0; } + } + *att_l = al; + *att_r = ar; + *lin_l = ll; + *lin_r = lr; +} + +///////////////////////////////////////////////////////////////////////////// + +sint32 EMU_CALL yam_init(void) { + return 0; +} + +///////////////////////////////////////////////////////////////////////////// +/* +static int gfreq[201]; + +void yam_debugoutput(void) { + int i; + int t=0; + int u=0; + for(i=0;i<201;i++) { + printf("gfreq[%3d]=%d\n",i,gfreq[i]); + t += i*gfreq[i]; + u += gfreq[i]; + } + printf("avg = %d/%d\n",t,u); + +} +*/ +///////////////////////////////////////////////////////////////////////////// +// +// State information +// +#define YAMSTATE ((struct YAM_STATE*)(state)) + +#define LOOP_NONE (0) +#define LOOP_FORWARDS (1) +#define LOOP_BACKWARDS (2) +#define LOOP_BIDIRECTIONAL (3) + +struct YAM_CHAN { + uint8 mute; + uint8 kyonb; + uint8 ssctl; + sint8 sampler_dir; + uint8 sampler_looptype; + sint32 sampler_invert; // bits 15-31 = invert sign bit, bits 0-14 = invert other bits + uint8 pcms; + uint32 sampleaddr; + sint32 loopstart; + sint32 loopend; + uint8 ar[4]; // amplitude envelope rate: attack, decay, sustain, release + uint8 dl; + uint8 krs; + uint8 link; + uint8 oct; + uint16 fns; + uint8 lfore; + uint8 lfof; + uint8 plfows; + uint8 plfos; + uint8 alfows; + uint8 alfos; + uint8 dspchan; + uint8 dsplevel; + uint8 disdl; + uint8 dipan; + uint8 tl; + uint8 voff; + uint8 lpoff; + uint8 q; + uint8 stwinh; + uint8 mdl; + uint8 mdxsl; + uint8 mdysl; + uint16 flv[5]; + uint8 fr[4]; // filter envelope rate: attack, decay, sustain, release + uint16 envlevelmask[4]; // for EGHOLD, the first will be 0 + uint16 envlevel; + uint16 lpflevel; + uint8 envstate; + uint8 lpfstate; + uint8 lp; + uint32 playpos; + uint32 frcphase; + uint32 lfophase; + sint32 samplebufcur; // these are 16-bit signed + sint32 samplebufnext; // these are 16-bit signed + sint32 lpp1; + sint32 lpp2; + sint32 adpcmstep; + sint32 adpcmstep_loopstart; + sint32 adpcmprev; + sint32 adpcmprev_loopstart; + uint8 adpcminloop; +}; + +struct MPRO { + uint8 c_0rrrrrrr; // CRA (up to 7 bits) + uint8 t_0rrrrrrr; // TRA + uint8 t_Twwwwwww; // !TWT, TWA + sint8 tablemask; // -1 if table + sint8 adrmask; // -1 if adreb=1 + sint8 negb; // -1 if negb + uint8 __kisxzbon; // skip, interpolate, saturate, XSEL, ZERO, BSEL, NOFL, NXADR + uint8 m_wrAFyyYh; // MWT, MRD, ADRL, FRCL, YSEL, YRL, shift-left-by + uint8 i_00rrrrrr; // IRA + uint8 i_0T0wwwww; // !IWT, IWA + uint8 e_000Twwww; // !EWT, EWA + uint8 m_00aaaaaa; // MASA +}; + +static uint64 mpro_scsp_read(struct MPRO *mpro) { + uint64 value = 0; + value |= ((uint64)(mpro->t_0rrrrrrr )) << 56; // TRA + value |= ((uint64)(mpro->t_Twwwwwww ^ 0x80)) << 48; // !TWT, TWA + value |= ((uint64)(mpro->tablemask & 1)) << 31; // TABLE + value |= ((uint64)(mpro->adrmask & 1)) << 1; // ADREB + value |= ((uint64)(mpro->negb & 1)) << 18; // NEGB + { uint64 sh = mpro->m_wrAFyyYh & 1; + if((mpro->__kisxzbon & 0x20) == 0) { sh ^= 3; } + value |= (sh << 20); // SHFT + } + value |= ((uint64)(mpro->__kisxzbon & 0x10)) << 43; // XSEL + value |= ((uint64)(mpro->__kisxzbon & 0x0C)) << 14; // ZERO, BSEL + value |= ((uint64)(mpro->__kisxzbon & 0x02)) << 6; // NOFL *** THIS IS JUST A GUESS *** + value |= ((uint64)(mpro->__kisxzbon & 0x01)) << 0; // NXADR + value |= ((uint64)(mpro->m_wrAFyyYh & 0xC0)) << 23; // MWT, MRD + value |= ((uint64)(mpro->m_wrAFyyYh & 0x32)) << 18; // ADRL, FRCL, YRL + value |= ((uint64)(mpro->m_wrAFyyYh & 0x0C)) << 43; // YSEL + value |= ((uint64)(mpro->i_00rrrrrr & 0x3F)) << 38; // IRA + value |= ((uint64)(mpro->i_0T0wwwww & 0x1F)) << 32; // IWA + value |= ((uint64)((mpro->i_0T0wwwww & 0x40) ^ 0x40)) << 31; // !IWT + value |= ((uint64)((mpro->e_000Twwww & 0x1F) ^ 0x10)) << 24; // !EWT, EWA + value |= ((uint64)(mpro->m_00aaaaaa & 0x1F)) << 2; // MASA (fewer bits on SCSP) + value |= ((uint64)(mpro->c_0rrrrrrr & 0x3F)) << 9; // CRA (SCSP exclusive) + + return value; +} + +static void mpro_scsp_write(struct MPRO *mpro, uint64 value) { + mpro->t_0rrrrrrr = ((value >> 56) & 0x7F); // TRA + mpro->t_Twwwwwww = ((value >> 48) ^ 0x80); // !TWT, TWA + mpro->tablemask = ((value >> 31) & 1) ? (-1) : (0); // TABLE + mpro->adrmask = ((value >> 1) & 1) ? (-1) : (0); // ADREB + mpro->negb = ((value >> 18) & 1) ? (-1) : (0); // NEGB + mpro->__kisxzbon = 0; + if(!value) { mpro->__kisxzbon |= 0x80; } // skip + if(((value >> 20) & 3) == 3) { mpro->__kisxzbon |= 0x40; } // interpolate + if(((value >> 21) & 1) == 0) { mpro->__kisxzbon |= 0x20; } // saturate + mpro->__kisxzbon |= (value >> 43) & 0x10; // XSEL + mpro->__kisxzbon |= (value >> 14) & 0x0C; // ZERO, BSEL + mpro->__kisxzbon |= (value >> 6) & 0x02; // NOFL *** THIS IS JUST A GUESS *** + mpro->__kisxzbon |= (value >> 0) & 1; // NXADR + mpro->m_wrAFyyYh = (value >> 23) & 0xC0; // MWT, MRD + mpro->m_wrAFyyYh |= (value >> 18) & 0x32; // ADRL, FRCL, YRL + mpro->m_wrAFyyYh |= (value >> 43) & 0x0C; // YSEL + mpro->m_wrAFyyYh |= ((value >> 20) & 1) ^ ((value >> 21) & 1); // shift left by + mpro->i_00rrrrrr = (value >> 38) & 0x3F; // IRA + mpro->i_0T0wwwww = (value >> 32) & 0x1F; // IWA + mpro->i_0T0wwwww |= ((value >> 31) & 0x40) ^ 0x40; // !IWT + mpro->e_000Twwww = ((value >> 24) & 0x1F) ^ 0x10; // !EWT, EWA + mpro->m_00aaaaaa = (value >> 2) & 0x1F; // MASA (fewer bits on SCSP) + mpro->c_0rrrrrrr = (value >> 9) & 0x3F; // CRA (SCSP exclusive) +} + +static void mpro_aica_write(struct MPRO *mpro, uint64 value) { + mpro->t_0rrrrrrr = ((value >> 57) & 0x7F); // TRA + mpro->t_Twwwwwww = ((value >> 49) ^ 0x80); // !TWT, TWA + mpro->tablemask = ((value >> 31) & 1) ? (-1) : (0); // TABLE + mpro->adrmask = ((value >> 8) & 1) ? (-1) : (0); // ADREB + mpro->negb = ((value >> 18) & 1) ? (-1) : (0); // NEGB + mpro->__kisxzbon = 0; + if(!value) { mpro->__kisxzbon |= 0x80; } // skip + if(((value >> 20) & 3) == 3) { mpro->__kisxzbon |= 0x40; } // interpolate + if(((value >> 21) & 1) == 0) { mpro->__kisxzbon |= 0x20; } // saturate + mpro->__kisxzbon |= (value >> 43) & 0x10; // XSEL + mpro->__kisxzbon |= (value >> 14) & 0x0E; // ZERO, BSEL, NOFL + mpro->__kisxzbon |= (value >> 7) & 1; // NXADR + mpro->m_wrAFyyYh = (value >> 23) & 0xC0; // MWT, MRD + mpro->m_wrAFyyYh |= (value >> 18) & 0x32; // ADRL, FRCL, YRL + mpro->m_wrAFyyYh |= (value >> 43) & 0x0C; // YSEL + mpro->m_wrAFyyYh |= ((value >> 20) & 1) ^ ((value >> 21) & 1); // shift left by + mpro->i_00rrrrrr = (value >> 39) & 0x3F; // IRA + mpro->i_0T0wwwww = (value >> 33) & 0x1F; // IWA + mpro->i_0T0wwwww |= ((value >> 32) & 0x40) ^ 0x40; // !IWT + mpro->e_000Twwww = ((value >> 24) & 0x1F) ^ 0x10; // !EWT, EWA + mpro->m_00aaaaaa = (value >> 9) & 0x3F; // MASA +} + +static uint64 mpro_aica_read(struct MPRO *mpro) { + uint64 value = 0; + value |= ((uint64)(mpro->t_0rrrrrrr )) << 57; // TRA + value |= ((uint64)(mpro->t_Twwwwwww ^ 0x80)) << 49; // !TWT, TWA + value |= ((uint64)(mpro->tablemask & 1)) << 31; // TABLE + value |= ((uint64)(mpro->adrmask & 1)) << 8; // ADREB + value |= ((uint64)(mpro->negb & 1)) << 18; // NEGB + { uint64 sh = mpro->m_wrAFyyYh & 1; + if((mpro->__kisxzbon & 0x20) == 0) { sh ^= 3; } + value |= (sh << 20); // SHFT + } + value |= ((uint64)(mpro->__kisxzbon & 0x10)) << 43; // XSEL + value |= ((uint64)(mpro->__kisxzbon & 0x0E)) << 14; // ZERO, BSEL, NOFL + value |= ((uint64)(mpro->__kisxzbon & 0x01)) << 7; // NXADR + value |= ((uint64)(mpro->m_wrAFyyYh & 0xC0)) << 23; // MWT, MRD + value |= ((uint64)(mpro->m_wrAFyyYh & 0x32)) << 18; // ADRL, FRCL, YRL + value |= ((uint64)(mpro->m_wrAFyyYh & 0x0C)) << 43; // YSEL + value |= ((uint64)(mpro->i_00rrrrrr & 0x3F)) << 39; // IRA + value |= ((uint64)(mpro->i_0T0wwwww & 0x1F)) << 33; // IWA + value |= ((uint64)((mpro->i_0T0wwwww & 0x40) ^ 0x40)) << 32; // !IWT + value |= ((uint64)((mpro->e_000Twwww & 0x1F) ^ 0x10)) << 24; // !EWT, EWA + value |= ((uint64)(mpro->m_00aaaaaa & 0x3F)) << 9; // MASA + return value; +} + +#define DYNACODE_MAX_SIZE (0x6000) +#define DYNACODE_SLOP_SIZE (0x80) + +struct YAM_STATE { + // + // Misc. + // + uint32 version; + void *ram_ptr; // EXTERNALLY-REGISTERED pointer + uint32 ram_mask; + sint16 *out_buf; // EXTERNALLY-REGISTERED pointer + uint32 out_pending; + uint32 odometer; + uint8 dry_out_enabled; + uint8 dsp_emulation_enabled; + uint8 dsp_dyna_enabled; + uint8 dsp_dyna_valid; + uint32 randseed; + uint32 mem_word_address_xor; + uint32 mem_byte_address_xor; + // + // Common regs + // + uint8 efsdl[18]; + uint8 efpan[18]; + uint8 mono; + uint8 mvol; + uint32 rbp; + uint8 rbl; + uint8 afsel; + uint8 mslc; + uint8 mrwinh; + uint8 tctl[3], tim[3]; + uint16 mcieb, mcipd; + uint16 scieb, scipd; + uint8 scilv0, scilv1, scilv2; + uint8 inton, intreq; + uint32 rtc; + // + // DSP regs + // + sint16 coef[128]; // stored as 13-bit + uint16 madrs[64]; + struct MPRO mpro[128]; + sint32 temp[128]; + // INPUTS all pre-promoted to 24-bit + // 0x00-0x1F: MEMS + // 0x20-0x2F: MIXS + // 0x30-0x31: EXTS + // 0x32-0x3F: always zero + // 0x40-0x5F: slop area to handle IWTA + sint32 inputs[0x60]; + // EFREG + // 0x00-0x0F: EFREG + // 0x10-0x1F: slop area to handle EWTA + sint16 efreg[0x20]; + uint32 mdec_ct; + uint32 adrs_reg; + + sint32 xzbchoice[5]; +#define XZBCHOICE_TEMP (0) +#define XZBCHOICE_ACC (1) +#define XZBCHOICE_ZERO (2) +#define XZBCHOICE_ZERO_ACC (3) +#define XZBCHOICE_INPUTS (4) + + sint32 yychoice[4]; +#define YYCHOICE_FRC_REG (0) +#define YYCHOICE_COEF (1) +#define YYCHOICE_Y_REG_H (2) +#define YYCHOICE_Y_REG_L (3) + + sint32 mem_in_data[4]; + + // SCSP modulation data + sint16 ringbuf[32*RINGMAX]; + uint32 bufptr; + // DMA registers + uint32 dmea; + uint16 drga; + uint16 dtlg; + // + // Channel regs + // + struct YAM_CHAN chan[64]; + // + // Buffer for dynarec code + // + uint8 dynacode[DYNACODE_MAX_SIZE]; +}; + +// +// Get size +// +uint32 EMU_CALL yam_get_state_size(uint8 version) { + return sizeof(struct YAM_STATE); +} + +// +// Initialize DSP state +// +void EMU_CALL yam_clear_state(void *state, uint8 version) { + int i; + if(version != 2) { version = 1; } + // Clear to zero + memset(state, 0, sizeof(struct YAM_STATE)); + // Set version + YAMSTATE->version = version; + // Clear channel regs + for(i = 0; i < 64; i++) { + YAMSTATE->chan[i].mute = 0; + YAMSTATE->chan[i].envstate = 3; + YAMSTATE->chan[i].lpfstate = 3; + YAMSTATE->chan[i].envlevel = 0x1FFF; + YAMSTATE->chan[i].envlevelmask[0] = 0x1FFF; + YAMSTATE->chan[i].envlevelmask[1] = 0x1FFF; + YAMSTATE->chan[i].envlevelmask[2] = 0x1FFF; + YAMSTATE->chan[i].envlevelmask[3] = 0x1FFF; + YAMSTATE->chan[i].lpflevel = 0x1FFF; + // no lowpass on the SCSP + if(version == 1) { YAMSTATE->chan[i].lpoff = 1; } + } + // Initialize MPRO + for(i = 0; i < 128; i++) { + switch(version) { + case 1: + mpro_scsp_write((YAMSTATE->mpro) + i, 0); + break; + case 2: + YAMSTATE->mpro[i].c_0rrrrrrr = i; + mpro_aica_write((YAMSTATE->mpro) + i, 0); + break; + } + } + // Enable dry output + YAMSTATE->dry_out_enabled = 1; + + // Enable DSP emulation by default + YAMSTATE->dsp_emulation_enabled = 1; + + // Enable DSP dynarec + YAMSTATE->dsp_dyna_enabled = 1; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Ugly hack to log debug output +// +/* +FILE *logfile = NULL; + +static void logf(const char *fmt, ...) { + va_list a; + va_start(a, fmt); + if(!logfile) { + logfile=fopen("C:\\Corlett\\yam.log","wb"); + } + if(logfile) { vfprintf(logfile, fmt, a); fflush(logfile); } +} + +static void logupdate(struct YAM_STATE *state) { + int i; + logf("log update\n"); +// for(i=0;i<10;i++) { +// logf("mpro %d: %08X %08X\n",i,state->mpro32[2*i+0],state->mpro32[2*i+1]); +// } + for(i = 0; i < 64; i++) { + logf("chan %d: dsp %X level %X\n",i,state->chan[i].dspchan,state->chan[i].dsplevel); + } + for(i = 0; i < 16; i++) { + logf("efsdl %d: %X pan %X\n",i,state->efsdl[i],state->efpan[i]); + } +} + +static void logstep(struct YAM_STATE *state, uint32 odometer) { + static uint32 lastodometer = 0; + if((odometer/50000) > (lastodometer/50000)) { + lastodometer = odometer; + logupdate(state); + } +} + +static int st = 0; + +static void dumpch(struct YAM_STATE *state, struct YAM_CHAN *chan) { + logf("st=%u (%us) envstate=%X level=%X\n",st,st/44100,chan->envstate,chan->envlevel); + logf(" playpos=%X ls=%X le=%X\n",chan->playpos,chan->loopstart,chan->loopend); + logf(" sample=%X tl=%X oct=%X fns=%X\n",chan->sampleaddr, chan->tl,chan->oct,chan->fns); + logf(" rbp=%X rbl=%X\n",state->rbp,state->rbl); +} +*/ +///////////////////////////////////////////////////////////////////////////// +// +// Set RAM pointer and size (must be a power of 2) +// +void EMU_CALL yam_setram(void *state, uint32 *ram, uint32 size, uint8 mbx, uint8 mwx) { + YAMSTATE->ram_ptr = ram; + if((size & (size-1)) == 0) { + YAMSTATE->ram_mask = size-1; + } else { + YAMSTATE->ram_mask = 0; + } + YAMSTATE->mem_byte_address_xor = mbx; + YAMSTATE->mem_word_address_xor = mwx; + // + // Invalidate dynarec code + // + YAMSTATE->dsp_dyna_valid = 0; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Set output buffer pointer and begin new execution run +// +void EMU_CALL yam_beginbuffer(void *state, sint16 *buf) { + YAMSTATE->out_buf = buf; + YAMSTATE->out_pending = 0; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Enable or disable various things +// +void EMU_CALL yam_enable_dry(void *state, uint8 enable) { + YAMSTATE->dry_out_enabled = (enable != 0); +} + +void EMU_CALL yam_enable_dsp(void *state, uint8 enable) { + YAMSTATE->dsp_emulation_enabled = (enable != 0); + if(enable == 0) { YAMSTATE->dsp_dyna_valid = 0; } +} + +void EMU_CALL yam_enable_dsp_dynarec(void *state, uint8 enable) { + YAMSTATE->dsp_dyna_enabled = (enable != 0); + if(enable == 0) { YAMSTATE->dsp_dyna_valid = 0; } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Timers / interrupts +// + +// +// Recompute intreq +// +static void sci_recompute(struct YAM_STATE *state) { + int i; + uint16 scipd = (state->scipd) & (state->scieb); + state->inton = 0; + for(i = 10; i >= 0; i--) { + if(((scipd) >> i) & 1) { + if(i > 7) i = 7; + state->intreq = + ((((state->scilv0) >> i) & 1) << 0) | + ((((state->scilv1) >> i) & 1) << 1) | + ((((state->scilv2) >> i) & 1) << 2); + state->inton = state->intreq; + return; + } + } +} + +// +// Signal an interrupt +// +static void sci_signal(struct YAM_STATE *state, int n) { + state->scipd |= (1 << n); + if(!(state->inton)) { + sci_recompute(state); + } +} + +uint8* EMU_CALL yam_get_interrupt_pending_ptr(void *state) { + return &(YAMSTATE->inton); +} + +// +// Determine how many samples until the next interrupt +// +uint32 EMU_CALL yam_get_min_samples_until_interrupt(void *state) { + uint32 min = 0xFFFFFFFF; + uint32 t, samples; + +//return 1; + + for(t = 0; t < 3; t++) { + if(YAMSTATE->scieb & (1 << (INT_TIMER_A + t))) { + samples = 0x100-((uint32)(YAMSTATE->tim[t])); + samples <<= YAMSTATE->tctl[t]; + samples -= (YAMSTATE->odometer) & ((1<tctl[t])-1); + if(samples < min) { min = samples; } + } + } +//printf("yam min: ta=%X %02X tb=%X %02X tc=%X %02X min=%u\n",YAMSTATE->tctl[0],YAMSTATE->tim[0],YAMSTATE->tctl[1],YAMSTATE->tim[1],YAMSTATE->tctl[2],YAMSTATE->tim[2],min); +// min should never be 1 if the above is correct +// if(min < 1) { min = 1; } + return min; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Advance timers and interrupts +// +void EMU_CALL yam_advance(void *state, uint32 samples) { + uint32 t; +//printf("yam_advance(%u)",samples); + for(t = 0; t < 3; t++) { + uint8 scale = YAMSTATE->tctl[t]; + uint32 whole = YAMSTATE->tim[t]; + uint32 frac = (YAMSTATE->odometer) & ((1<= remain) { sci_signal(state, INT_TIMER_A + t); } + YAMSTATE->tim[t] = ((frac + samples + (whole << scale)) >> scale) & 0xFF; + } + YAMSTATE->out_pending += samples; + YAMSTATE->odometer += samples; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Key on/off +// +static void keyon(struct YAM_CHAN *chan) { +//printf("keyon %08X\n",chan); + // Ignore redundant key-ons + if(chan->envstate != 3) return; + chan->sampler_dir = 1; + chan->playpos = 0; + chan->envlevel = 0x280; + chan->lpflevel = chan->flv[0]; + chan->envstate = 0; + chan->lpfstate = 0; + chan->adpcmstep = 0x7F; + chan->adpcmstep_loopstart = 0; + chan->adpcmprev = 0; + chan->adpcmprev_loopstart = 0; + chan->adpcminloop = 0; + chan->samplebufcur = 0; + chan->samplebufnext = 0; +//printf("keyon %08X passed\n",chan); +} + +static void keyoff(struct YAM_CHAN *chan) { + chan->envstate = 3; + chan->lpfstate = 3; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Estimate play position for a channel +// +// These are ROUGH approximations, and will not be entirely accurate in the +// following conditions: +// +// - any pitch LFO is applied +// - bidirectional loop mode +// - weird values of loopstart or loopend +// +static uint32 calculate_playpos( + struct YAM_STATE *state, + struct YAM_CHAN *chan +) { + sint32 p, deltap, loopsize; + + if(!(chan->sampler_dir)) return 0; + + if(state->out_pending > 100) yam_flush(state); + + loopsize = chan->loopend - chan->loopstart; + if(loopsize < 1) { loopsize = 1; } + + { uint32 oct = chan->oct^8; + uint32 fns = chan->fns^0x400; + uint32 base_phaseinc = fns << oct; + // weird ADPCM thing mentioned in official doc + if(chan->pcms == 2 && oct >= 0xA) { base_phaseinc <<= 1; } + deltap = base_phaseinc * ((uint32)(state->out_pending)); + deltap &= 0x7FFFFFFF; + deltap >>= 18; + } + p = ((uint16)(chan->playpos)); + + switch(chan->sampler_looptype) { + case LOOP_NONE: + p += deltap; + if(p >= chan->loopend) p = 0; + break; + case LOOP_FORWARDS: + p += deltap; + if(p >= chan->loopstart) { + p -= chan->loopstart; + p %= loopsize; + p += chan->loopstart; + } + break; + case LOOP_BACKWARDS: + if(p >= chan->loopstart) { + p -= chan->loopstart; + p = loopsize - p; + p += chan->loopstart; + } + p += deltap; + if(p >= chan->loopstart) { + p -= chan->loopstart; + p %= loopsize; + p += chan->loopstart; + } + if(p >= chan->loopstart) { + p -= chan->loopstart; + p = loopsize - p; + p += chan->loopstart; + } + break; + case LOOP_BIDIRECTIONAL: + if(chan->sampler_dir < 0) { + p = chan->loopend + loopsize - (p - chan->loopstart); + } + p += deltap; + if(p >= chan->loopstart) { + p -= chan->loopstart; + p %= 2 * loopsize; + p += chan->loopstart; + } + if(p >= chan->loopend) { + p = chan->loopend - (p - chan->loopend); + } + break; + } + return p & 0xFFFF; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Channel registers +// +static uint32 chan_scsp_load_reg(struct YAM_STATE *state, uint8 ch, uint8 a) { + struct YAM_CHAN *chan = state->chan + (((uint32)ch) & 0x1F); + uint16 d = 0; + // don't really need a flush for loading chan regs + switch(a & 0x1E) { + case 0x00: // PlayControl + d = (((uint32)(chan->kyonb )) & 0x0001) << 11; + d |= (((uint32)(chan->sampler_invert )) & 0xC000) >> 5; + d |= (((uint32)(chan->ssctl )) & 0x0003) << 7; + d |= (((uint32)(chan->sampler_looptype)) & 0x0003) << 5; + d |= (((uint32)(chan->pcms )) & 0x0001) << 4; + d |= ((chan->sampleaddr) >> 16) & 0xF; + break; + case 0x02: // SampleAddrLow + d = chan->sampleaddr; + break; + case 0x04: // LoopStart + d = chan->loopstart; + break; + case 0x06: // LoopEnd + d = chan->loopend; + break; + case 0x08: // AmpEnv1 + d = (((uint32)(chan->ar[2] )) & 0x001F) << 11; + d |= (((uint32)(chan->ar[1] )) & 0x001F) << 6; + d |= ((((uint32)(chan->envlevelmask[0])) & 1) ^ 1) << 5; + d |= (((uint32)(chan->ar[0] )) & 0x001F) << 0; + break; + case 0x0A: // AmpEnv2 + d = (((uint32)(chan->link )) & 0x0001) << 14; + d |= (((uint32)(chan->krs )) & 0x000F) << 10; + d |= (((uint32)(chan->dl )) & 0x001F) << 5; + d |= (((uint32)(chan->ar[3] )) & 0x001F) << 0; + break; + case 0x0C: // TotalLevel + d = (((uint32)(chan->stwinh )) & 0x0001) << 9; + d |= (((uint32)(chan->voff )) & 0x0001) << 8; + d |= (((uint32)(chan->tl )) & 0x00FF) << 0; + break; + case 0x0E: // Modulation + d = (((uint32)(chan->mdl )) & 0x000F) << 12; + d |= (((uint32)(chan->mdxsl )) & 0x003F) << 6; + d |= (((uint32)(chan->mdysl )) & 0x003F) << 0; + break; + case 0x10: // SampleRatePitch + d = (((uint32)(chan->oct )) & 0x000F) << 11; + d |= (((uint32)(chan->fns )) & 0x07FF) << 0; + break; + case 0x12: // LFOControl + d = (((uint32)(chan->lfore )) & 0x0001) << 15; + d |= (((uint32)(chan->lfof )) & 0x001F) << 10; + d |= (((uint32)(chan->plfows )) & 0x0003) << 8; + d |= (((uint32)(chan->plfos )) & 0x0007) << 5; + d |= (((uint32)(chan->alfows )) & 0x0003) << 3; + d |= (((uint32)(chan->alfos )) & 0x0007) << 0; + break; + case 0x14: // DSPInputSelect + d = (((uint32)(chan->dspchan )) & 0x000F) << 3; + d |= (((uint32)(chan->dsplevel )) & 0x000E) >> 1; + break; + case 0x16: // SendLevels + d = (((uint32)(chan->disdl )) & 0x000E) << 12; + d |= (((uint32)(chan->dipan )) & 0x001F) << 8; + if(ch < 18) { + d |= (((uint32)(state->efsdl[ch])) & 0x0E) << 4; + d |= (((uint32)(state->efpan[ch])) & 0x1F) << 0; + } + break; + } + return d; +} + +static void chan_scsp_store_reg(struct YAM_STATE *state, uint8 ch, uint8 a, uint32 d, uint32 mask) { + struct YAM_CHAN *chan; + a &= 0x1E; + if(a >= 0x18) return; + yam_flush(YAMSTATE); + chan = state->chan + (((uint32)ch) & 0x1F); + switch(a & 0x1E) { + case 0x00: // PlayControl + if(mask & 0x00FF) { + chan->sampleaddr &= 0xFFFF; + chan->sampleaddr |= (((uint32)d) & 0xF) << 16; + chan->pcms = (d >> 4) & 1; + chan->sampler_looptype = (d >> 5) & 3; + chan->ssctl &= 2; + chan->ssctl |= (d >> 7) & 1; + } + if(mask & 0xFF00) { + chan->ssctl &= 1; + chan->ssctl |= (d >> 7) & 2; + chan->sampler_invert = 0; + if(d & (1<< 9)) chan->sampler_invert |= 0x00007FFF; + if(d & (1<<10)) chan->sampler_invert |= 0xFFFF8000; + chan->kyonb = (d >> 11) & 1; + if(d & 0x1000) { // kyonex + int ch; +//for(ch=0;ch<32;ch++){printf("%d",state->chan[ch].envstate);}printf("\n"); + for(ch = 0; ch < 32; ch++) { + if(state->chan[ch].kyonb) { +//printf("*"); + keyon(state->chan + ch); + } else { +//printf("."); + keyoff(state->chan + ch); + } + } +//printf("\n"); +//for(ch=0;ch<32;ch++){printf("%d",state->chan[ch].envstate);}printf("\n"); + } + } + break; + case 0x02: // SampleAddrLow + chan->sampleaddr &= (0xFFFFF ^ mask); + chan->sampleaddr |= (d & mask); + break; + case 0x04: // LoopStart + chan->loopstart &= (0xFFFF ^ mask); + chan->loopstart |= (d & mask); + break; + case 0x06: // LoopEnd + chan->loopend &= (0xFFFF ^ mask); + chan->loopend |= (d & mask); + break; + case 0x08: // AmpEnv1 + if(mask & 0x00FF) { + chan->ar[0] = d & 0x1F; + chan->envlevelmask[0] = (d & (1<<5)) ? 0x0000 : 0x1FFF; +// chan->envlevelmask[0] = 0x1FFF; + chan->ar[1] &= 0x1C; + chan->ar[1] |= (d >> 6) & 0x03; + } + if(mask & 0xFF00) { + chan->ar[1] &= 0x03; + chan->ar[1] |= (d >> 6) & 0x1C; + chan->ar[2] = (d >> 11) & 0x1F; + } + break; + case 0x0A: // AmpEnv2 + if(mask & 0x00FF) { + chan->ar[3] = d & 0x1F; + chan->dl &= 0x18; + chan->dl |= (d >> 5) & 0x07; + } + if(mask & 0xFF00) { + chan->dl &= 0x07; + chan->dl |= (d >> 5) & 0x18; + chan->krs = (d >> 10) & 0xF; + chan->link = (d >> 14) & 1; + } + break; + case 0x0C: // TotalLevel + if(mask & 0x00FF) { + chan->tl = d & 0xFF; + } + if(mask & 0xFF00) { + chan->voff = (d >> 8) & 1; + chan->stwinh = (d >> 9) & 1; + } + break; + case 0x0E: // Modulation + if(mask & 0x00FF) { + chan->mdysl = d & 0x3F; + chan->mdxsl &= 0x3C; + chan->mdxsl |= (d >> 6) & 0x03; + } + if(mask & 0xFF00) { + chan->mdxsl &= 0x03; + chan->mdxsl |= (d >> 6) & 0x3C; + chan->mdl = (d >> 12) & 0xF; + } + break; + case 0x10: // SampleRatePitch + if(mask & 0x00FF) { + chan->fns &= 0x700; + chan->fns |= d & 0x0FF; + } + if(mask & 0xFF00) { + chan->fns &= 0x0FF; + chan->fns |= d & 0x700; + chan->oct = (d >> 11) & 0xF; + } + break; + case 0x12: // LFOControl + if(mask & 0x00FF) { + chan->alfos = d & 7; + chan->alfows = (d >> 3) & 3; + chan->plfos = (d >> 5) & 7; + } + if(mask & 0xFF00) { + chan->plfows = (d >> 8) & 3; + chan->lfof = (d >> 10) & 0x1F; + chan->lfore = (d >> 15) & 1; + } + break; + case 0x14: // DSPInputSelect + if(mask & 0x00FF) { + chan->dsplevel = (d << 1) & 0xE; + if(chan->dsplevel) chan->dsplevel |= 1; + chan->dspchan = (d >> 3) & 0xF; + } + break; + case 0x16: // SendLevels + if(mask & 0x00FF) { + if(ch < 18) { + state->efpan[ch] = d & 0x1F; + state->efsdl[ch] = (d >> 4) & 0xE; + if(state->efsdl[ch]) state->efsdl[ch] |= 1; + } + } + if(mask & 0xFF00) { + chan->dipan = (d >> 8) & 0x1F; + chan->disdl = (d >> 12) & 0xE; + if(chan->disdl) chan->disdl |= 1; + } + break; + } +} + +static uint32 chan_aica_load_reg(struct YAM_STATE *state, uint8 ch, uint8 a) { + struct YAM_CHAN *chan = state->chan + (((uint32)ch) & 0x3F); + uint16 d = 0; + // don't really need a flush for loading chan regs + switch(a & 0x7C) { + case 0x00: // PlayControl + d = (((uint32)(chan->kyonb )) & 0x0001) << 14; + d |= (((uint32)(chan->ssctl )) & 0x0001) << 10; + d |= (((uint32)(chan->sampler_looptype)) & 0x0001) << 9; + d |= (((uint32)(chan->pcms )) & 0x0003) << 7; + d |= ((chan->sampleaddr) >> 16) & 0x7F; + break; + case 0x04: // SampleAddrLow + d = chan->sampleaddr; + break; + case 0x08: // LoopStart + d = chan->loopstart; + break; + case 0x0C: // LoopEnd + d = chan->loopend; + break; + case 0x10: // AmpEnv1 + d = (((uint32)(chan->ar[2] )) & 0x001F) << 11; + d |= (((uint32)(chan->ar[1] )) & 0x001F) << 6; + d |= (((uint32)(chan->ar[0] )) & 0x001F) << 0; + break; + case 0x14: // AmpEnv2 + d = (((uint32)(chan->link )) & 0x0001) << 14; + d |= (((uint32)(chan->krs )) & 0x000F) << 10; + d |= (((uint32)(chan->dl )) & 0x001F) << 5; + d |= (((uint32)(chan->ar[3] )) & 0x001F) << 0; + break; + case 0x18: // SampleRatePitch + d = (((uint32)(chan->oct )) & 0x000F) << 11; + d |= (((uint32)(chan->fns )) & 0x07FF) << 0; + break; + case 0x1C: // LFOControl + d = (((uint32)(chan->lfore )) & 0x0001) << 15; + d |= (((uint32)(chan->lfof )) & 0x001F) << 10; + d |= (((uint32)(chan->plfows )) & 0x0003) << 8; + d |= (((uint32)(chan->plfos )) & 0x0007) << 5; + d |= (((uint32)(chan->alfows )) & 0x0003) << 3; + d |= (((uint32)(chan->alfos )) & 0x0007) << 0; + break; + case 0x20: // DSPChannelSend + d = (((uint32)(chan->dsplevel )) & 0x000F) << 4; + d |= (((uint32)(chan->dspchan )) & 0x000F) << 0; + break; + case 0x24: // DirectPanVolSend + d = (((uint32)(chan->disdl )) & 0x000F) << 8; + d |= (((uint32)(chan->dipan )) & 0x001F) << 0; + break; + case 0x28: // LPF1Volume + d = (((uint32)(chan->tl )) & 0x00FF) << 8; + d |= (((uint32)(chan->voff )) & 0x0001) << 6; + d |= (((uint32)(chan->lpoff )) & 0x0001) << 5; + d |= (((uint32)(chan->q )) & 0x001F) << 0; + break; + case 0x2C: // LPF2 + d = (chan->flv[0]) & 0x1FFF; + break; + case 0x30: // LPF3 + d = (chan->flv[1]) & 0x1FFF; + break; + case 0x34: // LPF4 + d = (chan->flv[2]) & 0x1FFF; + break; + case 0x38: // LPF5 + d = (chan->flv[3]) & 0x1FFF; + break; + case 0x3C: // LPF6 + d = (chan->flv[4]) & 0x1FFF; + break; + case 0x40: // LPF7 + d = (((uint32)(chan->fr[0] )) & 0x001F) << 8; + d |= (((uint32)(chan->fr[1] )) & 0x001F) << 0; + break; + case 0x44: // LPF8 + d = (((uint32)(chan->fr[2] )) & 0x001F) << 8; + d |= (((uint32)(chan->fr[3] )) & 0x001F) << 0; + break; + } + return d; +} + +static void chan_aica_store_reg(struct YAM_STATE *state, uint8 ch, uint8 a, uint32 d, uint32 mask) { + struct YAM_CHAN *chan; + a &= 0x7C; + if(a >= 0x48) return; + yam_flush(YAMSTATE); + chan = state->chan + (((uint32)ch) & 0x3F); + switch(a) { + case 0x00: // PlayControl + if(mask & 0x00FF) { + chan->sampleaddr &= 0xFFFF; + chan->sampleaddr |= (((uint32)d) & 0x7F) << 16; + chan->pcms &= 2; + chan->pcms |= (d >> 7) & 1; + } + if(mask & 0xFF00) { + chan->pcms &= 1; + chan->pcms |= (d >> 7) & 2; + chan->sampler_looptype = (d >> 9) & 1; + chan->ssctl = (d >> 10) & 1; + chan->kyonb = (d >> 14) & 1; + if(d & 0x8000) { // kyonex + int ch; + for(ch = 0; ch < 64; ch++) { + if(state->chan[ch].kyonb) { keyon(state->chan + ch); } + else { keyoff(state->chan + ch); } + } + } + } + break; + case 0x04: // SampleAddrLow + chan->sampleaddr &= (0x7FFFFF ^ mask); + chan->sampleaddr |= (d & mask); + break; + case 0x08: // LoopStart + chan->loopstart &= (0xFFFF ^ mask); + chan->loopstart |= (d & mask); + break; + case 0x0C: // LoopEnd + chan->loopend &= (0xFFFF ^ mask); + chan->loopend |= (d & mask); + break; + case 0x10: // AmpEnv1 + if(mask & 0x00FF) { + chan->ar[0] = d & 0x1F; + chan->ar[1] &= 0x1C; + chan->ar[1] |= (d >> 6) & 0x03; + } + if(mask & 0xFF00) { + chan->ar[1] &= 0x03; + chan->ar[1] |= (d >> 6) & 0x1C; + chan->ar[2] = (d >> 11) & 0x1F; + } + break; + case 0x14: // AmpEnv2 + if(mask & 0x00FF) { + chan->ar[3] = d & 0x1F; + chan->dl &= 0x18; + chan->dl |= (d >> 5) & 0x07; + } + if(mask & 0xFF00) { + chan->dl &= 0x07; + chan->dl |= (d >> 5) & 0x18; + chan->krs = (d >> 10) & 0xF; + chan->link = (d >> 14) & 1; + } + break; + case 0x18: // SampleRatePitch + if(mask & 0x00FF) { + chan->fns &= 0x700; + chan->fns |= d & 0x0FF; + } + if(mask & 0xFF00) { + chan->fns &= 0x0FF; + chan->fns |= d & 0x700; + chan->oct = (d >> 11) & 0xF; + } + break; + case 0x1C: // LFOControl + if(mask & 0x00FF) { + chan->alfos = d & 7; + chan->alfows = (d >> 3) & 3; + chan->plfos = (d >> 5) & 7; + } + if(mask & 0xFF00) { + chan->plfows = (d >> 8) & 3; + chan->lfof = (d >> 10) & 0x1F; + chan->lfore = (d >> 15) & 1; + } + break; + case 0x20: // DSPChannelSend + if(mask & 0x00FF) { + chan->dspchan = d & 0xF; + chan->dsplevel = (d >> 4) & 0xF; + } + break; + case 0x24: // DirectPanVolSend + if(mask & 0x00FF) { chan->dipan = d & 0x1F; } + if(mask & 0xFF00) { chan->disdl = (d >> 8) & 0xF; } + break; + case 0x28: // LPF1Volume + if(mask & 0x00FF) { + chan->q = d & 0x1F; + chan->lpoff = (d >> 5) & 1; + chan->voff = (d >> 6) & 1; + } + if(mask & 0xFF00) { + chan->tl = (d >> 8) & 0xFF; + } + break; + case 0x2C: // LPF2 + chan->flv[0] = (((chan->flv[0]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF; + break; + case 0x30: // LPF3 + chan->flv[1] = (((chan->flv[1]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF; + break; + case 0x34: // LPF4 + chan->flv[2] = (((chan->flv[2]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF; + break; + case 0x38: // LPF5 + chan->flv[3] = (((chan->flv[3]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF; + break; + case 0x3C: // LPF6 + chan->flv[4] = (((chan->flv[4]) & (0xFFFF ^ mask)) | (d & mask)) & 0x1FFF; + break; + case 0x40: // LPF7 + if(mask & 0x00FF) { chan->fr[1] = (d >> 0) & 0x1F; } + if(mask & 0xFF00) { chan->fr[0] = (d >> 8) & 0x1F; } + break; + case 0x44: // LPF8 + if(mask & 0x00FF) { chan->fr[3] = (d >> 0) & 0x1F; } + if(mask & 0xFF00) { chan->fr[2] = (d >> 8) & 0x1F; } + break; + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// DSP registers +// +static void coef_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) { + sint16 old = state->coef[n]; + yam_flush(state); + n &= 0x7F; + state->coef[n] <<= 3; + state->coef[n] &= ~mask; + state->coef[n] |= d & mask; + state->coef[n] = ((sint16)(state->coef[n])) >> 3; + if(old != state->coef[n]) { state->dsp_dyna_valid = 0; } +} + +static void madrs_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) { + uint16 old = state->madrs[n]; + yam_flush(state); + n &= 0x3F; + state->madrs[n] &= ~mask; + state->madrs[n] |= d & mask; + if(old != state->madrs[n]) { state->dsp_dyna_valid = 0; } +} + +static uint32 temp_read(struct YAM_STATE *state, uint32 n) { + yam_flush(state); + if((n & 1) == 0) { return ((state->temp[(n/2)&0x7F]) >> 0) & 0x00FF; } + else { return ((state->temp[(n/2)&0x7F]) >> 8) & 0xFFFF; } +} + +static void temp_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) { + yam_flush(state); + switch(n & 1) { + case 0: mask &= 0x00FF; break; + case 1: mask &= 0xFFFF; mask <<= 8; d <<= 8; break; + } + n /= 2; n &= 0x1F; + state->temp[n] &= ~mask; + state->temp[n] |= d & mask; + // redo sign extension + state->temp[n] <<= 8; + state->temp[n] >>= 8; +} + +static uint32 mems_read(struct YAM_STATE *state, uint32 n) { + yam_flush(state); + if((n & 1) == 0) { return ((state->inputs[(n/2)&0x1F]) >> 0) & 0x00FF; } + else { return ((state->inputs[(n/2)&0x1F]) >> 8) & 0xFFFF; } +} + +static void mems_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) { + yam_flush(state); + switch(n & 1) { + case 0: mask &= 0x00FF; break; + case 1: mask &= 0xFFFF; mask <<= 8; d <<= 8; break; + } + n /= 2; n &= 0x1F; + state->inputs[n] &= ~mask; + state->inputs[n] |= d & mask; + // redo sign extension + state->inputs[n] <<= 8; + state->inputs[n] >>= 8; +} + +static uint32 mixs_read(struct YAM_STATE *state, uint32 n) { + yam_flush(state); + // MIXS is pre-promoted to 24-bit here, so shift it right by 4 + if((n & 1) == 0) { return ((state->inputs[0x20+((n/2)&0xF)]) >> 4) & 0x000F; } + else { return ((state->inputs[0x20+((n/2)&0xF)]) >> 8) & 0xFFFF; } +} + +static uint32 efreg_read(struct YAM_STATE *state, uint32 n) { + yam_flush(state); + return ((uint32)(state->efreg[n & 0xF])) & 0xFFFF; +} + +static void efreg_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) { + yam_flush(state); + state->efreg[n & 0xF] &= ~mask; + state->efreg[n & 0xF] |= d & mask; +} + +static uint32 exts_read(struct YAM_STATE *state, uint32 n) { + yam_flush(state); + return (state->inputs[0x30 + (n & 1)] >> 8) & 0xFFFF; +} + +static void exts_write(struct YAM_STATE *state, uint32 n, uint32 d, uint32 mask) { + yam_flush(state); + state->inputs[0x30 + (n & 1)] >>= 8; + state->inputs[0x30 + (n & 1)] &= ~mask; + state->inputs[0x30 + (n & 1)] |= d & mask; + state->inputs[0x30 + (n & 1)] <<= 16; + state->inputs[0x30 + (n & 1)] >>= 8; +} + +static uint32 dsp_scsp_load_reg(struct YAM_STATE *state, uint32 a) { + a &= 0xFFE; + if(a < 0x700) return 0; + if(a < 0x780) return state->coef[(a/2) & 0x3F] << 3; + if(a < 0x7C0) return state->madrs[(a/2) & 0x1F]; + if(a < 0x800) return 0; + if(a < 0xC00) { + uint8 shift = ((a&6)^6) * 8; + uint32 index = ((a-0x800)/8)&0x7F; + return (mpro_scsp_read(state->mpro + index) >> shift) & 0xFFFF; + } + if(a < 0xE00) return temp_read(state, (a/2) & 0xFF); + if(a < 0xE80) return mems_read(state, (a/2) & 0x3F); + if(a < 0xEC0) return mixs_read(state, (a/2) & 0x1F); + if(a < 0xEE0) return efreg_read(state, (a/2) & 0xF); + if(a < 0xEE4) return exts_read(state, (a/2) & 1); + return 0; +} + +static void dsp_scsp_store_reg( + struct YAM_STATE *state, + uint32 a, uint32 d, uint32 mask +) { + a &= 0xFFE; + if(a < 0x700) { return; } + if(a < 0x780) { coef_write(state, (a/2) & 0x3F, d, mask); return; } + if(a < 0x7C0) { madrs_write(state, (a/2) & 0x1F, d, mask); return; } + if(a < 0x800) { return; } + if(a < 0xC00) { + uint8 shift64 = ((a&6)^6) * 8; + uint32 index64 = ((a-0x800)/8)&0x7F; + uint64 mask64sh = ((uint64)(mask & 0xFFFF)) << shift64; + uint64 dm64sh = ((uint64)(d & mask & 0xFFFF)) << shift64; + uint64 oldvalue = mpro_scsp_read(state->mpro + index64); + uint64 newvalue = (oldvalue & (~mask64sh)) | dm64sh; + if(newvalue != oldvalue) { + yam_flush(state); + mpro_scsp_write(state->mpro + index64, newvalue); + state->dsp_dyna_valid = 0; + } + return; + } + if(a < 0xE00) { temp_write(state, (a/2) & 0xFF, d, mask); return; } + if(a < 0xE80) { mems_write(state, (a/2) & 0x3F, d, mask); return; } + // you can't write to MIXS, at least not meaningfully + if(a < 0xEC0) { return; } + if(a < 0xEE0) { efreg_write(state, (a/2) & 0xF, d, mask); return; } + if(a < 0xEE4) { exts_write(state, (a/2) & 1, d, mask); return; } +} + +static uint32 dsp_aica_load_reg(struct YAM_STATE *state, uint32 a) { + a &= 0xFFFC; + if(a < 0x3000) return 0; + if(a < 0x3200) return state->coef[(a/4) & 0x7F] << 3; + if(a < 0x3300) return state->madrs[(a/4) & 0x3F]; + if(a < 0x3400) return 0; + if(a < 0x3C00) { + uint8 shift64 = ((a&0xC)^0xC) * 4; + uint32 index64 = ((a-0x3400)/16)&0x7F; + return (mpro_aica_read(state->mpro + index64) >> shift64) & 0xFFFF; + } + if(a < 0x4000) return 0; + if(a < 0x4400) return temp_read(state, (a/4) & 0xFF); + if(a < 0x4500) return mems_read(state, (a/4) & 0x3F); + if(a < 0x4580) return mixs_read(state, (a/4) & 0x1F); + if(a < 0x45C0) return efreg_read(state, (a/4) & 0xF); + if(a < 0x45C8) return exts_read(state, (a/4) & 1); + return 0; +} + +static void dsp_aica_store_reg( + struct YAM_STATE *state, + uint32 a, uint32 d, uint32 mask +) { + a &= 0xFFFC; + if(a < 0x3000) { return; } + if(a < 0x3200) { coef_write(state, (a/4) & 0x7F, d, mask); return; } + if(a < 0x3300) { madrs_write(state, (a/4) & 0x3F, d, mask); return; } + if(a < 0x3400) { return; } + if(a < 0x3C00) { + uint8 shift64 = ((a&0xC)^0xC) * 4; + uint32 index64 = ((a-0x3400)/16)&0x7F; + uint64 mask64sh = ((uint64)(mask & 0xFFFF)) << shift64; + uint64 dm64sh = ((uint64)(d & mask & 0xFFFF)) << shift64; + uint64 oldvalue = mpro_aica_read(state->mpro + index64); + uint64 newvalue = (oldvalue & (~mask64sh)) | dm64sh; + if(newvalue != oldvalue) { + yam_flush(state); + mpro_aica_write(state->mpro + index64, newvalue); + state->dsp_dyna_valid = 0; + } + return; + } + if(a < 0x4000) { return; } + if(a < 0x4400) { temp_write(state, (a/4) & 0xFF, d, mask); return; } + if(a < 0x4500) { mems_write(state, (a/4) & 0x3F, d, mask); return; } + // you can't write to MIXS, at least not meaningfully + if(a < 0x4580) { return; } + if(a < 0x45C0) { efreg_write(state, (a/4) & 0xF, d, mask); return; } + if(a < 0x45C8) { exts_write(state, (a/4) & 1, d, mask); return; } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Externally-accessible load/store register +// +uint32 EMU_CALL yam_scsp_load_reg(void *state, uint32 a, uint32 mask) { + uint32 d = 0; + a &= 0xFFE; + if(a < 0x400) return chan_scsp_load_reg(YAMSTATE, a>>5, a&0x1E) & mask; + if(a >= 0x700) return dsp_scsp_load_reg(YAMSTATE, a) & mask; + if(a >= 0x600) return YAMSTATE->ringbuf[(YAMSTATE->bufptr-64+(a-0x600)/2)&(32*RINGMAX-1)] & mask; + switch(a) { + case 0x400: d = 0x0010; break; // MasterVolume (actually returns the LSI version) + case 0x402: // RingBufferAddress + d = (((uint32)(YAMSTATE->rbl)) & 3) << 7; + d |= ((YAMSTATE->rbp >> 13) & 0x7F); + break; + case 0x404: d = (1<<11) | (1 << 8); break; // MIDIInput, unimplemented + case 0x406: d = 0; break; // MIDI output, unimplemented + case 0x408: // CallAddress (playpos in increments of 4K) + { int c = (YAMSTATE->mslc) & 0x1F; + + if(YAMSTATE->out_pending > 0) yam_flush(YAMSTATE); + + d = calculate_playpos(YAMSTATE, YAMSTATE->chan + c); + d &= 0xF000; d >>= 5; + +// +// might only be checking when envstate is release anyway? +// + +// d |= (YAMSTATE->chan[c].envstate != 3) << 4; +//d |= 1<<3; + +// d |= (YAMSTATE->chan[c].lp & 1) << 4; +// YAMSTATE->chan[c].lp = 0; + + + +// +// here bit 3 seems to be set to 1 to indicate idle. +// what idle means, I haven't determined +// + +//d|=1<<3; + + //d|=(YAMSTATE->chan[c].sampler_dir!=0)<<4; +// d|=(YAMSTATE->chan[c].envlevel>=0x80)<<4; + +// d|=((YAMSTATE->chan[c].envlevel)&0x3FF)>>5; + + //if(YAMSTATE->chan[c].envstate >= 1) { + // d |= 1<<4; + // d|=(YAMSTATE->chan[c].envlevel>=0x100)<<3; + //} +// //d |= 1<<3; +// d |= (YAMSTATE->chan[c].envlevel >= 0x80) << 3; +// +// d |= (YAMSTATE->chan[c].sampler_dir!=0) << 3; +//d|=1<<3; + + // if 1<<3 always set: missing notes + // if 1<<3 never set: notes get cut off early, but most are there + // if it's >=0x300: missing notes + // if it's >=0x3C0: missing notes + // if it's <0x300: notes get cut off early + +// close but missing notes +// d |= (YAMSTATE->chan[c].envstate == 3) << 4; +// d |= (YAMSTATE->chan[c].envlevel >= 0x281) << 3; + + +// d |= 1<<4; + +// d |= (YAMSTATE->chan[c].envlevel >= 0x281) << 3; +// d |= (YAMSTATE->chan[c].envstate != 3) << 3; + +// d |= (YAMSTATE->chan[c].sampler_dir == 0) << 4; + + //d |= ((YAMSTATE->chan[c].envlevel) & 0x1FFF) >> 3; + +//d ^= 0x00; // few +//d ^= 0x67; // few (these bits have no effect) +//d ^= 0x7F; // many missing notes +//d ^= 1<<4; // few +//d ^= 1<<3; // few +//d ^= 3<<3; // many missing notes + +// only updates when hardware bit 1<<4 is 1 +// hardware bit 1<<3 means idle? + + + +// ok but wrong +// d |= (((uint32)(YAMSTATE->chan[c].envstate)) & 3) << 5; +// d |= ((YAMSTATE->chan[c].envlevel) & 0x3FF) >> 5; +// d ^= 0x7F; + + +// { uint32 l = (YAMSTATE->chan[c].envlevel) & (YAMSTATE->chan[c].envlevelmask[YAMSTATE->chan[c].envstate & 3]); +// if(l>0x3BF)l=0x1FFF; +// if(YAMSTATE->chan[c].sampler_dir == 0) l=0x1FFF; +//d|=(l>=0x3C0)<<3; +//d|=(l>=0x3C0)<<4; +// d |= l >> 8; +// if(l>=0x3BF) d|=0<<3; +//d|=l>>5; +// } + + +//d^=0x1C; +// d |= ((YAMSTATE->chan[c].envlevel) & 0x1FFF) >> 8; + +//{ uint32 es = ((uint32)(YAMSTATE->chan[c].envstate)) & 3; +// es = 0; +// if(YAMSTATE->chan[c].sampler_dir == 0) es = 3; +// d |= es << 3; +//} + +//d ^= 0x18; +//d |= 0x00; + + } + + break; + case 0x412: + d = YAMSTATE->dmea & 0xFFFF; + break; + case 0x414: + d = (((uint32)(YAMSTATE->dmea)) & 0xF0000) >> 4; + d |= (((uint32)(YAMSTATE->drga)) & 0xFFE) << 0; + break; + case 0x416: + d = (((uint32)(YAMSTATE->dtlg)) & 0xFFE) << 0; + break; + case 0x418: + d = (((uint32)(YAMSTATE->tctl[0])) & 0x7) << 8; + d |= (((uint32)(YAMSTATE->tim[0])) & 0xFF) << 0; + break; + case 0x41A: + d = (((uint32)(YAMSTATE->tctl[1])) & 0x7) << 8; + d |= (((uint32)(YAMSTATE->tim[1])) & 0xFF) << 0; + break; + case 0x41C: + d = (((uint32)(YAMSTATE->tctl[2])) & 0x7) << 8; + d |= (((uint32)(YAMSTATE->tim[2])) & 0xFF) << 0; + break; + case 0x41E: d = YAMSTATE->scieb & 0x07FF; break; + case 0x420: d = YAMSTATE->scipd & 0x07FF; break; + case 0x424: d = YAMSTATE->scilv0 & 0xFF; break; + case 0x426: d = YAMSTATE->scilv1 & 0xFF; break; + case 0x428: d = YAMSTATE->scilv2 & 0xFF; break; + case 0x42A: d = YAMSTATE->mcieb & 0x07FF; break; + case 0x42C: d = YAMSTATE->mcipd & 0x07FF; break; + } + return d & mask; +} + +void EMU_CALL yam_scsp_store_reg(void *state, uint32 a, uint32 d, uint32 mask, uint8 *breakcpu) { + a &= 0xFFE; + d &= 0xFFFF & mask; + mask &= 0xFFFF; + if(a < 0x400) { chan_scsp_store_reg(YAMSTATE, a>>5, a&0x1E, d, mask); return; } + if(a >= 0x700) { dsp_scsp_store_reg(YAMSTATE, a, d, mask); return; } + if(a >= 0x600) { uint32 offset = (YAMSTATE->bufptr-64+(a-0x600)/2)&(32*RINGMAX-1); YAMSTATE->ringbuf[offset] = (d & mask) | (YAMSTATE->ringbuf[offset] & ~mask); return; } + switch(a) { + case 0x400: // MasterVolume + yam_flush(YAMSTATE); + if(mask & 0x00FF) { + YAMSTATE->mvol = d & 0xF; + } + break; + case 0x402: // RingBufferAddress + { uint32 oldrbp = YAMSTATE->rbp; + uint8 oldrbl = YAMSTATE->rbl; + if(mask & 0x00FF) { + YAMSTATE->rbp = (((uint32)d) & 0x7F) << 13; + YAMSTATE->rbl &= 2; + YAMSTATE->rbl |= (d >> 7) & 1; + } + if(mask & 0xFF00) { + YAMSTATE->rbl &= 1; + YAMSTATE->rbl |= (d >> 7) & 2; + } + if((oldrbp != YAMSTATE->rbp) || (oldrbl != YAMSTATE->rbl)) { + uint32 newrbp = YAMSTATE->rbp; + uint8 newrbl = YAMSTATE->rbl; + YAMSTATE->rbp = oldrbp; + YAMSTATE->rbl = oldrbl; + yam_flush(YAMSTATE); + YAMSTATE->dsp_dyna_valid = 0; + YAMSTATE->rbp = newrbp; + YAMSTATE->rbl = newrbl; + } + } + break; + case 0x408: // ChnInfoReq + if(mask & 0xFF00) { + YAMSTATE->mslc = (d >> 11) & 0x1F; + } + break; + case 0x412: // DMA + if(mask & 0x00FF) { YAMSTATE->dmea = (YAMSTATE->dmea & 0xFFF00) | (d & 0xFF); } + if(mask & 0xFF00) { YAMSTATE->dmea = (YAMSTATE->dmea & 0xF00FF) | (d & 0xFF00); } + break; + case 0x414: + if(mask & 0xFF) { YAMSTATE->drga = (YAMSTATE->drga & 0xF00) | (d & 0xFE); } + if(mask & 0xFF00) { YAMSTATE->drga = (YAMSTATE->drga & 0x0FF) | (d & 0xF00); YAMSTATE->dmea = (YAMSTATE->dmea & 0xFFFF) | ((d & 0xF000) << 4); } + break; + case 0x416: + if(mask & 0xFF) { YAMSTATE->dtlg = (YAMSTATE->dtlg & 0xF00) | (d & 0xFE); } + if(mask & 0xFF00) { YAMSTATE->dtlg = (YAMSTATE->dtlg & 0xFF) | (d & 0xF00); } + break; + case 0x418: // TimerAControl + if(mask & 0x00FF) { YAMSTATE->tim[0] = d & 0xFF; } + if(mask & 0xFF00) { YAMSTATE->tctl[0] = (d >> 8) & 7; } + if(breakcpu) *breakcpu = 1; + break; + case 0x41A: // TimerBControl + if(mask & 0x00FF) { YAMSTATE->tim[1] = d & 0xFF; } + if(mask & 0xFF00) { YAMSTATE->tctl[1] = (d >> 8) & 7; } + if(breakcpu) *breakcpu = 1; + break; + case 0x41C: // TimerCControl + if(mask & 0x00FF) { YAMSTATE->tim[2] = d & 0xFF; } + if(mask & 0xFF00) { YAMSTATE->tctl[2] = (d >> 8) & 7; } + if(breakcpu) *breakcpu = 1; + break; + case 0x41E: // SCIEB + YAMSTATE->scieb = (((YAMSTATE->scieb) & (~mask)) | (d & mask)) & 0x7FF; + if(breakcpu) *breakcpu = 1; + break; + case 0x420: // SCIPD + YAMSTATE->scipd = (((YAMSTATE->scipd) & (~mask)) | (d & mask)) & 0x7FF; + if(breakcpu) *breakcpu = 1; + break; + case 0x422: // SCIRE + YAMSTATE->scipd &= ~(d & mask); + // I guess this is how we acknowledge interrupts now + sci_recompute(YAMSTATE); + if(breakcpu) *breakcpu = 1; + break; + case 0x424: // SCILV0 + if(mask & 0x00FF) { YAMSTATE->scilv0 = d; } + break; + case 0x426: // SCILV1 + if(mask & 0x00FF) { YAMSTATE->scilv1 = d; } + break; + case 0x428: // SCILV2 + if(mask & 0x00FF) { YAMSTATE->scilv2 = d; } + break; + case 0x42A: // MCIEB + YAMSTATE->mcieb = (((YAMSTATE->mcieb) & (~mask)) | (d & mask)) & 0x7FF; + break; + case 0x42C: // MCIPD + YAMSTATE->mcipd = (((YAMSTATE->mcipd) & (~mask)) | (d & mask)) & 0x7FF; + break; + case 0x42E: // MCIRE + YAMSTATE->mcipd &= ~(d & mask); + break; + } +} + +uint32 EMU_CALL yam_aica_load_reg(void *state, uint32 a, uint32 mask) { + uint32 d = 0; + a &= 0xFFFC; + if(a < 0x2000) return chan_aica_load_reg(YAMSTATE, a>>7, a&0x7C) & mask; + if(a >= 0x3000) return dsp_aica_load_reg(YAMSTATE, a) & mask; + if(a < 0x2048) { + d = + ((((uint32)(YAMSTATE->efsdl[(a - 0x2000) / 4])) & 0x0F) << 8) | + ((((uint32)(YAMSTATE->efpan[(a - 0x2000) / 4])) & 0x1F) << 0); + return d & mask; + } + switch(a) { + case 0x2800: d = 0x0010; break; // MasterVolume (actually returns the LSI version) + case 0x2804: // RingBufferAddress + d = (((uint32)(YAMSTATE->rbl)) & 3) << 13; + d |= ((YAMSTATE->rbp >> 11) & 0xFFF); + break; + case 0x2808: d = (1<<11) | (1 << 8); break; // MIDIInput, unimplemented + case 0x280C: d = 0; break; // ChnInfoReq, always seems to return 0 when read + case 0x2810: // PlayStatus +// if(YAMSTATE->out_pending > 100) yam_flush(YAMSTATE); + if(YAMSTATE->out_pending > 0) yam_flush(YAMSTATE); + { int c = (YAMSTATE->mslc) & 0x3F; + d = (((uint32)(YAMSTATE->chan[c].lp )) & 1) << 15; + if(YAMSTATE->afsel == 0) { + d |= (((uint32)(YAMSTATE->chan[c].envstate)) & 3) << 13; + d |= (YAMSTATE->chan[c].envlevel) & 0x1FFF; + } else { + d |= (((uint32)(YAMSTATE->chan[c].lpfstate)) & 3) << 13; + d |= (YAMSTATE->chan[c].lpflevel) & 0x1FFF; + } + } + break; + case 0x2814: d = calculate_playpos(YAMSTATE, YAMSTATE->chan + ((YAMSTATE->mslc) & 0x3F)); break; + case 0x2880: d = YAMSTATE->mrwinh & 0xF; break; + case 0x2884: d = 0; break; + case 0x2888: d = 0; break; + case 0x288C: d = 0; break; + case 0x2890: + d = (((uint32)(YAMSTATE->tctl[0])) & 0x7) << 8; + d |= (((uint32)(YAMSTATE->tim[0])) & 0xFF) << 0; + break; + case 0x2894: + d = (((uint32)(YAMSTATE->tctl[1])) & 0x7) << 8; + d |= (((uint32)(YAMSTATE->tim[1])) & 0xFF) << 0; + break; + case 0x2898: + d = (((uint32)(YAMSTATE->tctl[2])) & 0x7) << 8; + d |= (((uint32)(YAMSTATE->tim[2])) & 0xFF) << 0; + break; + case 0x289C: d = YAMSTATE->scieb & 0x07FF; break; + case 0x28A0: d = YAMSTATE->scipd & 0x07FF; break; + case 0x28A4: d = 0; break; + case 0x28A8: d = YAMSTATE->scilv0 & 0xFF; break; + case 0x28AC: d = YAMSTATE->scilv1 & 0xFF; break; + case 0x28B0: d = YAMSTATE->scilv2 & 0xFF; break; + case 0x28B4: d = YAMSTATE->mcieb & 0x07FF; break; + case 0x28B8: d = YAMSTATE->mcipd & 0x07FF; break; + case 0x28BC: d = 0; break; + case 0x2C00: d = 0; break; + case 0x2D00: d = YAMSTATE->intreq & 7; break; + case 0x2D04: d = 0; break; + case 0x2E00: d = YAMSTATE->rtc >> 16; break; + case 0x2E04: d = YAMSTATE->rtc; break; + } + return d & mask; +} + +void EMU_CALL yam_aica_store_reg(void *state, uint32 a, uint32 d, uint32 mask, uint8 *breakcpu) { + a &= 0xFFFC; + d &= 0xFFFF & mask; + if(a < 0x2000) { chan_aica_store_reg(YAMSTATE, a>>7, a&0x7C, d, mask); return; } + if(a >= 0x3000) { dsp_aica_store_reg(YAMSTATE, a, d, mask); return; } + if(a < 0x2048) { + if(mask & 0x00FF) { YAMSTATE->efpan[(a - 0x2000) / 4] = d & 0x1F; } + if(mask & 0xFF00) { YAMSTATE->efsdl[(a - 0x2000) / 4] = (d >> 8) & 0x0F; } + return; + } + switch(a) { + case 0x2800: // MasterVolume + yam_flush(YAMSTATE); + if(mask & 0x00FF) { + YAMSTATE->mvol = d & 0xF; + } + if(mask & 0xFF00) { + YAMSTATE->mono = (d >> 15) & 1; + } + break; + case 0x2804: // RingBufferAddress + { uint32 oldrbp = YAMSTATE->rbp; + uint8 oldrbl = YAMSTATE->rbl; + if(mask & 0x00FF) { + YAMSTATE->rbp >>= 11; + YAMSTATE->rbp &= 0xF00; + YAMSTATE->rbp |= d & 0x0FF; + YAMSTATE->rbp <<= 11; + } + if(mask & 0xFF00) { + YAMSTATE->rbp >>= 11; + YAMSTATE->rbp &= 0x0FF; + YAMSTATE->rbp |= d & 0xF00; + YAMSTATE->rbp <<= 11; + YAMSTATE->rbl = (d >> 13) & 3; + } + if((oldrbp != YAMSTATE->rbp) || (oldrbl != YAMSTATE->rbl)) { + uint32 newrbp = YAMSTATE->rbp; + uint8 newrbl = YAMSTATE->rbl; + YAMSTATE->rbp = oldrbp; + YAMSTATE->rbl = oldrbl; + yam_flush(YAMSTATE); + YAMSTATE->dsp_dyna_valid = 0; + YAMSTATE->rbp = newrbp; + YAMSTATE->rbl = newrbl; + } + } + break; + case 0x2808: // MIDIInput, unimplemented + break; + case 0x280C: // ChnInfoReq + if(mask & 0x00FF) { + // MIDI output buffer, unimplemented + } + if(mask & 0xFF00) { + YAMSTATE->mslc = (d >> 8) & 0x3F; + YAMSTATE->afsel = (d >> 14) & 1; + } + break; + case 0x2810: break; // PlayStatus - writing probably has no effect. + case 0x2814: break; // PlayPos - writing probably has no effect. + case 0x2880: // misc. + if(mask & 0x00FF) { + YAMSTATE->mrwinh = d & 0xF; + } + break; + case 0x2884: break; // misc. + case 0x2888: break; // misc. + case 0x288C: break; // misc. + case 0x2890: // TimerAControl + if(mask & 0x00FF) { YAMSTATE->tim[0] = d & 0xFF; } + if(mask & 0xFF00) { YAMSTATE->tctl[0] = (d >> 8) & 7; } + if(breakcpu) *breakcpu = 1; + break; + case 0x2894: // TimerBControl + if(mask & 0x00FF) { YAMSTATE->tim[1] = d & 0xFF; } + if(mask & 0xFF00) { YAMSTATE->tctl[1] = (d >> 8) & 7; } + if(breakcpu) *breakcpu = 1; + break; + case 0x2898: // TimerCControl + if(mask & 0x00FF) { YAMSTATE->tim[2] = d & 0xFF; } + if(mask & 0xFF00) { YAMSTATE->tctl[2] = (d >> 8) & 7; } + if(breakcpu) *breakcpu = 1; + break; + case 0x289C: // SCIEB + YAMSTATE->scieb = (((YAMSTATE->scieb) & (~mask)) | (d & mask)) & 0x7FF; + if(breakcpu) *breakcpu = 1; + break; + case 0x28A0: // SCIPD + YAMSTATE->scipd = (((YAMSTATE->scipd) & (~mask)) | (d & mask)) & 0x7FF; + if(breakcpu) *breakcpu = 1; + break; + case 0x28A4: // SCIRE + YAMSTATE->scipd &= ~(d & mask); + if(breakcpu) *breakcpu = 1; + break; + case 0x28A8: // SCILV0 + if(mask & 0x00FF) { YAMSTATE->scilv0 = d; } + break; + case 0x28AC: // SCILV1 + if(mask & 0x00FF) { YAMSTATE->scilv1 = d; } + break; + case 0x28B0: // SCILV2 + if(mask & 0x00FF) { YAMSTATE->scilv2 = d; } + break; + case 0x28B4: // MCIEB + YAMSTATE->mcieb = (((YAMSTATE->mcieb) & (~mask)) | (d & mask)) & 0x7FF; + break; + case 0x28B8: // MCIPD + YAMSTATE->mcipd = (((YAMSTATE->mcipd) & (~mask)) | (d & mask)) & 0x7FF; + break; + case 0x28BC: // MCIRE + YAMSTATE->mcipd &= ~(d & mask); + break; + case 0x2C00: // ARMReset + break; + case 0x2D00: // INTRequest + break; + case 0x2D04: // INTClear + // running through the recompute will clear the previous interrupt + // as well as enabling the next one, if there is a next one + sci_recompute(YAMSTATE); + if(breakcpu) *breakcpu = 1; + break; + case 0x2E00: // RTCHi + break; + case 0x2E04: // RTCLo + break; + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Generate random data +// +static uint32 yamrand16(struct YAM_STATE *state) { + state->randseed = 1103515245 * state->randseed + 12345; + return state->randseed >> 16; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Envelope-related calculations +// + +// +// Adjust actual rate to get effective rate +// +static uint32 env_adjustrate(struct YAM_CHAN *chan, uint32 rate) { + sint32 effrate = rate * 2; + if(chan->krs < 0xF) { + effrate += (chan->fns >> 9) & 1; + effrate += chan->krs * 2; + effrate = (effrate - 8) + (chan->oct ^ 8); + } + // Clipping is important because of the table lookups + if(effrate <= 0) return 0; + if(effrate >= 0x3C) return 0x3C; + return effrate; +} + +// +// Determine whether a step is going to occur here +// +static int env_needstep(uint32 effrate, uint32 odometer) { + uint32 shift; + uint32 pattern; + uint32 bitplace; + if(effrate <= 0x01) return 0; + if(effrate >= 0x30) return ((odometer & 1) == 0); + shift = 12 - ((effrate - 1) >> 2); + pattern = (effrate - 1) & 3; + if(odometer & ((1<> shift) & 7; + return (0xFFFDDDD5 >> (pattern * 8 + bitplace)) & 1; + // 11010101 0x01 each bit is 4096 samples + // 11011101 0x02 + // 11111101 0x03 + // 11111111 0x04 +} + +///////////////////////////////////////////////////////////////////////////// +// +// Read next sample +// +static void readnextsample( + struct YAM_STATE *state, + struct YAM_CHAN *chan, + sint32 sample_offset, + uint8 advance +) { + sint32 s = 0; + // + // If the sampler is inactive, simply write 0 + // + if(!(chan->sampler_dir)) goto done; + // + // Process envelope link and lowpass phase reset + // + if(advance && chan->playpos == chan->loopstart) { + if(chan->link && chan->envstate == 0) { chan->envstate = 1; } + if(chan->lfore) chan->lfophase = 0; + // and save adpcm loop-start values + if(!(chan->adpcminloop)) { + chan->adpcmstep_loopstart = chan->adpcmstep; + chan->adpcmprev_loopstart = chan->adpcmprev; + chan->adpcminloop = 1; + } + // maybe do something if the loop type is fancy + switch(chan->sampler_looptype) { + case LOOP_NONE: + case LOOP_FORWARDS: + break; + case LOOP_BACKWARDS: + chan->playpos = chan->loopend - 1; + chan->playpos &= 0xFFFF; + chan->sampler_dir = -1; + break; + case LOOP_BIDIRECTIONAL: + chan->sampler_dir = 1; + break; + } + } + // + // Obtain sample + // + switch(chan->pcms) { + case 0: // 16-bit signed LSB-first + s = *(sint16*)(((sint8*)(state->ram_ptr)) + (((chan->sampleaddr + 2 * (chan->playpos + sample_offset)) ^ (state->mem_word_address_xor)) & (state->ram_mask))); + s ^= chan->sampler_invert; + break; + case 1: // 8-bit signed + s = *(sint8*)(((sint8*)(state->ram_ptr)) + (((chan->sampleaddr + chan->playpos + sample_offset) ^ (state->mem_byte_address_xor)) & (state->ram_mask))); + s ^= chan->sampler_invert >> 8; + s <<= 8; + break; + case 2: // 4-bit ADPCM + s = *(uint8*)(((uint8*)(state->ram_ptr)) + (((chan->sampleaddr + (chan->playpos >> 1)) ^ (state->mem_byte_address_xor)) & (state->ram_mask))); + s >>= 4 * ((chan->playpos & 1) ^ 0); + s &= 0xF; + { sint32 out = chan->adpcmprev; + out += (chan->adpcmstep * adpcmdiff[s]) / 8; + if(out > ( 0x7FFF)) { out = ( 0x7FFF); /* logf(""); */ } + if(out < (-0x8000)) { out = (-0x8000); /* logf(""); */ } + chan->adpcmstep = (chan->adpcmstep * adpcmscale[s & 7]) >> 8; + if(chan->adpcmstep > 0x6000) { chan->adpcmstep = 0x6000; } + if(chan->adpcmstep < 0x007F) { chan->adpcmstep = 0x007F; } + chan->adpcmprev = out; + s = out; + } + break; + } + switch(chan->ssctl) { + case 0: break; + case 1: s = ((sint16)(yamrand16(state))); break; + case 2: s = 0; break; + case 3: s = 0; break; + } + // + // Advance play position + // + if(advance) { + chan->playpos += ((sint32)(chan->sampler_dir)); + chan->playpos &= 0xFFFF; + if(chan->playpos == chan->loopend) { + switch(chan->sampler_looptype) { + case LOOP_NONE: + chan->sampler_dir = 0; + chan->playpos = 0; + goto done; + case LOOP_FORWARDS: + chan->playpos = chan->loopstart; + chan->adpcmstep = chan->adpcmstep_loopstart; + chan->adpcmprev = chan->adpcmprev_loopstart; + chan->lp = 1; + break; + case LOOP_BACKWARDS: + break; + case LOOP_BIDIRECTIONAL: + chan->sampler_dir = -1; + chan->playpos -= 2; + chan->playpos &= 0xFFFF; + break; + } + } + } +done: + // + // Write the new sample + // + chan->samplebufcur = chan->samplebufnext; + chan->samplebufnext = s; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Generate samples +// Samples are returned in 20-bit format +// Returns the number of samples actually generated +// +static uint32 generate_samples( + struct YAM_STATE *state, + struct YAM_CHAN *chan, + sint32 *buf, + uint32 odometer, + uint32 samples +) { + uint32 g; + uint32 base_phaseinc; + uint32 lfophaseinc = lfophaseinctable[chan->lfof]; + uint32 bufptrsave = state->bufptr; + +//gfreq[samples]++; + +//printf("generate_samples(%08X,%08X,%u)\n",chan,buf,samples); + + { uint32 oct = chan->oct^8; + uint32 fns = chan->fns^0x400; + base_phaseinc = fns << oct; + // weird ADPCM thing mentioned in official doc + if(chan->pcms == 2 && oct >= 0xA) { base_phaseinc <<= 1; } + } + + for(g = 0; g < samples; g++) { +//buf[g]=g*100;continue; + // + // If the amp envelope is inactive, quit + // + if(chan->envlevel >= 0x3C0) { + chan->envlevel = 0x1FFF; + break; + } + // + // If we must generate a sample, generate it + // + if(buf) { + sint32 s, s_cur, s_next, f; + // Apply SCSP ring modulation, if necessary + if(state->version==1 && (chan->mdl!=0 || chan->mdxsl!=0 || chan->mdysl!=0)) { + sint32 smp=(state->ringbuf[(state->bufptr-64+chan->mdxsl)&(32*RINGMAX-1)]+state->ringbuf[(state->bufptr-64+chan->mdysl)&(32*RINGMAX-1)])/2; + smp<<=0xA; // associate cycle with 1024 + smp>>=0x1A-chan->mdl; // ex. for MDL=0xF, sample range corresponds to +/- 64 pi (32=2^5 cycles) so shift by 11 (16-5 == 0x1A-0xF) + readnextsample(state, chan, smp, 0); + readnextsample(state, chan, smp+1, 0); + } + // Generate interpolated sample + s_cur = chan->samplebufcur; + s_next = chan->samplebufnext; + f = ((chan->frcphase) >> 4) & 0x3FFF; + s = (s_next * f) + (s_cur * (0x4000-f)); + s >>= 14; // s is 16-bit + // Apply attenuation, if we want it + if(!(chan->voff)) { + uint32 attenuation; + sint32 linearvol; + attenuation = ((uint32)(chan->tl)) << 2; + attenuation += ((uint32)(chan->envlevel)) & ((uint32)(chan->envlevelmask[chan->envstate])); + // LFO amplitude modulation + if(chan->alfos) { + uint32 att_wave_y = 0; + switch(chan->alfows) { + case 0: // sawtooth + att_wave_y = ((uint32)(chan->lfophase)) >> 24; + break; + case 1: // square + att_wave_y = (((sint32)(chan->lfophase)) >> 31) & 0xFF; + break; + case 2: // triangle + att_wave_y = (chan->lfophase >> 23) & 0xFF; + if(chan->lfophase & 0x80000000) { att_wave_y ^= 0xFF; } + break; + case 3: // noise + att_wave_y = yamrand16(state) & 0xFF; + break; + } + attenuation += (att_wave_y >> (7 - (chan->alfos))); + } + if(attenuation >= 0x3C0) { + s = 0; + } else { + // Convert log attenuation to linear volume + linearvol = ((attenuation & 0x3F) ^ 0x7F) + 1; + s *= linearvol; s >>= 7 + (attenuation >> 6); + } + } + // Store in ring modulation buffer, if we're SCSP and it's enabled + if(state->version == 1 && !chan->stwinh) { + state->ringbuf[state->bufptr] = s; + } + // Apply filter, if we want it + if(!(chan->lpoff)) { + uint32 fv = chan->lpflevel; + uint32 qv = chan->q & 0x1F; + sint32 f = (((fv & 0xFF) | 0x100) << 4) >> ((fv >> 8) ^ 0x1F); + sint32 q = qtable[qv]; + s = f * s + (0x2000 - f + q) * (chan->lpp1) - q * (chan->lpp2); + s >>= 13; + chan->lpp2 = chan->lpp1; + chan->lpp1 = s; + } + // Write output + s <<= 4; + buf[g] = s; + } + state->bufptr = (state->bufptr + 32) & (32*RINGMAX-1); + // + // Now we need to advance the channel state machine, regardless of + // whether we're generating output or not + // + // + // Advance LFO phase + // + chan->lfophase += lfophaseinc; + // + // Advance amplitude envelope + // + { uint32 effectiverate = env_adjustrate(chan, chan->ar[chan->envstate]); + if(env_needstep(effectiverate, odometer)) { + switch(chan->envstate) { + case 0: // attack + chan->envlevel -= (chan->envlevel >> envattackshift[effectiverate][odometer&3]) + 1; + if(chan->envlevel == 0) { chan->envstate = 1; } + break; + case 1: // decay + chan->envlevel += envdecayvalue[effectiverate][odometer&3]; + if((chan->envlevel >> 5) >= chan->dl) { chan->envstate = 2; } + break; + case 2: // sustain + case 3: // release + chan->envlevel += envdecayvalue[effectiverate][odometer&3]; + break; + } + } + } + // + // Advance filter envelope + // + { uint32 effectiverate = env_adjustrate(chan, chan->fr[chan->lpfstate]); + if(env_needstep(effectiverate, odometer)) { + uint32 d = envdecayvalue[effectiverate][odometer&3]; + uint32 target = chan->flv[chan->lpfstate+1]; + if(chan->lpflevel < target) { + uint32 maxd = target - chan->lpflevel; + if(d > maxd) { d = maxd; } + chan->lpflevel += d; + } else if(chan->lpflevel > target) { + uint32 maxd = chan->lpflevel - target; + if(d > maxd) { d = maxd; } + chan->lpflevel -= d; + } else { + if(chan->lpfstate < 3) { chan->lpfstate++; } + } + } + } + // + // Advance the sample phase + // + { uint32 realphaseinc = base_phaseinc; + // + // LFO pitch shifting + // + if(chan->plfos) { + uint32 pitch_wave_y = 0; + switch(chan->plfows) { + case 0: // sawtooth + pitch_wave_y = chan->lfophase ^ 0x80000000; + break; + case 1: // square + pitch_wave_y = (chan->lfophase & 0x80000000) ? 0 : 0xFFFFFFFF; + break; + case 2: // triangle + pitch_wave_y = (chan->lfophase << 1) + 0x80000000; + if(chan->lfophase >= 0x40000000 && chan->lfophase < 0xC0000000) { + pitch_wave_y = ~pitch_wave_y; + } + break; + case 3: // noise + pitch_wave_y = yamrand16(state) << 16; + break; + } + { uint32 maxvary = base_phaseinc >> (10-(chan->plfos)); + uint32 scaled_pitch_wave_y = + (((uint64)(maxvary*2)) * ((uint64)pitch_wave_y)) >> 32; + realphaseinc = base_phaseinc + scaled_pitch_wave_y - maxvary; + } + } + // + // Advance phase, and read new sample data if necessary + // + chan->frcphase += realphaseinc; + while(chan->frcphase >= 0x40000) { + chan->frcphase -= 0x40000; + readnextsample(state, chan, 0, 1); + } + } + // Advance our temporary odometer copy + odometer++; + // Done with this sample! + } + state->bufptr = bufptrsave; + return g; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Render a single channel and add it to the given outputs +// +// directout or fxout may be NULL +// +static void render_and_add_channel( + struct YAM_STATE *state, + struct YAM_CHAN *chan, + sint32 *directout, + sint32 *fxout, + uint32 odometer, + uint32 samples +) { + uint32 i; + sint32 localbuf[RENDERMAX]; + uint32 rendersamples; + + // Channel does nothing if attenuation >= 0x3C0 + if(chan->envlevel >= 0x3C0) { chan->envlevel = 0x1FFF; return; } + + if(!chan->disdl) { directout = NULL; } + if(!chan->dsplevel) { fxout = NULL; } + + // Generate samples + rendersamples = generate_samples( + state, + chan, + (!chan->mute && (directout || fxout || (state->version == 1 && !chan->stwinh))) ? localbuf : NULL, + odometer, + samples + ); + + // Add to output + if(directout) { + uint8 att_l, att_r; + sint32 lin_l, lin_r; + convert_stereo_send_level( + chan->disdl, + (state->mono) ? 0 : (chan->dipan), + &att_l, &att_r, &lin_l, &lin_r + ); + for(i = 0; i < rendersamples; i++) { + directout[0] += (localbuf[i]*lin_l) >> att_l; + directout[1] += (localbuf[i]*lin_r) >> att_r; + directout += 2; + } + } + if(fxout) { + uint32 att = (chan->dsplevel) ^ 0xF; + sint32 lin = 4 - (att & 1); + att >>= 1; att += 2; + for(i = 0; i < rendersamples; i++) { + fxout[0] += (localbuf[i]*lin) >> att; + fxout += 16; + } + } + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Floating-point conversion +// +static uint32 __fastcall float16_to_int24(uint32 f) { + uint32 exponent = (f >> 11) & 0xF; + sint32 result; + result = (f & 0x8000) << 16; // take the sign in bit 31 + result >>= 1; // duplicate the sign in bit 30 + if(exponent >= 12) { exponent = 11; } // cap exponent to 11 for denormals + else { result ^= 0x40000000; } // reverse bit 30 for normals + result |= (f & 0x7FF) << 19; // set bits 29-0 to the mantissa + result >>= exponent + 8; // shift right by the exponent + 8 + return result; +} + +static uint32 __fastcall int24_to_float16(uint32 i) { + uint32 exponent = 0; + uint32 sign = i & 0x00800000; + if(sign) { i = ~i; } + i &= 0x7FFFFF; + if(i < 0x020000) { exponent += (6<<11); i <<= 6; } + if(i < 0x100000) { exponent += (3<<11); i <<= 3; } + if(i < 0x400000) { exponent += (1<<11); i <<= 1; } + if(i < 0x400000) { exponent += (1<<11); i <<= 1; } + if(i < 0x400000) { exponent += (1<<11); } + i >>= 11; + i &= 0x7FF; + i |= exponent; + if(sign) { i ^= 0x87FF; } + return i; +} + +///////////////////////////////////////////////////////////////////////////// + +#define SINT32ATOFFSET(a,b) (*((sint32*)(((uint8*)(a))+(b)))) + +///////////////////////////////////////////////////////////////////////////// +// +// Execute one sample on the effects DSP +// +static void __fastcall dsp_sample_interpret(struct YAM_STATE *state) { + const struct MPRO *mpro = state->mpro; + uint32 i; + // Pre-compute ringbuffer size mask + uint32 rbmask = (1 << ((state->rbl)+13)) - 1; + // + // For 128 steps: + // + for(i = 0; i < 128; i++, mpro++) { + sint32 b, x, y, shifted; + // + // Proper skip for "empty" instructions + // + if((mpro->__kisxzbon) & 0x80) { + x = state->temp[(state->mdec_ct)&0x7F]; + state->xzbchoice[XZBCHOICE_ACC] = + ((((sint64)x) * ((sint64)(state->yychoice[YYCHOICE_FRC_REG]))) >> 12) + x; + continue; + } + state->xzbchoice[XZBCHOICE_TEMP] = state->temp[((mpro->t_0rrrrrrr)+(state->mdec_ct))&0x7F]; + state->yychoice[YYCHOICE_COEF] = state->coef[mpro->c_0rrrrrrr]; + // + // Input read + // + state->xzbchoice[XZBCHOICE_INPUTS] = state->inputs[mpro->i_00rrrrrr]; + // + // Input write + // + state->inputs[mpro->i_0T0wwwww] = state->mem_in_data[i & 3]; + // + // B selection + // + b = SINT32ATOFFSET(state->xzbchoice, (mpro->__kisxzbon) & 0x0C); + b ^= ((sint32)(mpro->negb)); + b -= ((sint32)(mpro->negb)); + // + // X selection + // + x = SINT32ATOFFSET(state->xzbchoice, (mpro->__kisxzbon) & 0x10); + // + // Y selection + // + y = SINT32ATOFFSET(state->yychoice, (mpro->m_wrAFyyYh) & 0x0C); + // + // Y latch + // + if(mpro->m_wrAFyyYh & 2) { + sint32 inputs = state->xzbchoice[XZBCHOICE_INPUTS]; + state->yychoice[YYCHOICE_Y_REG_H] = inputs >> 11; + state->yychoice[YYCHOICE_Y_REG_L] = (inputs >> 4) & 0xFFF; + } + // + // Shift of previous accumulator + // + shifted = state->xzbchoice[XZBCHOICE_ACC] << ((mpro->m_wrAFyyYh) & 1); + if((mpro->__kisxzbon) & 0x20) { + if(shifted > ( 0x7FFFFF)) { shifted = ( 0x7FFFFF); } + if(shifted < (-0x800000)) { shifted = (-0x800000); } + } + // + // Multiply and accumulate + // + state->xzbchoice[XZBCHOICE_ACC] = ((((sint64)x) * ((sint64)y)) >> 12) + b; + // + // Temp write + // + if(mpro->t_Twwwwwww < 0x80) { + state->temp[((mpro->t_Twwwwwww)+(state->mdec_ct))&0x7F] = shifted; + } + // + // Fractional address latch + // + if((mpro->m_wrAFyyYh) & 0x10) { + if((mpro->__kisxzbon) & 0x40) { + state->yychoice[YYCHOICE_FRC_REG] = shifted & 0xFFF; + } else { + state->yychoice[YYCHOICE_FRC_REG] = shifted >> 11; + } + } + // + // Memory operations + // + if((mpro->m_wrAFyyYh) & 0xC0) { + sint32 tm = ((sint32)(mpro->tablemask)); + uint32 a = state->madrs[mpro->m_00aaaaaa]; + a += (state->adrs_reg) & ((sint32)(mpro->adrmask)); + a += (mpro->__kisxzbon) & 1; + a += (state->mdec_ct) & (~tm); + a &= (rbmask | tm) & 0xFFFF; + a <<= 1; + a += state->rbp; + a &= (state->ram_mask); + a ^= state->mem_word_address_xor; + if(mpro->m_wrAFyyYh & 0x40) { // MRD + sint32 memdata = *((sint16*)(((sint8*)(state->ram_ptr))+a)); + if(!(mpro->__kisxzbon & 2)) { memdata = float16_to_int24(memdata); } + else { memdata <<= 8; } + state->mem_in_data[(i+2)&3] = memdata; + } + if(mpro->m_wrAFyyYh & 0x80) { // MWT + sint32 memdata = shifted; + if(!(mpro->__kisxzbon & 2)) { memdata = int24_to_float16(memdata); } + else { memdata >>= 8; } + *((sint16*)(((sint8*)(state->ram_ptr))+a)) = memdata; + } + } + // + // Address latch + // + if((mpro->m_wrAFyyYh) & 0x20) { + if((mpro->__kisxzbon) & 0x40) { + state->adrs_reg = shifted >> 12; + } else { + state->adrs_reg = state->xzbchoice[XZBCHOICE_INPUTS] >> 16; + } + state->adrs_reg &= 0xFFF; + } + // + // Effect output write + // + state->efreg[mpro->e_000Twwww] = shifted >> 8; + // End of step + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// +// + +#define C(N) { *outp++ = ((uint8)(N)); } +#define C32(N) { *((uint32*)outp) = ((uint32)(N)); outp += 4; } +#define C32CALL(N) { *((uint32*)outp) = ((uint32)(N)) - (((uint32)(outp))+4); outp += 4; } + +#define STRUCTOFS(thetype,thefield) ((uint32)(&(((struct thetype*)0)->thefield))) +#define STATEOFS(thefield) STRUCTOFS(YAM_STATE,thefield) + +static int instruction_uses_shifted(struct MPRO *mpro) { + // uses SHIFTED if: + // - ADRL and INTERP + if((mpro->m_wrAFyyYh & 0x20) != 0) { + if((mpro->__kisxzbon & 0x40) != 0) return 1; + } + // - FRCL + if((mpro->m_wrAFyyYh & 0x10) != 0) return 1; + // - EWT + if((mpro->e_000Twwww & 0x10) == 0) return 1; + // - TWT + if((mpro->t_Twwwwwww & 0x80) == 0) return 1; + // - MWT + if((mpro->m_wrAFyyYh & 0x80) != 0) return 1; + // otherwise not + return 0; +} + +// +// Compile x86 code out of the current DSP program/coef/address set +// Also uses the current ringbuffer pointer and size, and ram pointer/mask/memwordxor +// So if any of those change, the compiled dynacode must be invalidated +// +static void dynacompile(struct YAM_STATE *state) { + // Pre-compute ringbuffer size mask + uint32 rbmask = (1 << ((state->rbl)+13)) - 1; + + uint8 *outp = state->dynacode; + int i; + char ins_uses_acc[129]; + char ins_uses_shifted[129]; + // + // Put some slop here to avoid cache problems? + // + outp += DYNACODE_SLOP_SIZE; + // + // Figure out which instructions need what things + // + memset(ins_uses_acc, 0, sizeof(ins_uses_acc)); + memset(ins_uses_shifted, 0, sizeof(ins_uses_shifted)); + ins_uses_acc[128] = 1; + ins_uses_shifted[128] = 1; + for(i = 0; i < 128; i++) { + struct MPRO *mpro = state->mpro + i; + ins_uses_shifted[i] = instruction_uses_shifted(mpro); + ins_uses_acc[i] = + (ins_uses_shifted[i]) || + ((mpro->__kisxzbon & 0x0C) == 0x04); + } + + // + // Prefix + // + C(0x60) // pusha + C(0x89) C(0xCF) // mov edi, ecx + C(0x8B) C(0xAF) C32(STATEOFS(mdec_ct)) // mov ebp,[edi+] + C(0x8B) C(0xB7) C32(STATEOFS(xzbchoice[XZBCHOICE_ACC])) // mov esi,[edi+] + // 16 bytes + // + // Each instruction + // + for(i = 0; i < 128; i++) { + struct MPRO *mpro = state->mpro + i; + // + // If we need to compute the new accumulator, do so (to EAX) + // + if(ins_uses_acc[i + 1]) { + int need_tra = + ((mpro->__kisxzbon & 0x10) == 0x00) || + ((mpro->__kisxzbon & 0x0C) == 0x00); + // + // If we will need TRA in the future, compute it in ECX + // + if(need_tra) { + C(0x8D) C(0x4D) C(mpro->t_0rrrrrrr) // lea ecx,[ebp+] + C(0x83) C(0xE1) C(0x7F) // and ecx,7Fh + } + // 6 bytes max + // + // Load EAX with the Y value + // + switch(mpro->m_wrAFyyYh & 0x0C) { + case 0x00: // FRC_REG + C(0x8B) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_FRC_REG])) // mov eax,[edi+yychoice0] + break; + case 0x04: // COEF + { sint32 coef = state->coef[mpro->c_0rrrrrrr]; + C(0xB8) C32(coef) // mov eax, + } + break; + case 0x08: // Y_REG_H + C(0x8B) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_H])) // mov eax,[edi+yychoice2] + break; + case 0x0C: // Y_REG_L + C(0x8B) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_L])) // mov eax,[edi+yychoice3] + break; + } + // 6 bytes max + // + // Multiply by the X value + // + if((mpro->__kisxzbon & 0x10) == 0) { + C(0xF7) C(0xAC) C(0x8F) C32(STATEOFS(temp)) // imul dword ptr [edi+ecx*4+temp] + } else { + C(0xF7) C(0xAF) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) // imul dword ptr [edi+] + } + C(0x0F) C(0xAC) C(0xD0) C(0x0C) // shrd eax,edx,12 + // 11 bytes max + // + // Add B if necessary + // + if((mpro->__kisxzbon & 0x08) == 0) { + if(mpro->negb == 0) { + if((mpro->__kisxzbon & 0x04) == 0) { + C(0x03) C(0x84) C(0x8F) C32(STATEOFS(temp)) // add eax,[edi+ecx*4+] + } else { + C(0x01) C(0xF0) // add eax,esi + } + } else { + if((mpro->__kisxzbon & 0x04) == 0) { + C(0x2B) C(0x84) C(0x8F) C32(STATEOFS(temp)) // sub eax,[edi+ecx*4+] + } else { + C(0x29) C(0xF0) // sub eax,esi + } + } + } + // 7 bytes max + } + // 30 bytes max + // + // If YRL is on, latch Y register + // + if(mpro->m_wrAFyyYh & 2) { + C(0x8B) C(0x97) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) // mov edx, [edi+] + C(0xC1) C(0xFA) C(0x0B) // sar edx,11 + C(0x89) C(0x97) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_H])) // mov [edi+],edx + C(0x8B) C(0x97) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) // mov edx, [edi+] + C(0xC1) C(0xFA) C(0x04) // sar edx,4 + C(0x81) C(0xE2) C32(0x00000FFF) // and edx,0FFFh + C(0x89) C(0x97) C32(STATEOFS(yychoice[YYCHOICE_Y_REG_L])) // mov [edi+],edx + } + // 36 bytes max + // + // If we will be needing SHIFTED this instruction, edx will become SHIFTED: + // + if(ins_uses_shifted[i]) { + if((mpro->__kisxzbon & 0x20) == 0) { // no saturate + C(0x89) C(0xF2) // mov edx,esi + C(0xC1) C(0xE2) C(8+(mpro->m_wrAFyyYh & 1)) // shl edx, + C(0xC1) C(0xFA) C(0x08) // sar edx,8 + // 8 bytes max + } else { // saturate + if((mpro->m_wrAFyyYh & 1) == 0) { // NOT shifting left + C(0x8D) C(0x96) C32(0x00800000) // lea edx,[esi+800000h] + C(0xF7) C(0xC2) C32(0xFF000000) // test edx,0FF000000h + C(0x89) C(0xF2) // mov edx,esi + // 14 bytes max + } else { // shifting left + C(0x8D) C(0x94) C(0x36) C32(0x00800000) // lea edx,[esi+esi+800000h] + C(0xF7) C(0xC2) C32(0xFF000000) // test edx,0FF000000h + C(0x8D) C(0x14) C(0x36) // lea edx,[esi+esi] + // 16 bytes max + } + C(0x72) C(0x09) // jb +9bytes + C(0xC1) C(0xFA) C(0x1F) // sar edx,1Fh + C(0x81) C(0xF2) C32(0x007FFFFF) // xor edx,7FFFFFh + // 27 bytes max + } + } + // 27 bytes max + // + // If we need the accumulator next instruction, save it + // + if(ins_uses_acc[i + 1]) { + C(0x89) C(0xC6) // mov esi,eax + } + // 2 bytes max + // + // If FRCL is set, latch it + // + if(mpro->m_wrAFyyYh & 0x10) { + C(0x89) C(0xD0) //mov eax,edx + if(mpro->__kisxzbon & 0x40) { // interpolate mode + C(0x25) C32(0x00000FFF) // and eax,0FFFh + } else { // non-interpolate mode + C(0xC1) C(0xF8) C(0x0B) // sar eax,11 + } + C(0x89) C(0x87) C32(STATEOFS(yychoice[YYCHOICE_FRC_REG])) // mov [edi+],eax + } + // 13 bytes max + // + // If TWT is on, perform the temp write of SHIFTED + // + if((mpro->t_Twwwwwww & 0x80) == 0) { + C(0x8D) C(0x4D) C(mpro->t_Twwwwwww) // lea ecx,[ebp+] + C(0x83) C(0xE1) C(0x7F) // and ecx,7Fh + C(0x89) C(0x94) C(0x8F) C32(STATEOFS(temp)) // mov [edi+ecx*4+],edx + } + // 13 bytes max + // + // If EWT is on, perform write of EFREG + // + if((mpro->e_000Twwww & 0x10) == 0) { + C(0x89) C(0xD0) // mov eax,edx + C(0xC1) C(0xF8) C(0x08) // sar eax,8 + C(0x89) C(0x87) C32(STATEOFS(efreg[mpro->e_000Twwww])) // mov [edi+],eax + } + // 11 bytes max + // + // If we'll be needing an address, compute it in EBX (a word address) + // ODD LINES ONLY + // + if((i & 1) && (mpro->m_wrAFyyYh & 0xC0)) { + uint32 madrsnx = state->madrs[mpro->m_00aaaaaa]; + if(mpro->__kisxzbon & 1) { madrsnx++; } + madrsnx &= 0xFFFF; + if(mpro->tablemask == 0) { + C(0x8D) C(0x9D) C32(madrsnx) // lea ebx,[ebp+] + if(mpro->adrmask != 0) { + C(0x03) C(0x9F) C32(STATEOFS(adrs_reg)) // add ebx,[edi+] + } + C(0x81) C(0xE3) C32(rbmask) // and ebx, + // 18 bytes max + } else { + C(0xBB) C32(madrsnx) // mov ebx, + if(mpro->adrmask != 0) { + C(0x03) C(0x9F) C32(STATEOFS(adrs_reg)) // add ebx,[edi+] + C(0x81) C(0xE3) C32(0x0000FFFF) // and ebx,0FFFFh + } + // 17 bytes max + } + C(0x81) C(0xC3) C32(state->rbp / 2) // add ebx, + C(0x81) C(0xE3) C32(state->ram_mask / 2) // and ebx, + if((state->mem_word_address_xor / 2) != 0) { + C(0x83) C(0xF3) C(state->mem_word_address_xor / 2) // xor ebx, + } + } + // 33 bytes max ODD LINES ONLY + // + // If ADRL is set, latch address reg + // + if(mpro->m_wrAFyyYh & 0x20) { + if(mpro->__kisxzbon & 0x40) { // interpolate mode + C(0x89) C(0xD0) // mov eax,edx + C(0xC1) C(0xF8) C(0x0C) // sar eax,12 + } else { + C(0x8B) C(0x87) C32(STATEOFS(inputs[mpro->i_00rrrrrr])) // mov eax,[edi+] + C(0xC1) C(0xF8) C(0x10) // sar eax,16 + } + C(0x25) C32(0x00000FFF) // and eax,0FFFh + C(0x89) C(0x87) C32(STATEOFS(adrs_reg)) // mov [edi+],eax + } + // 20 bytes max + // + // If MRD is set, read from ebx*2: + // ODD LINES ONLY + // + if((i & 1) && (mpro->m_wrAFyyYh & 0x40)) { + if((mpro->__kisxzbon & 0x02) == 0) { // NOFL=0 + C(0x0F) C(0xBF) C(0x8C) C(0x1B) C32(state->ram_ptr) // movsx ecx, word ptr [ebx+ebx+] + C(0xE8) C32CALL(float16_to_int24) // call float16_to_int24 + // 13 bytes max + } else { // NOFL=1: + C(0x0F) C(0xBF) C(0x84) C(0x1B) C32(state->ram_ptr) // movsx eax, word ptr [ebx+ebx+] + C(0xC1) C(0xE0) C(0x08) // shl eax,8 + // 11 bytes max + } + C(0x89) C(0x87) C32(STATEOFS(mem_in_data[(i+2)&3])) // mov [edi+],eax + // 19 bytes max + // + // Or, if MWT is set, write edx to ebx*2: + // ODD LINES ONLY + // + } else if((i & 1) && (mpro->m_wrAFyyYh & 0x80)) { + if((mpro->__kisxzbon & 0x02) == 0) { // NOFL=0 + C(0x89) C(0xD1) // mov ecx,edx + C(0xE8) C32CALL(int24_to_float16) // call int24_to_float16 + C(0x66) C(0x89) C(0x84) C(0x1B) C32(state->ram_ptr) // mov [ebx+ebx+],ax + // 15 bytes max + } else { // NOFL=1: + C(0xC1) C(0xFA) C(0x08) // sar edx,8 + C(0x66) C(0x89) C(0x94) C(0x1B) C32(state->ram_ptr) // mov [ebx+ebx+],dx + // 11 bytes max + } + // 15 bytes max + } + // 19 bytes max ODD LINES ONLY + // + // If IWT is on, perform input write + // ODD LINES ONLY + // + if((i&1) && ((mpro->i_0T0wwwww & 0x40) == 0)) { + C(0x8B) C(0x97) C32(STATEOFS(mem_in_data[i&3])) // mov edx, [edi+] + C(0x89) C(0x97) C32(STATEOFS(inputs[mpro->i_0T0wwwww])) // mov [edi+],edx + } + // 12 bytes max ODD LINES ONLY + } + // + // Suffix + // + C(0x89) C(0xB7) C32(STATEOFS(xzbchoice[XZBCHOICE_ACC])) // mov [edi+],esi + C(0x61) // popa + C(0xC3) // retn + // 8 bytes + // + // Set valid flag + // + state->dsp_dyna_valid = 1; + +//{FILE*f=fopen("C:\\Corlett\\yamdyna.bin","wb");if(f){fwrite(state->dynacode,1,0x6000,f);fclose(f);}} + +} + +///////////////////////////////////////////////////////////////////////////// + +typedef void (__fastcall *dsp_sample_t)(struct YAM_STATE *state); + +///////////////////////////////////////////////////////////////////////////// +// +// Render effects by emulating the DSP +// +static void render_effects( + struct YAM_STATE *state, + sint32 *fxbus, + sint32 *out, + uint32 samples +) { + dsp_sample_t samplefunc; + uint32 i, j; + uint8 efatt_l[16]; + uint8 efatt_r[16]; + sint32 eflin_l[16]; + sint32 eflin_r[16]; + + if(state->dsp_dyna_enabled) { + if(!(state->dsp_dyna_valid)) { + dynacompile(state); + } + samplefunc = (dsp_sample_t)(((uint8*)(state->dynacode)) + DYNACODE_SLOP_SIZE); + } else { + samplefunc = dsp_sample_interpret; + } + + // + // Determine what the effect out levels are, for left and right + // + for(j = 0; j < 16; j++) { + convert_stereo_send_level( + state->efsdl[j], + (state->mono) ? 0 : state->efpan[j], + efatt_l + j, efatt_r + j, + eflin_l + j, eflin_r + j + ); + } + // + // For every sample: + // + for(i = 0; i < samples; i++, fxbus += 16, out += 2) { + // + // Clip and copy fxbus inputs (20-bit, pre-promote to 24-bit) + // + for(j = 0; j < 16; j++) { + sint32 t = fxbus[j]; + if(t < (-0x80000)) t = (-0x80000); + if(t > ( 0x7FFFF)) t = ( 0x7FFFF); + state->inputs[0x20 + j] = t << 4; + } + // + // Execute one DSP sample + // + samplefunc(state); + // Advance MDEC_CT + state->mdec_ct--; + // + // Copy outputs out of EFREG, scale accordingly, and add to output + // + for(j = 0; j < 16; j++) if(state->efsdl[j]) { + sint32 ef = (sint32)((sint16)(state->efreg[j])); + ef <<= 4; + out[0] += (ef*eflin_l[j]) >> efatt_l[j]; + out[1] += (ef*eflin_r[j]) >> efatt_r[j]; + } + } + +} + +///////////////////////////////////////////////////////////////////////////// +// +// Must not render more than RENDERMAX samples at a time +// +struct render_priority +{ + sint32 channel_number; + sint32 priority_level; +}; +int __cdecl render_priority_compare(const void * a, const void * b) { + struct render_priority *_a = (struct render_priority *) a; + struct render_priority *_b = (struct render_priority *) b; + return _b->priority_level - _a->priority_level; +} +static void render(struct YAM_STATE *state, uint32 odometer, uint32 samples) { + uint32 i, j; + struct render_priority priority_list[64]; + sint32 outbuf[2*RENDERMAX]; + sint32 fxbus[16*RENDERMAX]; + sint32 *directout; +// sint32 *fxout; + sint16 *buf; + uint32 nchannels; + uint32 bufptr_base; + int wantreverb = 0; + if(!samples) return; + buf = YAMSTATE->out_buf; + directout = (buf && (state->dry_out_enabled)) ? outbuf : NULL; + nchannels = ((YAMSTATE->version) == 1) ? 32 : 64; + +// st=odometer; +//if(odometer>=11*44100)dumpch(YAMSTATE,YAMSTATE->chan+11); +/* +if(odometer >= 11*44100) { +static int dumped=0; +if(!dumped) { +dumped=1; +{FILE*f=fopen("C:\\Corlett\\yamdump.ram","wb"); +if(f){ +fwrite(YAMSTATE->ram_ptr,0x200000,1,f); +fclose(f); +} +} +} +} +*/ + +//logstep(state,odometer); + + // figure out if we want reverb or not + if(buf && (state->dsp_emulation_enabled)) { + for(i = 0; i < 16; i++) { if(state->efsdl[i] != 0) break; } + wantreverb = (i < 16); + } else { + wantreverb = 0; + } + if(buf) { + memset(outbuf, 0, 4*2*samples); + if(wantreverb) memset(fxbus, 0, 4*16*samples); + } + // + // Figure out if any channels need to be rendered before others + // + for(i = 0; i < nchannels; i++) { + priority_list[i].channel_number = i; + priority_list[i].priority_level = 0; + } + if (state->version == 1) { + for(i = 0; i < nchannels; i++) { + struct YAM_CHAN *chan = state->chan + i; + sint32 priority_level = priority_list[i].priority_level + 1; + if (chan->mdxsl) priority_list[(i+chan->mdxsl)&31].priority_level = priority_level; + if (chan->mdysl) priority_list[(i+chan->mdysl)&31].priority_level = priority_level; + } + qsort(&priority_list, nchannels, sizeof(*priority_list), render_priority_compare); + } + bufptr_base = state->bufptr; + // + // Render each channel + // + for(i = 0; i < nchannels; i++) { + struct YAM_CHAN *chan; + j = priority_list[i].channel_number; + chan = state->chan + j; + state->bufptr = bufptr_base + j; +// is 11 + render_and_add_channel(state, chan, directout, + wantreverb ? (fxbus + chan->dspchan) : NULL, + odometer, samples + ); + } + state->bufptr = (bufptr_base + (32*samples)) & (32*RINGMAX-1); + // + // Emulate DSP effects if desired + // + if(wantreverb) { render_effects(state, fxbus, outbuf, samples); } + // + // Scale, clip and copy output + // + if(buf) { + uint32 att = state->mvol ^ 0xF; + sint32 lin = 4 - (att & 1); + att >>= 1; att += 2; att += 4; + for(i = 0; i < samples; i++) { + sint32 l = outbuf[2 * i + 0]; + sint32 r = outbuf[2 * i + 1]; + l *= lin; l >>= att; + r *= lin; r >>= att; + if(l < (-0x8000)) l = (-0x8000); + if(r < (-0x8000)) r = (-0x8000); + if(l > ( 0x7FFF)) l = ( 0x7FFF); + if(r > ( 0x7FFF)) r = ( 0x7FFF); + buf[2 * i + 0] = l; + buf[2 * i + 1] = r; + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Flush all pending samples into the output buffer +// +void EMU_CALL yam_flush(void *state) { +// return; +//printf("yam_flush(%up)",YAMSTATE->out_pending); + + for(;;) { + uint32 n = YAMSTATE->out_pending; + if(n < 1) { break; } + if(n > RENDERMAX) { n = RENDERMAX; } + render(YAMSTATE, YAMSTATE->odometer - YAMSTATE->out_pending, n); + YAMSTATE->out_pending -= n; + if(YAMSTATE->out_buf) { YAMSTATE->out_buf += 2 * n; } + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Prepare or unprepare dynacode buffer for execution +// +void EMU_CALL yam_prepare_dynacode(void *state) { +#ifdef ENABLE_DYNAREC +#ifdef _WIN32 + DWORD i; + VirtualProtect( &YAMSTATE->dynacode, sizeof(YAMSTATE->dynacode), PAGE_EXECUTE_READWRITE, &i ); +#elif defined(HAVE_MPROTECT) + unsigned long startaddr = &YAMSTATE->dynacode; + unsigned long length = sizeof(YAMSTATE->dynacode); + int psize = getpagesize(); + unsigned long addr = ( startaddr & ~(psize - 1) ); + mprotect( (char *) addr, length + startaddr - addr + psize, PROT_READ | PROT_WRITE | PROT_EXEC ); +#endif +#endif +} + +void EMU_CALL yam_unprepare_dynacode(void *state) { +#ifdef ENABLE_DYNAREC +#ifdef _WIN32 + DWORD i; + VirtualProtect( &YAMSTATE->dynacode, sizeof(YAMSTATE->dynacode), PAGE_READWRITE, &i ); +#elif defined(HAVE_MPROTECT) + unsigned long startaddr = &YAMSTATE->dynacode; + unsigned long length = sizeof(YAMSTATE->dynacode); + int psize = getpagesize(); + unsigned long addr = ( startaddr & ~(psize - 1) ); + mprotect( (char *) addr, length + startaddr - addr + psize, PROT_READ | PROT_WRITE ); +#endif +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// +// Mute channels post reset +// +void EMU_CALL yam_set_mute(void *state, uint32 channel, uint32 enable) { + YAMSTATE->chan[channel].mute = (uint8) enable; +} + +///////////////////////////////////////////////////////////////////////////// diff --git a/Frameworks/GME/vgmplay/chips/yam.h b/Frameworks/GME/vgmplay/chips/yam.h new file mode 100644 index 000000000..e31c374c3 --- /dev/null +++ b/Frameworks/GME/vgmplay/chips/yam.h @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////// +// +// yam - Emulates Yamaha SCSP and AICA +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __SEGA_YAM_H__ +#define __SEGA_YAM_H__ + +#include "emuconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +///////////////////////////////////////////////////////////////////////////// + +// version = 1 for SCSP, 2 for AICA +// ramsize must be a power of 2 + +sint32 EMU_CALL yam_init(void); +uint32 EMU_CALL yam_get_state_size(uint8 version); +void EMU_CALL yam_clear_state(void *state, uint8 version); + +void EMU_CALL yam_enable_dry(void *state, uint8 enable); +void EMU_CALL yam_enable_dsp(void *state, uint8 enable); +void EMU_CALL yam_enable_dsp_dynarec(void *state, uint8 enable); + +void EMU_CALL yam_setram(void *state, uint32 *ram, uint32 size, uint8 mbx, uint8 mwx); +void EMU_CALL yam_beginbuffer(void *state, sint16 *buf); +void EMU_CALL yam_advance(void *state, uint32 samples); +void EMU_CALL yam_flush(void *state); + +uint32 EMU_CALL yam_aica_load_reg(void *state, uint32 a, uint32 mask); +void EMU_CALL yam_aica_store_reg(void *state, uint32 a, uint32 d, uint32 mask, uint8 *breakcpu); + +uint32 EMU_CALL yam_scsp_load_reg(void *state, uint32 a, uint32 mask); +void EMU_CALL yam_scsp_store_reg(void *state, uint32 a, uint32 d, uint32 mask, uint8 *breakcpu); + +uint8* EMU_CALL yam_get_interrupt_pending_ptr(void *state); +uint32 EMU_CALL yam_get_min_samples_until_interrupt(void *state); + +void EMU_CALL yam_prepare_dynacode(void *state); +void EMU_CALL yam_unprepare_dynacode(void *state); + +void EMU_CALL yam_set_mute(void *state, uint32 channel, uint32 enable); + +///////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Frameworks/GME/vgmplay/chips/ym2151.c b/Frameworks/GME/vgmplay/chips/ym2151.c index 17b60d1c1..a7de5ca2f 100644 --- a/Frameworks/GME/vgmplay/chips/ym2151.c +++ b/Frameworks/GME/vgmplay/chips/ym2151.c @@ -9,12 +9,14 @@ #include "mamedef.h" #include -#include +#include //#include "sndintrf.h" //#include "streams.h" #include "ym2151.h" +#ifndef NULL #define NULL ((void *)0) +#endif /* undef this to not use MAME timer system */ @@ -1118,7 +1120,7 @@ void ym2151_write_reg(void *_chip, int r, int v) chip->status &= ~1; timer_set(chip->device->machine, attotime_zero,chip,0,irqAoff_callback); #else - int oldstate = chip->status & 3; + //int oldstate = chip->status & 3; chip->status &= ~1; //if ((oldstate==1) && (chip->irqhandler)) (*chip->irqhandler)(chip->device, 0); #endif @@ -1130,7 +1132,7 @@ void ym2151_write_reg(void *_chip, int r, int v) chip->status &= ~2; timer_set(chip->device->machine, attotime_zero,chip,0,irqBoff_callback); #else - int oldstate = chip->status & 3; + //int oldstate = chip->status & 3; chip->status &= ~2; //if ((oldstate==2) && (chip->irqhandler)) (*chip->irqhandler)(chip->device, 0); #endif @@ -2402,7 +2404,7 @@ INLINE signed int acc_calc(signed int value) */ void ym2151_update_one(void *chip, SAMP **buffers, int length) { - int i, chn; + int i; // , chn; signed int outl,outr; SAMP *bufL, *bufR; @@ -2422,7 +2424,7 @@ void ym2151_update_one(void *chip, SAMP **buffers, int length) PSG->tim_B_val += PSG->tim_B_tab[ PSG->timer_B_index ]; if ( PSG->irq_enable & 0x08 ) { - int oldstate = PSG->status & 3; + //int oldstate = PSG->status & 3; PSG->status |= 2; //if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(chip->device, 1); } @@ -2500,7 +2502,7 @@ void ym2151_update_one(void *chip, SAMP **buffers, int length) PSG->tim_A_val += PSG->tim_A_tab[ PSG->timer_A_index ]; if (PSG->irq_enable & 0x04) { - int oldstate = PSG->status & 3; + //int oldstate = PSG->status & 3; PSG->status |= 1; //if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(chip->device, 1); } diff --git a/Frameworks/GME/vgmplay/chips/ym2413.c b/Frameworks/GME/vgmplay/chips/ym2413.c index 04994ac73..d06a961d1 100644 --- a/Frameworks/GME/vgmplay/chips/ym2413.c +++ b/Frameworks/GME/vgmplay/chips/ym2413.c @@ -41,11 +41,13 @@ to do: #include #include "mamedef.h" #include -#include +#include //#include "sndintrf.h" #include "ym2413.h" +#ifndef NULL #define NULL ((void *)0) +#endif /* output final shift */ #if (SAMPLE_BITS==16) diff --git a/Frameworks/GME/vgmplay/chips/ymdeltat.c b/Frameworks/GME/vgmplay/chips/ymdeltat.c index 6272f1711..ef5744488 100644 --- a/Frameworks/GME/vgmplay/chips/ymdeltat.c +++ b/Frameworks/GME/vgmplay/chips/ymdeltat.c @@ -217,8 +217,10 @@ value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: DELTAT->adpcml = 0; DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; DELTAT->now_data = 0; +#ifdef _DEBUG if (DELTAT->start > DELTAT->end) logerror("DeltaT-Warning: Start: %06X, End: %06X\n", DELTAT->start, DELTAT->end); +#endif } if( DELTAT->portstate&0x20 ) /* do we access external memory? */ @@ -673,4 +675,4 @@ void YM_DELTAT_calc_mem_mask(YM_DELTAT* DELTAT) DELTAT->memory_mask = (MaskSize << 1) - 1; // it's Mask<<1 because of the nibbles return; -} \ No newline at end of file +} diff --git a/Frameworks/GME/vgmplay/chips/ymf262.c b/Frameworks/GME/vgmplay/chips/ymf262.c index 9aebcfbae..03f3ca765 100644 --- a/Frameworks/GME/vgmplay/chips/ymf262.c +++ b/Frameworks/GME/vgmplay/chips/ymf262.c @@ -56,11 +56,13 @@ differences between OPL2 and OPL3 shown in datasheets: #include #include "mamedef.h" #include -#include +#include //#include "sndintrf.h" #include "ymf262.h" +#ifndef NULL #define NULL ((void *)0) +#endif /* output final shift */ @@ -2561,7 +2563,7 @@ void ymf262_update_one(void *_chip, OPL3SAMPLE **buffers, int length) //OPL3SAMPLE *ch_d = buffers[3]; int i; - int chn; + //int chn; for( i=0; i < length ; i++ ) { diff --git a/Frameworks/GME/vgmplay/chips/ymf271.c b/Frameworks/GME/vgmplay/chips/ymf271.c index e41fb3579..e9542d8f1 100644 --- a/Frameworks/GME/vgmplay/chips/ymf271.c +++ b/Frameworks/GME/vgmplay/chips/ymf271.c @@ -34,7 +34,7 @@ #include #endif #include -#include +#include #include "ymf271.h" #ifndef __cplusplus // C++ already has the bool-type @@ -43,7 +43,9 @@ typedef unsigned char bool; #endif // !__cplusplus +#ifndef NULL #define NULL ((void *)0) +#endif //#define DEVCB_NULL { DEVCB_TYPE_NULL } #define DEVCB_NULL DEVCB_TYPE_NULL @@ -1243,7 +1245,9 @@ static void ymf271_write_fm(YMF271Chip *chip, int bank, UINT8 address, UINT8 dat if (groupnum == -1) { +#ifdef _DEBUG logerror("ymf271_write_fm invalid group %02X %02X\n", address, data); +#endif return; } @@ -1340,7 +1344,9 @@ static void ymf271_write_pcm(YMF271Chip *chip, UINT8 address, UINT8 data) YMF271Slot *slot; if (slotnum == -1) { +#ifdef _DEBUG logerror("ymf271_write_pcm invalid slot %02X %02X\n", address, data); +#endif return; } slot = &chip->slots[slotnum]; @@ -1465,7 +1471,9 @@ static void ymf271_write_timer(YMF271Chip *chip, UINT8 address, UINT8 data) YMF271Group *group; if (groupnum == -1) { +#ifdef _DEBUG logerror("ymf271_write_timer invalid group %02X %02X\n", address, data); +#endif return; } group = &chip->groups[groupnum]; diff --git a/Frameworks/GME/vgmplay/chips/ymf278b.c b/Frameworks/GME/vgmplay/chips/ymf278b.c index 99fb3ffb7..70059adaf 100644 --- a/Frameworks/GME/vgmplay/chips/ymf278b.c +++ b/Frameworks/GME/vgmplay/chips/ymf278b.c @@ -64,13 +64,15 @@ //#include "streams.h" //#include "cpuintrf.h" #include -#include +#include #include #include #include "ymf262.h" #include "ymf278b.h" +#ifndef NULL #define NULL ((void *)0) +#endif typedef struct { @@ -79,7 +81,7 @@ typedef struct UINT32 endaddr; UINT32 step; /* fixed-point frequency step */ UINT32 stepptr; /* fixed-point pointer into the sample */ - UINT32 pos; + UINT16 pos; INT16 sample1, sample2; INT32 env_vol; @@ -536,9 +538,9 @@ INLINE void ymf278b_advance(YMF278BChip* chip) INLINE UINT8 ymf278b_readMem(YMF278BChip* chip, offs_t address) { if (address < chip->ROMSize) - return chip->rom[address]; + return chip->rom[address&0x3fffff]; else if (address < chip->ROMSize + chip->RAMSize) - return chip->ram[address - chip->ROMSize]; + return chip->ram[address - chip->ROMSize&0x3fffff]; else return 255; // TODO check } @@ -546,9 +548,9 @@ INLINE UINT8 ymf278b_readMem(YMF278BChip* chip, offs_t address) INLINE UINT8* ymf278b_readMemAddr(YMF278BChip* chip, offs_t address) { if (address < chip->ROMSize) - return &chip->rom[address]; + return &chip->rom[address&0x3fffff]; else if (address < chip->ROMSize + chip->RAMSize) - return &chip->ram[address - chip->ROMSize]; + return &chip->ram[address - chip->ROMSize&0x3fffff]; else return NULL; // TODO check } @@ -696,10 +698,12 @@ void ymf278b_pcm_update(void *_info, stream_sample_t** outputs, int samples) { sl->stepptr -= 0x10000; sl->sample1 = sl->sample2; - sl->pos ++; - if (sl->pos >= sl->endaddr) - sl->pos = sl->loopaddr; + sl->sample2 = ymf278b_getSample(chip, sl); + if (sl->pos == sl->endaddr) + sl->pos = sl->pos - sl->endaddr + sl->loopaddr; + else + sl->pos ++; } } ymf278b_advance(chip); @@ -826,7 +830,7 @@ void ymf278b_C_w(YMF278BChip* chip, UINT8 reg, UINT8 data) slot->startaddr = buf[2] | (buf[1] << 8) | ((buf[0] & 0x3F) << 16); slot->loopaddr = buf[4] + (buf[3] << 8); - slot->endaddr = (((buf[6] + (buf[5] << 8)) ^ 0xFFFF) + 1); + slot->endaddr = ((buf[6] + (buf[5] << 8)) ^ 0xFFFF); if (chip->regs[reg + 4] & 0x080) ymf278b_keyOnHelper(chip, slot); diff --git a/Frameworks/GME/vgmplay/chips/ymz280b.c b/Frameworks/GME/vgmplay/chips/ymz280b.c index 8e2a91e8b..b89cc64b3 100644 --- a/Frameworks/GME/vgmplay/chips/ymz280b.c +++ b/Frameworks/GME/vgmplay/chips/ymz280b.c @@ -36,11 +36,13 @@ #ifdef _DEBUG #include #endif -#include +#include #include #include "ymz280b.h" +#ifndef NULL #define NULL ((void *)0) +#endif static void update_irq_state_timer_common(void *param, int voicenum); @@ -1157,7 +1159,9 @@ static void write_to_register(ymz280b_state *chip, int data) case 0x80: // d0-2: DSP Rch, d3: enable Rch (0: yes, 1: no), d4-6: DSP Lch, d7: enable Lch (0: yes, 1: no) case 0x81: // d0: enable control of $82 (0: yes, 1: no) case 0x82: // DSP data +#ifdef _DEBUG logerror("YMZ280B: DSP register write %02X = %02X\n", chip->current_register, data); +#endif break; case 0x84: /* ROM readback / RAM write (high) */ diff --git a/Frameworks/GME/vgmplay/resampler.c b/Frameworks/GME/vgmplay/resampler.c index 168e51764..2bf5a3148 100644 --- a/Frameworks/GME/vgmplay/resampler.c +++ b/Frameworks/GME/vgmplay/resampler.c @@ -36,13 +36,14 @@ static void gen_sinc( double rolloff, int width, double offset, double spacing, double const step = PI / maxh * spacing; double const to_w = maxh * 2 / width; double const pow_a_n = pow( rolloff, maxh ); - scale /= maxh * 2; double angle = (count / 2 - 1 + offset) * -step; + scale /= maxh * 2; while ( count-- ) { + double w; *out++ = 0; - double w = angle * to_w; + w = angle * to_w; if ( fabs( w ) < PI ) { double rolloff_cos_a = rolloff * cos( angle ); @@ -133,17 +134,29 @@ void resampler_set_rate( void *_r, double new_factor ) double const rolloff = 0.999; double const gain = 1.0; + int step; + double fraction; + + double filter; + double pos = 0.0; + + imp_t* out; + + int n; + /* determine number of sub-phases that yield lowest error */ double ratio_ = 0.0; int res = -1; { double least_error = 2; double pos = 0; - for ( int r = 1; r <= max_res; r++ ) + int r; + for ( r = 1; r <= max_res; r++ ) { + double nearest, error; pos += new_factor; - double nearest = floor( pos + 0.5 ); - double error = fabs( pos - nearest ); + nearest = floor( pos + 0.5 ); + error = fabs( pos - nearest ); if ( error < least_error ) { res = r; @@ -155,20 +168,21 @@ void resampler_set_rate( void *_r, double new_factor ) rs->rate_ = ratio_; /* how much of input is used for each output sample */ - int const step = stereo * (int) floor( ratio_ ); - double fraction = fmod( ratio_, 1.0 ); + step = stereo * (int) floor( ratio_ ); + fraction = fmod( ratio_, 1.0 ); - double const filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_; - double pos = 0.0; + filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_; /*int input_per_cycle = 0;*/ - imp_t* out = rs->impulses; - for ( int n = res; --n >= 0; ) + out = rs->impulses; + for ( n = res; --n >= 0; ) { + int cur_step; + gen_sinc( rolloff, (int) (rs->width_ * filter + 1) & ~1, pos, filter, (double)(imp_scale * gain * filter), (int) rs->width_, out ); out += rs->width_; - int cur_step = step; + cur_step = step; pos += fraction; if ( pos >= 0.9999999 ) { @@ -208,7 +222,8 @@ void resampler_write_pair(void *_r, sample_t ls, sample_t rs) if (!r->latency) { - for (int i = 0; i < adj_width / 2; ++i) + int i; + for (i = 0; i < adj_width / 2; ++i) { r->buffer_in[r->inptr + 0] = 0; r->buffer_in[r->inptr + 1] = 0; @@ -249,11 +264,12 @@ static const sample_t * resampler_inner_loop( resampler *r, sample_t** out_, { /* accumulate in extended precision*/ int pt = imp [0]; + int n; intermediate_t l = (intermediate_t)pt * (intermediate_t)(in [0]); intermediate_t r = (intermediate_t)pt * (intermediate_t)(in [1]); if ( out >= out_end ) break; - for ( int n = (adj_width - 2) / 2; n; --n ) + for ( n = (adj_width - 2) / 2; n; --n ) { pt = imp [1]; l += (intermediate_t)pt * (intermediate_t)(in [2]); @@ -305,9 +321,10 @@ static void resampler_fill( resampler *r ) { int writepos = ( r->outptr + r->outfilled ) % (buffer_size * stereo); int writesize = (buffer_size * stereo) - writepos; + int inread; if ( writesize > ( buffer_size * stereo - r->outfilled ) ) writesize = buffer_size * stereo - r->outfilled; - int inread = resampler_wrapper(r, &r->buffer_out[writepos], &writesize, &r->buffer_in[buffer_size * stereo + r->inptr - r->infilled], r->infilled); + inread = resampler_wrapper(r, &r->buffer_out[writepos], &writesize, &r->buffer_in[buffer_size * stereo + r->inptr - r->infilled], r->infilled); r->infilled -= inread; r->outfilled += writesize; if (!inread) diff --git a/Frameworks/GME/vgmplay/vgm2pcm.c b/Frameworks/GME/vgmplay/vgm2pcm.c index 5e608bb9a..71f3e690d 100644 --- a/Frameworks/GME/vgmplay/vgm2pcm.c +++ b/Frameworks/GME/vgmplay/vgm2pcm.c @@ -27,7 +27,6 @@ int main(int argc, char *argv[]) { FILE *outputFile; void *vgmp; VGM_PLAYER *p; - int EndPlay; if (argc < 3) { fputs("usage: vgm2pcm vgm_file pcm_file\n", stderr); @@ -58,8 +57,7 @@ int main(int argc, char *argv[]) { return 1; } - EndPlay = 0; - while (!EndPlay) { + while (!p->EndPlay) { UINT32 bufferSize = p->SampleRate; bufferedLength = FillBuffer(vgmp, sampleBuffer, bufferSize); if (bufferedLength) { @@ -73,8 +71,6 @@ int main(int argc, char *argv[]) { fputBE16(sampleData[currentSample], outputFile); } } - if (bufferedLength < bufferSize) - EndPlay = 1; } StopVGM(vgmp);