mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
Merge remote-tracking branch 'origin/master' into asmjit
This commit is contained in:
commit
369dcfd57f
304 changed files with 14829 additions and 8919 deletions
|
@ -93,16 +93,15 @@ matrix:
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env:
|
env:
|
||||||
- CLANG_VERSION=6.0
|
- CLANG_VERSION=7
|
||||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
|
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-trusty-6.0
|
- llvm-toolchain-trusty-7
|
||||||
packages:
|
packages:
|
||||||
- clang-6.0
|
- clang-7
|
||||||
- libstdc++-5-dev
|
|
||||||
- libsdl2-dev
|
- libsdl2-dev
|
||||||
- libgme-dev
|
- libgme-dev
|
||||||
- libopenal-dev
|
- libopenal-dev
|
||||||
|
|
|
@ -328,6 +328,9 @@ if( GME_FOUND AND NOT FORCE_INTERNAL_GME )
|
||||||
message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" )
|
message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" )
|
||||||
else()
|
else()
|
||||||
message( STATUS "Using internal gme library" )
|
message( STATUS "Using internal gme library" )
|
||||||
|
# Use MAME as it's balanced emulator: well-accurate, but doesn't eats lot of CPU
|
||||||
|
# Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow
|
||||||
|
set( GME_YM2612_EMU "MAME" )
|
||||||
add_subdirectory( game-music-emu )
|
add_subdirectory( game-music-emu )
|
||||||
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/game-music-emu" )
|
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/game-music-emu" )
|
||||||
set( GME_LIBRARIES gme )
|
set( GME_LIBRARIES gme )
|
||||||
|
|
|
@ -4,14 +4,12 @@ project(libgme)
|
||||||
include (CheckCXXCompilerFlag)
|
include (CheckCXXCompilerFlag)
|
||||||
|
|
||||||
# When version is changed, also change the one in gme/gme.h to match
|
# When version is changed, also change the one in gme/gme.h to match
|
||||||
set(GME_VERSION 0.6.1 CACHE INTERNAL "libgme Version")
|
set(GME_VERSION 0.6.2 CACHE INTERNAL "libgme Version")
|
||||||
|
|
||||||
# 2.6+ always assumes FATAL_ERROR, but 2.4 and below don't.
|
# 2.6+ always assumes FATAL_ERROR, but 2.4 and below don't.
|
||||||
# Of course, 2.4 might work, in which case you're welcome to drop
|
# Of course, 2.4 might work, in which case you're welcome to drop
|
||||||
# down the requirement, but I can't test that.
|
# down the requirement, but I can't test that.
|
||||||
cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR)
|
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
|
||||||
|
|
||||||
make_release_only()
|
|
||||||
|
|
||||||
# I don't plan on debugging this, so make it a release build.
|
# I don't plan on debugging this, so make it a release build.
|
||||||
if( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
if( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
||||||
|
@ -29,84 +27,112 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#[ZDoom] Disable most of bogus and annoying MSVC warnings
|
||||||
|
if( MSVC )
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4101 /wd4800 /wd4702 /wd4706 /wd4805 /wd4310 /wd4244 /wd4456 /wd4459 /wd4146 /wd4127 /wd4458 /wd4267 /wd4804")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Enable fast flag for GME
|
# Enable fast flag for GME
|
||||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
||||||
|
|
||||||
# Default emulators to build (all of them! ;)
|
# Default emulators to build (all of them! ;)
|
||||||
# [ZDoom] No options, enable all of them by default.
|
# [ZDoom] No options, enable all of them by default.
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_AY)
|
#if (NOT DEFINED USE_GME_AY)
|
||||||
SET(USE_GME_AY 1 BOOL "Enable support for Spectrum ZX music emulation")
|
SET(USE_GME_AY 1 CACHE BOOL "Enable support for Spectrum ZX music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_GBS)
|
#if (NOT DEFINED USE_GME_GBS)
|
||||||
SET(USE_GME_GBS 1 BOOL "Enable support for Game Boy music emulation")
|
SET(USE_GME_GBS 1 CACHE BOOL "Enable support for Game Boy music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_GYM)
|
#if (NOT DEFINED USE_GME_GYM)
|
||||||
SET(USE_GME_GYM 1 BOOL "Enable Sega MegaDrive/Genesis music emulation")
|
SET(USE_GME_GYM 1 CACHE BOOL "Enable Sega MegaDrive/Genesis music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_HES)
|
#if (NOT DEFINED USE_GME_HES)
|
||||||
SET(USE_GME_HES 1 BOOL "Enable PC Engine/TurboGrafx-16 music emulation")
|
SET(USE_GME_HES 1 CACHE BOOL "Enable PC Engine/TurboGrafx-16 music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_KSS)
|
#if (NOT DEFINED USE_GME_KSS)
|
||||||
SET(USE_GME_KSS 1 BOOL "Enable MSX or other Z80 systems music emulation")
|
SET(USE_GME_KSS 1 CACHE BOOL "Enable MSX or other Z80 systems music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_NSF)
|
#if (NOT DEFINED USE_GME_NSF)
|
||||||
SET(USE_GME_NSF 1 BOOL "Enable NES NSF music emulation")
|
SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_NSFE)
|
#if (NOT DEFINED USE_GME_NSFE)
|
||||||
SET(USE_GME_NSFE 1 BOOL "Enable NES NSFE and NSF music emulation")
|
SET(USE_GME_NSFE 1 CACHE BOOL "Enable NES NSFE and NSF music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_SAP)
|
#if (NOT DEFINED USE_GME_SAP)
|
||||||
SET(USE_GME_SAP 1 BOOL "Enable Atari SAP music emulation")
|
SET(USE_GME_SAP 1 CACHE BOOL "Enable Atari SAP music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_SPC)
|
#if (NOT DEFINED USE_GME_SPC)
|
||||||
SET(USE_GME_SPC 1 BOOL "Enable SNES SPC music emulation")
|
SET(USE_GME_SPC 1 CACHE BOOL "Enable SNES SPC music emulation")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (NOT DEFINED USE_GME_VGM)
|
#if (NOT DEFINED USE_GME_VGM)
|
||||||
SET(USE_GME_VGM 1 BOOL "Enable Sega VGM/VGZ music emulation")
|
SET(USE_GME_VGM 1 CACHE BOOL "Enable Sega VGM/VGZ music emulation")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#if (NOT DEFINED GME_YM2612_EMU)
|
||||||
|
SET(GME_YM2612_EMU "Nuked" CACHE STRING "Which YM2612 emulator to use: \"Nuked\" (LGPLv2.1+), \"MAME\" (GPLv2+), or \"GENS\" (LGPLv2.1+)")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#if (USE_GME_NSFE AND NOT USE_GME_NSF)
|
#if (USE_GME_NSFE AND NOT USE_GME_NSF)
|
||||||
#MESSAGE(" -- NSFE support requires NSF, enabling NSF support. --")
|
#MESSAGE(" -- NSFE support requires NSF, enabling NSF support. --")
|
||||||
SET(USE_GME_NSF 1 BOOL "Enable NES NSF music emulation")
|
SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation" FORCE)
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
# [ZDoom] Set always to OFF.
|
# [ZDoom] Set always to OFF.
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
set(ENABLE_UBSAN OFF)
|
||||||
|
|
||||||
# Check for GCC "visibility" support.
|
# Check for GCC/Clang "visibility" support.
|
||||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||||
check_cxx_compiler_flag (-fvisibility=hidden __LIBGME_TEST_VISIBILITY)
|
OR
|
||||||
set (ENABLE_VISIBILITY OFF)
|
CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
if (__LIBGME_TEST_VISIBILITY)
|
|
||||||
# get the gcc version
|
|
||||||
exec_program(${CMAKE_CXX_COMPILER} ARGS --version OUTPUT_VARIABLE _gcc_version_info)
|
|
||||||
string (REGEX MATCH "[3-9]\\.[0-9]\\.[0-9]" _gcc_version "${_gcc_version_info}")
|
|
||||||
|
|
||||||
# gcc <4.1 had poor support for symbol visibility
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -W -Wextra")
|
||||||
if ((${_gcc_version} VERSION_GREATER "4.1") OR (${_gcc_version} VERSION_EQUAL "4.1"))
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
|
|
||||||
set (ENABLE_VISIBILITY ON)
|
# Assume we have visibility support on any compiler that supports C++11
|
||||||
add_definitions (-DLIBGME_VISIBILITY)
|
add_definitions (-DLIBGME_VISIBILITY)
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
|
||||||
|
|
||||||
# GCC >= 4.2 also correctly supports making inline members have hidden
|
# Try to protect against undefined behavior from signed integer overflow
|
||||||
# visibility by default.
|
# This has caused miscompilation of code already and there are other
|
||||||
if ((${_gcc_version} VERSION_GREATER "4.2") OR (${_gcc_version} VERSION_EQUAL "4.2"))
|
# potential uses; see https://bitbucket.org/mpyne/game-music-emu/issues/18/
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fwrapv")
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
if (NOT DEFINED LIBGME_SWITCH_FALLTHROUGH)
|
||||||
|
check_cxx_compiler_flag (-Wimplicit-fallthrough __LIBGME_SWITCH_FALLTHROUGH_WARNINGS)
|
||||||
|
set (LIBGME_SWITCH_FALLTHROUGH ${__LIBGME_SWITCH_FALLTHROUGH_WARNINGS}
|
||||||
|
CACHE BOOL "Set if the compiler will complain about implicit switch fallthrough"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override -Wno-unused-const-variable")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_UBSAN)
|
||||||
|
# GCC needs -static-libubsan
|
||||||
|
if (NOT BUILD_SHARED_LIBS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -static-libubsan")
|
||||||
|
else()
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif ()
|
endif ()
|
||||||
endif() # test visibility
|
|
||||||
|
|
||||||
# Cache this result
|
if(LIBGME_SWITCH_FALLTHROUGH)
|
||||||
set( LIBGME_HAVE_GCC_VISIBILITY ${ENABLE_VISIBILITY} CACHE BOOL "GCC support for hidden visibility")
|
# Avoid warning spam about switch fallthroughs, which are numerous in
|
||||||
|
# the codebase.
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wimplicit-fallthrough=0")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Shared library defined here
|
# Shared library defined here
|
||||||
|
|
|
@ -1,274 +1,5 @@
|
||||||
Game_Music_Emu Change Log
|
Game_Music_Emu Change Log
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Game_Music_Emu 0.6.1
|
Please see the git version history (e.g. git shortlog tags/0.6.0..tags/0.6.1)
|
||||||
--------------------
|
for the accurate change log.
|
||||||
|
|
||||||
- Moved repository to Bitbucket since Google Code announced they would
|
|
||||||
shutdown this year.
|
|
||||||
|
|
||||||
- Packaging improvements:
|
|
||||||
- Honor $LIB_SUFFIX for installed pkg-config metadata.
|
|
||||||
- Support setting BUILD_SHARED_LIBS to OFF to build libgme as a static
|
|
||||||
library. (Pass -DBUILD_SHARED_LIBS=OFF when running cmake).
|
|
||||||
Thanks to lachs0r.
|
|
||||||
|
|
||||||
Game_Music_Emu 0.6.0
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
- Note: A 0.5.6 release was referenced but never tagged or packaged.
|
|
||||||
|
|
||||||
- SPC improvements:
|
|
||||||
- Switched to newer snes_spc 0.9.0 for SPC emulation. Uses fast DSP.
|
|
||||||
- Fixed Spc_Emu::gain().
|
|
||||||
- Fixed support for files <0x10200 bytes.
|
|
||||||
|
|
||||||
- Other bugfixes:
|
|
||||||
- Fixed a couple of GBS bugs, one involving access of memory after
|
|
||||||
realloc.
|
|
||||||
- Blip_Buffer works on systems where 'double' is a single-precision
|
|
||||||
floating-point type.
|
|
||||||
- Fix uninitialized buffer size in dual_resampler.
|
|
||||||
- Compilation warnings squashed out as of clang 3.3-pre and gcc 4.7.2.
|
|
||||||
|
|
||||||
- API changes/additions:
|
|
||||||
- Removed documentation of C++ interface, as the C interface in gme.h is
|
|
||||||
the only supported one.
|
|
||||||
- Added gme_enable_accuracy() for enabling more accurate sound emulation
|
|
||||||
options (currently affects SPC only).
|
|
||||||
|
|
||||||
- Build system improvements:
|
|
||||||
- Add pkg_config support.
|
|
||||||
- Fix build on case-insensitive systems.
|
|
||||||
- Allow for install on Cygwin.
|
|
||||||
- Fix install on multilib systems, such as many 64-bit distros (CMake must
|
|
||||||
be able to figure out your system's libsuffix, if any).
|
|
||||||
- C++ implementation symbols are not leaked into the resultant library
|
|
||||||
file (requires symbol visibility support).
|
|
||||||
|
|
||||||
- Sample player improvements:
|
|
||||||
- Can toggle fast/accurate emulation (with the 'A' key).
|
|
||||||
|
|
||||||
Game_Music_Emu 0.5.5
|
|
||||||
--------------------
|
|
||||||
- CMake build support has been added. You can build Game_Music_Emu as
|
|
||||||
a shared library and install it so that you do not have to include your
|
|
||||||
own copy if you know libgme will be present on your target system.
|
|
||||||
Requires CMake 2.6 or higher.
|
|
||||||
|
|
||||||
|
|
||||||
Game_Music_Emu 0.5.2
|
|
||||||
--------------------
|
|
||||||
- *TONS* of changes and improvements. You should re-read the new header
|
|
||||||
files and documentation as the changes will allow you to simplify your
|
|
||||||
code a lot (it might even be simpler to just rewrite it). Existing code
|
|
||||||
should continue to work without changes in most cases (see Deprecated
|
|
||||||
features in gme.txt).
|
|
||||||
|
|
||||||
- New file formats: AY, HES, KSS, SAP, NSFE
|
|
||||||
|
|
||||||
- All-new comprehensive C interface (also usable from C++). Simplifies
|
|
||||||
many things, especially file loading, and brings everything together in
|
|
||||||
one header file (gme.h).
|
|
||||||
|
|
||||||
- Information tags and track names and times can be accessed for all
|
|
||||||
game music formats
|
|
||||||
|
|
||||||
- New features supported by all emulators: end of track fading,
|
|
||||||
automatic silence detection, adjustable song tempo, seek to new time in
|
|
||||||
track
|
|
||||||
|
|
||||||
- Updated mini player example to support track names and times, echo,
|
|
||||||
tempo, and channel muting, and added visual waveform display
|
|
||||||
|
|
||||||
- Improved configuration to use blargg_config.h, which you can modify
|
|
||||||
and keep when you update to a newer libary version. Includes flag for
|
|
||||||
library to automatically handle gzipped files using zlib (so you don't
|
|
||||||
need to use Gzip_File_Reader anymore).
|
|
||||||
|
|
||||||
- GBS: Fixed wave channel to not reset waveform when APU is powered off
|
|
||||||
(affected Garfield). Also improved invalid bank selection (affected Game
|
|
||||||
& Watch and others).
|
|
||||||
|
|
||||||
- VGM: Added support for alternate noise shifter register
|
|
||||||
configurations, used by other systems like the BBC Micro.
|
|
||||||
|
|
||||||
- SPC: Removed IPL ROM dump from emulator, as none of the SPC files I
|
|
||||||
scanned needed it, and an SPC file can include a copy if necessary. Also
|
|
||||||
re-enabled supposed clamping in gaussian interpolation between the third
|
|
||||||
and fourth lookups, though I don't know whether it matters
|
|
||||||
|
|
||||||
- Added Music_Emu::load_mem() to use music data already in memory
|
|
||||||
(without copying it)
|
|
||||||
|
|
||||||
- Added Music_Emu::warning(), which reports minor problems when loading
|
|
||||||
and playing a music file
|
|
||||||
|
|
||||||
- Added Music_Emu::set_gain() for uniform adjustment of gain. Can only
|
|
||||||
be set during initialization, so not useful as a general volume control.
|
|
||||||
|
|
||||||
- Added custom operator new to ensure that no exceptions are thrown in
|
|
||||||
the library (I'd use std::nothrow if it were part of pre-ISO (ARM) C++)
|
|
||||||
|
|
||||||
- Added BLIP_BUFFER_FAST flag to blargg_config.h to use a lower quality
|
|
||||||
bandlimited synthesis in "classic" emulators, which might help
|
|
||||||
performance on ancient processors (measure first!). Don't use this
|
|
||||||
unless absolutely necessary, as quality suffers.
|
|
||||||
|
|
||||||
- Improved performance a bit for x86 platforms
|
|
||||||
|
|
||||||
- Text files now in DOS newline format so they will open in Notepad
|
|
||||||
properly
|
|
||||||
|
|
||||||
- Removed requirement that file header structures not have any padding
|
|
||||||
added to the end
|
|
||||||
|
|
||||||
- Fixed common bug in all CPU emulators where negative program counter
|
|
||||||
could crash emulator (occurred during a negative branch from the
|
|
||||||
beginning of memory). Also fixed related bug in Z80 emulator for
|
|
||||||
IX/IY+displacement mode.
|
|
||||||
|
|
||||||
- Eliminated all warnings when compiling on gcc 4.0. The following
|
|
||||||
generates no diagnostics:
|
|
||||||
|
|
||||||
gcc -S gme/*.cpp -o /dev/null -ansi -fno-gnu-keywords
|
|
||||||
-fno-nonansi-builtins -pedantic -W -Wabi -Wall -Wcast-align
|
|
||||||
-Wcast-qual -Wchar-subscripts -Wdisabled-optimization -Werror
|
|
||||||
-Winline -Wlong-long -Wmultichar -Winvalid-offsetof
|
|
||||||
-Wnon-virtual-dtor -Woverloaded-virtual -Wparentheses
|
|
||||||
-Wpointer-arith -Wredundant-decls -Wreorder -Wsign-compare
|
|
||||||
-Wsign-promo -Wunknown-pragmas -Wwrite-strings
|
|
||||||
|
|
||||||
|
|
||||||
Game_Music_Emu 0.3.0
|
|
||||||
--------------------
|
|
||||||
- Added more demos, including music player using the SDL multimedia
|
|
||||||
library for sound, and improved documentation
|
|
||||||
|
|
||||||
- All: Improved interface to emulators to allow simpler setup and
|
|
||||||
loading. Instead of various init() functions, all now support
|
|
||||||
set_sample_rate( long rate ) and load( const char* file_path ).
|
|
||||||
|
|
||||||
- All: Removed error return from start_track() and play(), and added
|
|
||||||
error_count() to get the total number of emulation errors since the
|
|
||||||
track was last started. See demos for examples of new usage.
|
|
||||||
|
|
||||||
- All: Fixed mute_voices() muting to be preserved after loading files
|
|
||||||
and starting tracks, instead of being cleared as it was whenever a track
|
|
||||||
was started
|
|
||||||
|
|
||||||
- VGM: Rewrote Vgm_Emu to support Sega Genesis/Mega Drive FM sound at
|
|
||||||
any sample rate with optional FM oversampling, support for alternate
|
|
||||||
YM2612 sound cores, and support for optional YM2413
|
|
||||||
|
|
||||||
- VGM: Added tempo control, useful for slowing 60Hz NTSC Sega Genesis
|
|
||||||
music to 50Hz PAL
|
|
||||||
|
|
||||||
- VGM: Removed Vgm_Emu::track_data(), since I realized that this
|
|
||||||
information is already present in the VGM header (oops!)
|
|
||||||
|
|
||||||
- GYM: Changed Gym_Emu::track_length() operation (see Gym_Emu.h)
|
|
||||||
|
|
||||||
- NSF: Added support for Sunsoft FME-7 sound chip used by Gimmick
|
|
||||||
soundtrack
|
|
||||||
|
|
||||||
- NSF: Fixed Namco 106 problems with Final Lap and others
|
|
||||||
|
|
||||||
- Moved library sources to gme/ directory to reduce clutter, and merged
|
|
||||||
boost/ functionality into blargg_common.h
|
|
||||||
|
|
||||||
- Added Gzip_File_Reader for transparently using gzipped files
|
|
||||||
|
|
||||||
|
|
||||||
Game_Music_Emu 0.2.4
|
|
||||||
--------------------
|
|
||||||
- Created a discussion forum for problems and feedback:
|
|
||||||
http://groups-beta.google.com/group/blargg-sound-libs
|
|
||||||
|
|
||||||
- Changed error return value of Blip_Buffer::sample_rate() (also for
|
|
||||||
Stereo_Buffer, Effects_Buffer, etc.) to blargg_err_t (defined in
|
|
||||||
blargg_common.h), to make error reporting consistent with other
|
|
||||||
functions. This means the "no error" return value is the opposite of
|
|
||||||
what it was before, which will break current code which checks the error
|
|
||||||
return value:
|
|
||||||
|
|
||||||
// current code (broken)
|
|
||||||
if ( !buf.sample_rate( samples_per_sec ) )
|
|
||||||
out_of_memory();
|
|
||||||
|
|
||||||
// quick-and-dirty fix (just remove the ! operation)
|
|
||||||
if ( buf.sample_rate( samples_per_sec ) )
|
|
||||||
out_of_memory();
|
|
||||||
|
|
||||||
// proper fix
|
|
||||||
blargg_err_t error = buf.sample_rate( samples_per_sec );
|
|
||||||
if ( error )
|
|
||||||
report_error( error );
|
|
||||||
|
|
||||||
- Implemented workaround for MSVC++ 6 compiler limitations, allowing it
|
|
||||||
to work on that compiler again
|
|
||||||
|
|
||||||
- Added sample clamping to avoid wrap-around at high volumes, allowing
|
|
||||||
higher volume with little distortion
|
|
||||||
|
|
||||||
- Added to-do list and design notes
|
|
||||||
|
|
||||||
- Added Music_Emu::skip( long sample_count ) to skip ahead in current
|
|
||||||
track
|
|
||||||
|
|
||||||
- Added Gym_Emu::track_length() and Vgm_Emu::track_length() for
|
|
||||||
determining the length of non-looped GYM and VGM files
|
|
||||||
|
|
||||||
- Partially implemented DMC non-linearity when its value is directly set
|
|
||||||
using $4011, which reduces previously over-emphasized "popping" of
|
|
||||||
percussion on some games (TMNT II in particular)
|
|
||||||
|
|
||||||
- Fixed Fir_Resampler, used for SPC and GYM playback (was incorrectly
|
|
||||||
using abs() instead of fabs()...argh)
|
|
||||||
|
|
||||||
- Fixed SPC emulation bugs: eliminated clicks in Plok! soundtrack and
|
|
||||||
now stops sample slightly earlier than the end, as the SNES does. Fixed
|
|
||||||
a totally broken CPU addressing mode.
|
|
||||||
|
|
||||||
- Fixed Konami VRC6 saw wave (was very broken before). Now VRC6 music
|
|
||||||
sounds decent
|
|
||||||
|
|
||||||
- Fixed a minor GBS emulation bug
|
|
||||||
|
|
||||||
- Fixed GYM loop point bug when track was restarted before loop point
|
|
||||||
had been reached
|
|
||||||
|
|
||||||
- Made default GBS frequency equalization less muffled
|
|
||||||
|
|
||||||
- Added pseudo-surround effect removal for SPC files
|
|
||||||
|
|
||||||
- Added Music_Emu::voice_names() which returns names for each voice.
|
|
||||||
|
|
||||||
- Added BLARGG_SOURCE_BEGIN which allows custom compiler options to be
|
|
||||||
easily set for library sources
|
|
||||||
|
|
||||||
- Changed assignment of expansion sound chips in Nsf_Emu to be spread
|
|
||||||
more evenly when using Effects_Buffer
|
|
||||||
|
|
||||||
- Changed 'size_t' values in Blip_Buffer interface to 'long'
|
|
||||||
|
|
||||||
- Changed demo to generate a WAVE sound file rather than an AIFF file
|
|
||||||
|
|
||||||
|
|
||||||
Game_Music_Emu 0.2.0
|
|
||||||
--------------------
|
|
||||||
- Redid framework and rewrote/cleaned up emulators
|
|
||||||
|
|
||||||
- Changed licensing to GNU Lesser General Public License (LGPL)
|
|
||||||
|
|
||||||
- Added Sega Genesis GYM and Super Nintendo SPC emulators
|
|
||||||
|
|
||||||
- Added Namco-106 and Konami VRC6 sound chip support to NSF emulator
|
|
||||||
|
|
||||||
- Eliminated use of static mutable data in emulators, allowing
|
|
||||||
multi-instance safety
|
|
||||||
|
|
||||||
|
|
||||||
Game_Music_Emu 0.1.0
|
|
||||||
--------------------
|
|
||||||
- First release
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
Game_Music_Emu 0.6.1
|
Game_Music_Emu 0.6.2
|
||||||
--------------------
|
--------------------
|
||||||
Author : Shay Green <gblargg@gmail.com>
|
Author : Shay Green <gblargg@gmail.com>
|
||||||
Maintainer : Michael Pyne <mpyne@purinchu.net>
|
Maintainer : Michael Pyne <mpyne@purinchu.net>
|
||||||
Website : http://www.slack.net/~ant/libs/
|
Website : https://bitbucket.org/mpyne/game-music-emu/
|
||||||
Forum : http://groups.google.com/group/blargg-sound-libs
|
|
||||||
Source : https://bitbucket.org/mpyne/game-music-emu/
|
Source : https://bitbucket.org/mpyne/game-music-emu/
|
||||||
License : GNU Lesser General Public License (LGPL), see LICENSE.txt
|
License : GNU Lesser General Public License (LGPL), see LICENSE.txt
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Ay_Apu.h"
|
#include "Ay_Apu.h"
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ void Ay_Apu::run_until( blip_time_t final_end_time )
|
||||||
while ( ntime <= end ) // must advance *past* time to avoid hang
|
while ( ntime <= end ) // must advance *past* time to avoid hang
|
||||||
{
|
{
|
||||||
int changed = noise_lfsr + 1;
|
int changed = noise_lfsr + 1;
|
||||||
noise_lfsr = ((blargg_ulong)-(blargg_long)(noise_lfsr & 1) & 0x12000) ^ (noise_lfsr >> 1);
|
noise_lfsr = (-(noise_lfsr & 1) & 0x12000) ^ (noise_lfsr >> 1);
|
||||||
if ( changed & 2 )
|
if ( changed & 2 )
|
||||||
{
|
{
|
||||||
delta = -delta;
|
delta = -delta;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// AY-3-8910 sound chip emulator
|
// AY-3-8910 sound chip emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef AY_APU_H
|
#ifndef AY_APU_H
|
||||||
#define AY_APU_H
|
#define AY_APU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Last validated with zexall 2006.11.21 5:26 PM
|
Last validated with zexall 2006.11.21 5:26 PM
|
||||||
|
@ -136,11 +136,6 @@ static byte const ed_dd_timing [0x100] = {
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
// even on x86, using short and unsigned char was slower
|
|
||||||
typedef int fint16;
|
|
||||||
typedef unsigned fuint16;
|
|
||||||
typedef unsigned fuint8;
|
|
||||||
|
|
||||||
bool Ay_Cpu::run( cpu_time_t end_time )
|
bool Ay_Cpu::run( cpu_time_t end_time )
|
||||||
{
|
{
|
||||||
set_end_time( end_time );
|
set_end_time( end_time );
|
||||||
|
@ -148,8 +143,6 @@ bool Ay_Cpu::run( cpu_time_t end_time )
|
||||||
this->state = &s;
|
this->state = &s;
|
||||||
bool warning = false;
|
bool warning = false;
|
||||||
|
|
||||||
typedef BOOST::int8_t int8_t;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
regs_t rg;
|
regs_t rg;
|
||||||
pairs_t rp;
|
pairs_t rp;
|
||||||
|
@ -160,10 +153,10 @@ bool Ay_Cpu::run( cpu_time_t end_time )
|
||||||
|
|
||||||
cpu_time_t s_time = s.time;
|
cpu_time_t s_time = s.time;
|
||||||
uint8_t* const mem = this->mem; // cache
|
uint8_t* const mem = this->mem; // cache
|
||||||
fuint16 pc = r.pc;
|
uint16_t pc = r.pc;
|
||||||
fuint16 sp = r.sp;
|
uint16_t sp = r.sp;
|
||||||
fuint16 ix = r.ix; // TODO: keep in memory for direct access?
|
uint16_t ix = r.ix; // TODO: keep in memory for direct access?
|
||||||
fuint16 iy = r.iy;
|
uint16_t iy = r.iy;
|
||||||
int flags = r.b.flags;
|
int flags = r.b.flags;
|
||||||
|
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -182,7 +175,7 @@ loop:
|
||||||
check( (unsigned) ix < 0x10000 );
|
check( (unsigned) ix < 0x10000 );
|
||||||
check( (unsigned) iy < 0x10000 );
|
check( (unsigned) iy < 0x10000 );
|
||||||
|
|
||||||
fuint8 opcode;
|
uint8_t opcode;
|
||||||
opcode = READ_PROG( pc );
|
opcode = READ_PROG( pc );
|
||||||
pc++;
|
pc++;
|
||||||
|
|
||||||
|
@ -206,7 +199,7 @@ loop:
|
||||||
11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
|
11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
|
||||||
};
|
};
|
||||||
|
|
||||||
fuint16 data;
|
uint16_t data;
|
||||||
data = base_timing [opcode];
|
data = base_timing [opcode];
|
||||||
if ( (s_time += data) >= 0 )
|
if ( (s_time += data) >= 0 )
|
||||||
goto possibly_out_of_time;
|
goto possibly_out_of_time;
|
||||||
|
@ -262,7 +255,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x3A:{// LD A,(addr)
|
case 0x3A:{// LD A,(addr)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
rg.a = READ( addr );
|
rg.a = READ( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -277,7 +270,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
// JR
|
// JR
|
||||||
#define JR( cond ) {\
|
#define JR( cond ) {\
|
||||||
int disp = (BOOST::int8_t) data;\
|
int disp = (int8_t) data;\
|
||||||
pc++;\
|
pc++;\
|
||||||
if ( !(cond) )\
|
if ( !(cond) )\
|
||||||
goto jr_not_taken;\
|
goto jr_not_taken;\
|
||||||
|
@ -349,7 +342,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0xCD:{// CALL addr
|
case 0xCD:{// CALL addr
|
||||||
call_taken:
|
call_taken:
|
||||||
fuint16 addr = pc + 2;
|
uint16_t addr = pc + 2;
|
||||||
pc = GET_ADDR();
|
pc = GET_ADDR();
|
||||||
sp = uint16_t (sp - 2);
|
sp = uint16_t (sp - 2);
|
||||||
WRITE_WORD( sp, addr );
|
WRITE_WORD( sp, addr );
|
||||||
|
@ -469,7 +462,7 @@ possibly_out_of_time:
|
||||||
add_hl_data: {
|
add_hl_data: {
|
||||||
blargg_ulong sum = rp.hl + data;
|
blargg_ulong sum = rp.hl + data;
|
||||||
data ^= rp.hl;
|
data ^= rp.hl;
|
||||||
rp.hl = (uint16_t)sum;
|
rp.hl = sum;
|
||||||
flags = (flags & (S80 | Z40 | V04)) |
|
flags = (flags & (S80 | Z40 | V04)) |
|
||||||
(sum >> 16) |
|
(sum >> 16) |
|
||||||
(sum >> 8 & (F20 | F08)) |
|
(sum >> 8 & (F20 | F08)) |
|
||||||
|
@ -659,21 +652,21 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x2A:{// LD HL,(addr)
|
case 0x2A:{// LD HL,(addr)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
rp.hl = READ_WORD( addr );
|
rp.hl = READ_WORD( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x32:{// LD (addr),A
|
case 0x32:{// LD (addr),A
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE( addr, rg.a );
|
WRITE( addr, rg.a );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x22:{// LD (addr),HL
|
case 0x22:{// LD (addr),HL
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE_WORD( addr, rp.hl );
|
WRITE_WORD( addr, rp.hl );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -696,7 +689,7 @@ possibly_out_of_time:
|
||||||
// Rotate
|
// Rotate
|
||||||
|
|
||||||
case 0x07:{// RLCA
|
case 0x07:{// RLCA
|
||||||
fuint16 temp = rg.a;
|
uint16_t temp = rg.a;
|
||||||
temp = (temp << 1) | (temp >> 7);
|
temp = (temp << 1) | (temp >> 7);
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & (F20 | F08 | C01));
|
(temp & (F20 | F08 | C01));
|
||||||
|
@ -705,7 +698,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x0F:{// RRCA
|
case 0x0F:{// RRCA
|
||||||
fuint16 temp = rg.a;
|
uint16_t temp = rg.a;
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & C01);
|
(temp & C01);
|
||||||
temp = (temp << 7) | (temp >> 1);
|
temp = (temp << 7) | (temp >> 1);
|
||||||
|
@ -719,12 +712,12 @@ possibly_out_of_time:
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & (F20 | F08)) |
|
(temp & (F20 | F08)) |
|
||||||
(temp >> 8);
|
(temp >> 8);
|
||||||
rg.a = (uint8_t)temp;
|
rg.a = temp;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x1F:{// RRA
|
case 0x1F:{// RRA
|
||||||
fuint16 temp = (flags << 7) | (rg.a >> 1);
|
uint16_t temp = (flags << 7) | (rg.a >> 1);
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & (F20 | F08)) |
|
(temp & (F20 | F08)) |
|
||||||
(rg.a & C01);
|
(rg.a & C01);
|
||||||
|
@ -734,7 +727,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
case 0x2F:{// CPL
|
case 0x2F:{// CPL
|
||||||
fuint16 temp = ~rg.a;
|
uint16_t temp = ~rg.a;
|
||||||
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
||||||
(temp & (F20 | F08)) |
|
(temp & (F20 | F08)) |
|
||||||
(H10 | N02);
|
(H10 | N02);
|
||||||
|
@ -760,21 +753,21 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xE3:{// EX (SP),HL
|
case 0xE3:{// EX (SP),HL
|
||||||
fuint16 temp = READ_WORD( sp );
|
uint16_t temp = READ_WORD( sp );
|
||||||
WRITE_WORD( sp, rp.hl );
|
WRITE_WORD( sp, rp.hl );
|
||||||
rp.hl = temp;
|
rp.hl = temp;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xEB:{// EX DE,HL
|
case 0xEB:{// EX DE,HL
|
||||||
fuint16 temp = rp.hl;
|
uint16_t temp = rp.hl;
|
||||||
rp.hl = rp.de;
|
rp.hl = rp.de;
|
||||||
rp.de = temp;
|
rp.de = temp;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xD9:{// EXX DE,HL
|
case 0xD9:{// EXX DE,HL
|
||||||
fuint16 temp = r.alt.w.bc;
|
uint16_t temp = r.alt.w.bc;
|
||||||
r.alt.w.bc = rp.bc;
|
r.alt.w.bc = rp.bc;
|
||||||
rp.bc = temp;
|
rp.bc = temp;
|
||||||
|
|
||||||
|
@ -815,7 +808,7 @@ possibly_out_of_time:
|
||||||
// Rotate left
|
// Rotate left
|
||||||
|
|
||||||
#define RLC( read, write ) {\
|
#define RLC( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
result = uint8_t (result << 1) | (result >> 7);\
|
result = uint8_t (result << 1) | (result >> 7);\
|
||||||
flags = SZ28P( result ) | (result & C01);\
|
flags = SZ28P( result ) | (result & C01);\
|
||||||
write;\
|
write;\
|
||||||
|
@ -834,7 +827,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RL( read, write ) {\
|
#define RL( read, write ) {\
|
||||||
fuint16 result = (read << 1) | (flags & C01);\
|
uint16_t result = (read << 1) | (flags & C01);\
|
||||||
flags = SZ28PC( result );\
|
flags = SZ28PC( result );\
|
||||||
write;\
|
write;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
|
@ -852,7 +845,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SLA( read, add, write ) {\
|
#define SLA( read, add, write ) {\
|
||||||
fuint16 result = (read << 1) | add;\
|
uint16_t result = (read << 1) | add;\
|
||||||
flags = SZ28PC( result );\
|
flags = SZ28PC( result );\
|
||||||
write;\
|
write;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
|
@ -883,7 +876,7 @@ possibly_out_of_time:
|
||||||
// Rotate right
|
// Rotate right
|
||||||
|
|
||||||
#define RRC( read, write ) {\
|
#define RRC( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
flags = result & C01;\
|
flags = result & C01;\
|
||||||
result = uint8_t (result << 7) | (result >> 1);\
|
result = uint8_t (result << 7) | (result >> 1);\
|
||||||
flags |= SZ28P( result );\
|
flags |= SZ28P( result );\
|
||||||
|
@ -903,8 +896,8 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RR( read, write ) {\
|
#define RR( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
fuint8 temp = result & C01;\
|
uint8_t temp = result & C01;\
|
||||||
result = uint8_t (flags << 7) | (result >> 1);\
|
result = uint8_t (flags << 7) | (result >> 1);\
|
||||||
flags = SZ28P( result ) | temp;\
|
flags = SZ28P( result ) | temp;\
|
||||||
write;\
|
write;\
|
||||||
|
@ -923,7 +916,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SRA( read, write ) {\
|
#define SRA( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
flags = result & C01;\
|
flags = result & C01;\
|
||||||
result = (result & 0x80) | (result >> 1);\
|
result = (result & 0x80) | (result >> 1);\
|
||||||
flags |= SZ28P( result );\
|
flags |= SZ28P( result );\
|
||||||
|
@ -943,7 +936,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SRL( read, write ) {\
|
#define SRL( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
flags = result & C01;\
|
flags = result & C01;\
|
||||||
result >>= 1;\
|
result >>= 1;\
|
||||||
flags |= SZ28P( result );\
|
flags |= SZ28P( result );\
|
||||||
|
@ -1048,7 +1041,7 @@ possibly_out_of_time:
|
||||||
blargg_ulong sum = temp + (flags & C01);
|
blargg_ulong sum = temp + (flags & C01);
|
||||||
flags = ~data >> 2 & N02;
|
flags = ~data >> 2 & N02;
|
||||||
if ( flags )
|
if ( flags )
|
||||||
sum = (blargg_ulong)-(blargg_long)sum;
|
sum = -sum;
|
||||||
sum += rp.hl;
|
sum += rp.hl;
|
||||||
temp ^= rp.hl;
|
temp ^= rp.hl;
|
||||||
temp ^= sum;
|
temp ^= sum;
|
||||||
|
@ -1056,7 +1049,7 @@ possibly_out_of_time:
|
||||||
(temp >> 8 & H10) |
|
(temp >> 8 & H10) |
|
||||||
(sum >> 8 & (S80 | F20 | F08)) |
|
(sum >> 8 & (S80 | F20 | F08)) |
|
||||||
((temp - -0x8000) >> 14 & V04);
|
((temp - -0x8000) >> 14 & V04);
|
||||||
rp.hl = (uint16_t)sum;
|
rp.hl = sum;
|
||||||
if ( (uint16_t) sum )
|
if ( (uint16_t) sum )
|
||||||
goto loop;
|
goto loop;
|
||||||
flags |= Z40;
|
flags |= Z40;
|
||||||
|
@ -1084,7 +1077,7 @@ possibly_out_of_time:
|
||||||
case 0x43: // LD (ADDR),BC
|
case 0x43: // LD (ADDR),BC
|
||||||
case 0x53: // LD (ADDR),DE
|
case 0x53: // LD (ADDR),DE
|
||||||
temp = R16( data, 4, 0x43 );
|
temp = R16( data, 4, 0x43 );
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE_WORD( addr, temp );
|
WRITE_WORD( addr, temp );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -1092,21 +1085,21 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0x4B: // LD BC,(ADDR)
|
case 0x4B: // LD BC,(ADDR)
|
||||||
case 0x5B:{// LD DE,(ADDR)
|
case 0x5B:{// LD DE,(ADDR)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x7B:{// LD SP,(ADDR)
|
case 0x7B:{// LD SP,(ADDR)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
sp = READ_WORD( addr );
|
sp = READ_WORD( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x67:{// RRD
|
case 0x67:{// RRD
|
||||||
fuint8 temp = READ( rp.hl );
|
uint8_t temp = READ( rp.hl );
|
||||||
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
||||||
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
||||||
flags = (flags & C01) | SZ28P( temp );
|
flags = (flags & C01) | SZ28P( temp );
|
||||||
|
@ -1115,7 +1108,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x6F:{// RLD
|
case 0x6F:{// RLD
|
||||||
fuint8 temp = READ( rp.hl );
|
uint8_t temp = READ( rp.hl );
|
||||||
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
||||||
temp = (rg.a & 0xF0) | (temp >> 4);
|
temp = (rg.a & 0xF0) | (temp >> 4);
|
||||||
flags = (flags & C01) | SZ28P( temp );
|
flags = (flags & C01) | SZ28P( temp );
|
||||||
|
@ -1139,7 +1132,7 @@ possibly_out_of_time:
|
||||||
case 0xA1: // CPI
|
case 0xA1: // CPI
|
||||||
case 0xB1: // CPIR
|
case 0xB1: // CPIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
int temp = READ( addr );
|
int temp = READ( addr );
|
||||||
|
|
||||||
|
@ -1172,7 +1165,7 @@ possibly_out_of_time:
|
||||||
case 0xA0: // LDI
|
case 0xA0: // LDI
|
||||||
case 0xB0: // LDIR
|
case 0xB0: // LDIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
int temp = READ( addr );
|
int temp = READ( addr );
|
||||||
|
|
||||||
|
@ -1204,7 +1197,7 @@ possibly_out_of_time:
|
||||||
case 0xA3: // OUTI
|
case 0xA3: // OUTI
|
||||||
case 0xB3: // OTIR
|
case 0xB3: // OTIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
int temp = READ( addr );
|
int temp = READ( addr );
|
||||||
|
|
||||||
|
@ -1230,7 +1223,7 @@ possibly_out_of_time:
|
||||||
case 0xB2: // INIR
|
case 0xB2: // INIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
|
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
|
|
||||||
int temp = IN( rp.bc );
|
int temp = IN( rp.bc );
|
||||||
|
@ -1295,7 +1288,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
//////////////////////////////////////// DD/FD prefix
|
//////////////////////////////////////// DD/FD prefix
|
||||||
{
|
{
|
||||||
fuint16 ixy;
|
uint16_t ixy;
|
||||||
case 0xDD:
|
case 0xDD:
|
||||||
ixy = ix;
|
ixy = ix;
|
||||||
goto ix_prefix;
|
goto ix_prefix;
|
||||||
|
@ -1490,7 +1483,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x22:{// LD (ADDR),IXY
|
case 0x22:{// LD (ADDR),IXY
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE_WORD( addr, ixy );
|
WRITE_WORD( addr, ixy );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -1502,7 +1495,7 @@ possibly_out_of_time:
|
||||||
goto set_ixy;
|
goto set_ixy;
|
||||||
|
|
||||||
case 0x2A:{// LD IXY,(addr)
|
case 0x2A:{// LD IXY,(addr)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
ixy = READ_WORD( addr );
|
ixy = READ_WORD( addr );
|
||||||
pc += 2;
|
pc += 2;
|
||||||
goto set_ixy;
|
goto set_ixy;
|
||||||
|
@ -1526,7 +1519,7 @@ possibly_out_of_time:
|
||||||
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
||||||
|
|
||||||
CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
|
CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
|
||||||
fuint8 temp = READ( data );
|
uint8_t temp = READ( data );
|
||||||
int masked = temp & 1 << (data2 >> 3 & 7);
|
int masked = temp & 1 << (data2 >> 3 & 7);
|
||||||
flags = (flags & C01) | H10 |
|
flags = (flags & C01) | H10 |
|
||||||
(masked & S80) |
|
(masked & S80) |
|
||||||
|
@ -1628,7 +1621,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xE3:{// EX (SP),IXY
|
case 0xE3:{// EX (SP),IXY
|
||||||
fuint16 temp = READ_WORD( sp );
|
uint16_t temp = READ_WORD( sp );
|
||||||
WRITE_WORD( sp, ixy );
|
WRITE_WORD( sp, ixy );
|
||||||
ixy = temp;
|
ixy = temp;
|
||||||
goto set_ixy;
|
goto set_ixy;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Z80 CPU emulator
|
// Z80 CPU emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef AY_CPU_H
|
#ifndef AY_CPU_H
|
||||||
#define AY_CPU_H
|
#define AY_CPU_H
|
||||||
|
|
||||||
|
@ -28,9 +28,6 @@ public:
|
||||||
void set_time( cpu_time_t t ) { state->time = t - state->base; }
|
void set_time( cpu_time_t t ) { state->time = t - state->base; }
|
||||||
void adjust_time( int delta ) { state->time += delta; }
|
void adjust_time( int delta ) { state->time += delta; }
|
||||||
|
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
typedef BOOST::uint16_t uint16_t;
|
|
||||||
|
|
||||||
#if BLARGG_BIG_ENDIAN
|
#if BLARGG_BIG_ENDIAN
|
||||||
struct regs_t { uint8_t b, c, d, e, h, l, flags, a; };
|
struct regs_t { uint8_t b, c, d, e, h, l, flags, a; };
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Ay_Emu.h"
|
#include "Ay_Emu.h"
|
||||||
|
|
||||||
|
@ -47,10 +47,10 @@ Ay_Emu::~Ay_Emu() { }
|
||||||
|
|
||||||
static byte const* get_data( Ay_Emu::file_t const& file, byte const* ptr, int min_size )
|
static byte const* get_data( Ay_Emu::file_t const& file, byte const* ptr, int min_size )
|
||||||
{
|
{
|
||||||
long pos = long(ptr - (byte const*) file.header);
|
long pos = ptr - (byte const*) file.header;
|
||||||
long file_size = long(file.end - (byte const*) file.header);
|
long file_size = file.end - (byte const*) file.header;
|
||||||
assert( (unsigned long) pos <= (unsigned long) file_size - 2 );
|
assert( (unsigned long) pos <= (unsigned long) file_size - 2 );
|
||||||
int offset = (BOOST::int16_t) get_be16( ptr );
|
int offset = (int16_t) get_be16( ptr );
|
||||||
if ( !offset || blargg_ulong (pos + offset) > blargg_ulong (file_size - min_size) )
|
if ( !offset || blargg_ulong (pos + offset) > blargg_ulong (file_size - min_size) )
|
||||||
return 0;
|
return 0;
|
||||||
return ptr + offset;
|
return ptr + offset;
|
||||||
|
@ -117,7 +117,7 @@ static Music_Emu* new_ay_emu () { return BLARGG_NEW Ay_Emu ; }
|
||||||
static Music_Emu* new_ay_file() { return BLARGG_NEW Ay_File; }
|
static Music_Emu* new_ay_file() { return BLARGG_NEW Ay_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_ay_type_ = { "ZX Spectrum", 0, &new_ay_emu, &new_ay_file, "AY", 1 };
|
static gme_type_t_ const gme_ay_type_ = { "ZX Spectrum", 0, &new_ay_emu, &new_ay_file, "AY", 1 };
|
||||||
gme_type_t const gme_ay_type = &gme_ay_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_ay_type = &gme_ay_type_;
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ blargg_err_t Ay_Emu::start_track_( int track )
|
||||||
if ( len > blargg_ulong (file.end - in) )
|
if ( len > blargg_ulong (file.end - in) )
|
||||||
{
|
{
|
||||||
set_warning( "Missing file data" );
|
set_warning( "Missing file data" );
|
||||||
len = unsigned(file.end - in);
|
len = file.end - in;
|
||||||
}
|
}
|
||||||
//debug_printf( "addr: $%04X, len: $%04X\n", addr, len );
|
//debug_printf( "addr: $%04X, len: $%04X\n", addr, len );
|
||||||
if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data
|
if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Sinclair Spectrum AY music file emulator
|
// Sinclair Spectrum AY music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef AY_EMU_H
|
#ifndef AY_EMU_H
|
||||||
#define AY_EMU_H
|
#define AY_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,8 @@ public:
|
||||||
Blip_Buffer();
|
Blip_Buffer();
|
||||||
~Blip_Buffer();
|
~Blip_Buffer();
|
||||||
|
|
||||||
|
Blip_Buffer(Blip_Buffer &&) = default;
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
typedef blip_resampled_time_t resampled_time_t;
|
typedef blip_resampled_time_t resampled_time_t;
|
||||||
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
|
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
|
||||||
|
|
|
@ -14,6 +14,15 @@ set(libgme_SRCS Blip_Buffer.cpp
|
||||||
Music_Emu.cpp
|
Music_Emu.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# static builds need to find static zlib (and static forms of other needed
|
||||||
|
# libraries. Ensure CMake looks only for static libs if we're doing a static
|
||||||
|
# build. See https://stackoverflow.com/a/44738756
|
||||||
|
if(NOT BUILD_SHARED_LIBS)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(ZLIB QUIET)
|
||||||
|
|
||||||
# Ay_Apu is very popular around here
|
# Ay_Apu is very popular around here
|
||||||
if (USE_GME_AY OR USE_GME_KSS)
|
if (USE_GME_AY OR USE_GME_KSS)
|
||||||
set(libgme_SRCS ${libgme_SRCS}
|
set(libgme_SRCS ${libgme_SRCS}
|
||||||
|
@ -23,9 +32,25 @@ endif()
|
||||||
|
|
||||||
# so is Ym2612_Emu
|
# so is Ym2612_Emu
|
||||||
if (USE_GME_VGM OR USE_GME_GYM)
|
if (USE_GME_VGM OR USE_GME_GYM)
|
||||||
|
if(GME_YM2612_EMU STREQUAL "Nuked")
|
||||||
|
add_definitions(-DVGM_YM2612_NUKED)
|
||||||
set(libgme_SRCS ${libgme_SRCS}
|
set(libgme_SRCS ${libgme_SRCS}
|
||||||
Ym2612_Emu.cpp
|
Ym2612_Nuked.cpp
|
||||||
)
|
)
|
||||||
|
message("VGM/GYM: Nuked OPN2 emulator will be used")
|
||||||
|
elseif(GME_YM2612_EMU STREQUAL "MAME")
|
||||||
|
add_definitions(-DVGM_YM2612_MAME)
|
||||||
|
set(libgme_SRCS ${libgme_SRCS}
|
||||||
|
Ym2612_MAME.cpp
|
||||||
|
)
|
||||||
|
message("VGM/GYM: MAME YM2612 emulator will be used")
|
||||||
|
else()
|
||||||
|
add_definitions(-DVGM_YM2612_GENS)
|
||||||
|
set(libgme_SRCS ${libgme_SRCS}
|
||||||
|
Ym2612_GENS.cpp
|
||||||
|
)
|
||||||
|
message("VGM/GYM: GENS 2.10 emulator will be used")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# But none are as popular as Sms_Apu
|
# But none are as popular as Sms_Apu
|
||||||
|
@ -127,19 +152,11 @@ endif()
|
||||||
# These headers are part of the generic gme interface.
|
# These headers are part of the generic gme interface.
|
||||||
set (EXPORTED_HEADERS gme.h)
|
set (EXPORTED_HEADERS gme.h)
|
||||||
|
|
||||||
# Run during cmake phase, so this is available during make
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gme_types.h.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/gme_types.h)
|
|
||||||
|
|
||||||
# [ZDoom] Not needed.
|
|
||||||
if( FALSE )
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libgme.pc.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/libgme.pc @ONLY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# On some platforms we may need to change headers or whatnot based on whether
|
# On some platforms we may need to change headers or whatnot based on whether
|
||||||
# we're building the library or merely using the library. The following is
|
# we're building the library or merely using the library. The following is
|
||||||
# only defined when building the library to allow us to tell which is which.
|
# only defined when building the library to allow us to tell which is which.
|
||||||
|
|
||||||
|
#[ZDoom] Not needed
|
||||||
#add_definitions(-DBLARGG_BUILD_DLL)
|
#add_definitions(-DBLARGG_BUILD_DLL)
|
||||||
|
|
||||||
# For the gme_types.h
|
# For the gme_types.h
|
||||||
|
@ -148,13 +165,25 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
# Add library to be compiled.
|
# Add library to be compiled.
|
||||||
add_library(gme ${libgme_SRCS})
|
add_library(gme ${libgme_SRCS})
|
||||||
|
|
||||||
|
if(ZLIB_FOUND)
|
||||||
|
message(" ** ZLib library located, compressed file formats will be supported")
|
||||||
|
target_compile_definitions(gme PRIVATE -DHAVE_ZLIB_H)
|
||||||
|
target_include_directories(gme PRIVATE ${ZLIB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(gme ${ZLIB_LIBRARIES})
|
||||||
|
# Is not to be installed though
|
||||||
|
|
||||||
|
set(PKG_CONFIG_ZLIB -lz) # evaluated in libgme.pc.in
|
||||||
|
else()
|
||||||
|
message("ZLib library not found, disabling support for compressed formats such as VGZ")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# [ZDoom] Not needed.
|
||||||
|
if( FALSE )
|
||||||
# The version is the release. The "soversion" is the API version. As long
|
# The version is the release. The "soversion" is the API version. As long
|
||||||
# as only build fixes are performed (i.e. no backwards-incompatible changes
|
# as only build fixes are performed (i.e. no backwards-incompatible changes
|
||||||
# to the API), the SOVERSION should be the same even when bumping up VERSION.
|
# to the API), the SOVERSION should be the same even when bumping up VERSION.
|
||||||
# The way gme.h is designed, SOVERSION should very rarely be bumped, if ever.
|
# The way gme.h is designed, SOVERSION should very rarely be bumped, if ever.
|
||||||
# Hopefully the API can stay compatible with old versions.
|
# Hopefully the API can stay compatible with old versions.
|
||||||
# [ZDoom] Not needed.
|
|
||||||
if( FALSE )
|
|
||||||
set_target_properties(gme
|
set_target_properties(gme
|
||||||
PROPERTIES VERSION ${GME_VERSION}
|
PROPERTIES VERSION ${GME_VERSION}
|
||||||
SOVERSION 0)
|
SOVERSION 0)
|
||||||
|
@ -163,8 +192,13 @@ install(TARGETS gme LIBRARY DESTINATION lib${LIB_SUFFIX}
|
||||||
RUNTIME DESTINATION bin # DLL platforms
|
RUNTIME DESTINATION bin # DLL platforms
|
||||||
ARCHIVE DESTINATION lib) # DLL platforms
|
ARCHIVE DESTINATION lib) # DLL platforms
|
||||||
|
|
||||||
|
# Run during cmake phase, so this is available during make
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gme_types.h.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/gme_types.h)
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libgme.pc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/libgme.pc @ONLY)
|
||||||
|
|
||||||
install(FILES ${EXPORTED_HEADERS} DESTINATION include/gme)
|
install(FILES ${EXPORTED_HEADERS} DESTINATION include/gme)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(gme)
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Classic_Emu.h"
|
#include "Classic_Emu.h"
|
||||||
|
|
||||||
|
@ -54,6 +54,12 @@ blargg_err_t Classic_Emu::set_sample_rate_( long rate )
|
||||||
return buf->set_sample_rate( rate, 1000 / 20 );
|
return buf->set_sample_rate( rate, 1000 / 20 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blargg_err_t Classic_Emu::set_multi_channel ( bool is_enabled )
|
||||||
|
{
|
||||||
|
RETURN_ERR( Music_Emu::set_multi_channel_( is_enabled ) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Classic_Emu::mute_voices_( int mask )
|
void Classic_Emu::mute_voices_( int mask )
|
||||||
{
|
{
|
||||||
Music_Emu::mute_voices_( mask );
|
Music_Emu::mute_voices_( mask );
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Common aspects of emulators which use Blip_Buffer for sound output
|
// Common aspects of emulators which use Blip_Buffer for sound output
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef CLASSIC_EMU_H
|
#ifndef CLASSIC_EMU_H
|
||||||
#define CLASSIC_EMU_H
|
#define CLASSIC_EMU_H
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ public:
|
||||||
Classic_Emu();
|
Classic_Emu();
|
||||||
~Classic_Emu();
|
~Classic_Emu();
|
||||||
void set_buffer( Multi_Buffer* );
|
void set_buffer( Multi_Buffer* );
|
||||||
|
blargg_err_t set_multi_channel( bool is_enabled ) override;
|
||||||
protected:
|
protected:
|
||||||
// Services
|
// Services
|
||||||
enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
|
enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// File_Extractor 0.4.0. http://www.slack.net/~ant/
|
// File_Extractor 0.4.0. http://www.slack.net/~ant/
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
|
|
||||||
#include "Data_Reader.h"
|
#include "Data_Reader.h"
|
||||||
|
|
||||||
#include "blargg_endian.h"
|
#include "blargg_endian.h"
|
||||||
|
@ -22,10 +20,22 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
#include "blargg_source.h"
|
#include "blargg_source.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_ZLIB_H
|
||||||
|
#include <zlib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
static const unsigned char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
|
|
||||||
const char Data_Reader::eof_error [] = "Unexpected end of file";
|
const char Data_Reader::eof_error [] = "Unexpected end of file";
|
||||||
|
|
||||||
|
#define RETURN_VALIDITY_CHECK( cond ) \
|
||||||
|
do { if ( unlikely( !(cond) ) ) return "Corrupt file"; } while(0)
|
||||||
|
|
||||||
blargg_err_t Data_Reader::read( void* p, long s )
|
blargg_err_t Data_Reader::read( void* p, long s )
|
||||||
{
|
{
|
||||||
|
RETURN_VALIDITY_CHECK( s > 0 );
|
||||||
|
|
||||||
long result = read_avail( p, s );
|
long result = read_avail( p, s );
|
||||||
if ( result != s )
|
if ( result != s )
|
||||||
{
|
{
|
||||||
|
@ -40,6 +50,8 @@ blargg_err_t Data_Reader::read( void* p, long s )
|
||||||
|
|
||||||
blargg_err_t Data_Reader::skip( long count )
|
blargg_err_t Data_Reader::skip( long count )
|
||||||
{
|
{
|
||||||
|
RETURN_VALIDITY_CHECK( count >= 0 );
|
||||||
|
|
||||||
char buf [512];
|
char buf [512];
|
||||||
while ( count )
|
while ( count )
|
||||||
{
|
{
|
||||||
|
@ -56,7 +68,8 @@ long File_Reader::remain() const { return size() - tell(); }
|
||||||
|
|
||||||
blargg_err_t File_Reader::skip( long n )
|
blargg_err_t File_Reader::skip( long n )
|
||||||
{
|
{
|
||||||
assert( n >= 0 );
|
RETURN_VALIDITY_CHECK( n >= 0 );
|
||||||
|
|
||||||
if ( !n )
|
if ( !n )
|
||||||
return 0;
|
return 0;
|
||||||
return seek( tell() + n );
|
return seek( tell() + n );
|
||||||
|
@ -69,13 +82,14 @@ Subset_Reader::Subset_Reader( Data_Reader* dr, long size )
|
||||||
in = dr;
|
in = dr;
|
||||||
remain_ = dr->remain();
|
remain_ = dr->remain();
|
||||||
if ( remain_ > size )
|
if ( remain_ > size )
|
||||||
remain_ = size;
|
remain_ = max( 0l, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
long Subset_Reader::remain() const { return remain_; }
|
long Subset_Reader::remain() const { return remain_; }
|
||||||
|
|
||||||
long Subset_Reader::read_avail( void* p, long s )
|
long Subset_Reader::read_avail( void* p, long s )
|
||||||
{
|
{
|
||||||
|
s = max( 0l, s );
|
||||||
if ( s > remain_ )
|
if ( s > remain_ )
|
||||||
s = remain_;
|
s = remain_;
|
||||||
remain_ -= s;
|
remain_ -= s;
|
||||||
|
@ -87,30 +101,32 @@ long Subset_Reader::read_avail( void* p, long s )
|
||||||
Remaining_Reader::Remaining_Reader( void const* h, long size, Data_Reader* r )
|
Remaining_Reader::Remaining_Reader( void const* h, long size, Data_Reader* r )
|
||||||
{
|
{
|
||||||
header = (char const*) h;
|
header = (char const*) h;
|
||||||
header_end = header + size;
|
header_end = header + max( 0l, size );
|
||||||
in = r;
|
in = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Remaining_Reader::remain() const { return long(header_end - header + in->remain()); }
|
long Remaining_Reader::remain() const { return header_end - header + in->remain(); }
|
||||||
|
|
||||||
long Remaining_Reader::read_first( void* out, long count )
|
long Remaining_Reader::read_first( void* out, long count )
|
||||||
{
|
{
|
||||||
long first = long(header_end - header);
|
count = max( 0l, count );
|
||||||
|
long first = header_end - header;
|
||||||
if ( first )
|
if ( first )
|
||||||
{
|
{
|
||||||
if ( first > count )
|
if ( first > count || first < 0 )
|
||||||
first = count;
|
first = count;
|
||||||
void const* old = header;
|
void const* old = header;
|
||||||
header += first;
|
header += first;
|
||||||
memcpy( out, old, first );
|
memcpy( out, old, (size_t) first );
|
||||||
}
|
}
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Remaining_Reader::read_avail( void* out, long count )
|
long Remaining_Reader::read_avail( void* out, long count )
|
||||||
{
|
{
|
||||||
|
count = max( 0l, count );
|
||||||
long first = read_first( out, count );
|
long first = read_first( out, count );
|
||||||
long second = count - first;
|
long second = max( 0l, count - first );
|
||||||
if ( second )
|
if ( second )
|
||||||
{
|
{
|
||||||
second = in->read_avail( (char*) out + first, second );
|
second = in->read_avail( (char*) out + first, second );
|
||||||
|
@ -122,8 +138,9 @@ long Remaining_Reader::read_avail( void* out, long count )
|
||||||
|
|
||||||
blargg_err_t Remaining_Reader::read( void* out, long count )
|
blargg_err_t Remaining_Reader::read( void* out, long count )
|
||||||
{
|
{
|
||||||
|
count = max( 0l, count );
|
||||||
long first = read_first( out, count );
|
long first = read_first( out, count );
|
||||||
long second = count - first;
|
long second = max( 0l, count - first );
|
||||||
if ( !second )
|
if ( !second )
|
||||||
return 0;
|
return 0;
|
||||||
return in->read( (char*) out + first, second );
|
return in->read( (char*) out + first, second );
|
||||||
|
@ -132,41 +149,135 @@ blargg_err_t Remaining_Reader::read( void* out, long count )
|
||||||
// Mem_File_Reader
|
// Mem_File_Reader
|
||||||
|
|
||||||
Mem_File_Reader::Mem_File_Reader( const void* p, long s ) :
|
Mem_File_Reader::Mem_File_Reader( const void* p, long s ) :
|
||||||
begin( (const char*) p ),
|
m_begin( (const char*) p ),
|
||||||
size_( s )
|
m_size( max( 0l, s ) ),
|
||||||
|
m_pos( 0l )
|
||||||
{
|
{
|
||||||
pos = 0;
|
#ifdef HAVE_ZLIB_H
|
||||||
|
if( !m_begin )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( gz_decompress() )
|
||||||
|
{
|
||||||
|
debug_printf( "Loaded compressed data\n" );
|
||||||
|
m_ownedPtr = true;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
}
|
}
|
||||||
|
|
||||||
long Mem_File_Reader::size() const { return size_; }
|
#ifdef HAVE_ZLIB_H
|
||||||
|
Mem_File_Reader::~Mem_File_Reader()
|
||||||
|
{
|
||||||
|
if ( m_ownedPtr )
|
||||||
|
free( const_cast<char*>( m_begin ) ); // see gz_compress for the malloc
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
long Mem_File_Reader::size() const { return m_size; }
|
||||||
|
|
||||||
long Mem_File_Reader::read_avail( void* p, long s )
|
long Mem_File_Reader::read_avail( void* p, long s )
|
||||||
{
|
{
|
||||||
long r = remain();
|
long r = remain();
|
||||||
if ( s > r )
|
if ( s > r || s < 0 )
|
||||||
s = r;
|
s = r;
|
||||||
memcpy( p, begin + pos, s );
|
memcpy( p, m_begin + m_pos, static_cast<size_t>(s) );
|
||||||
pos += s;
|
m_pos += s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Mem_File_Reader::tell() const { return pos; }
|
long Mem_File_Reader::tell() const { return m_pos; }
|
||||||
|
|
||||||
blargg_err_t Mem_File_Reader::seek( long n )
|
blargg_err_t Mem_File_Reader::seek( long n )
|
||||||
{
|
{
|
||||||
if ( n > size_ )
|
RETURN_VALIDITY_CHECK( n >= 0 );
|
||||||
|
if ( n > m_size )
|
||||||
return eof_error;
|
return eof_error;
|
||||||
pos = n;
|
m_pos = n;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ZLIB_H
|
||||||
|
|
||||||
|
bool Mem_File_Reader::gz_decompress()
|
||||||
|
{
|
||||||
|
if ( m_size >= 2 && memcmp(m_begin, gz_magic, 2) != 0 )
|
||||||
|
{
|
||||||
|
/* Don't try to decompress non-GZ files, just assign input pointer */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using vec_size = size_t;
|
||||||
|
const vec_size full_length = static_cast<vec_size>( m_size );
|
||||||
|
const vec_size half_length = static_cast<vec_size>( m_size / 2 );
|
||||||
|
|
||||||
|
// We use malloc/friends here so we can realloc to grow buffer if needed
|
||||||
|
char *raw_data = reinterpret_cast<char *> ( malloc( full_length ) );
|
||||||
|
size_t raw_data_size = full_length;
|
||||||
|
if ( !raw_data )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
z_stream strm;
|
||||||
|
strm.next_in = const_cast<Bytef *>( reinterpret_cast<const Bytef *>( m_begin ) );
|
||||||
|
strm.avail_in = static_cast<uInt>( m_size );
|
||||||
|
strm.total_out = 0;
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
// Adding 16 sets bit 4, which enables zlib to auto-detect the
|
||||||
|
// header.
|
||||||
|
if ( inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK )
|
||||||
|
{
|
||||||
|
free( raw_data );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( !done )
|
||||||
|
{
|
||||||
|
/* If our output buffer is too small */
|
||||||
|
if ( strm.total_out >= raw_data_size )
|
||||||
|
{
|
||||||
|
raw_data_size += half_length;
|
||||||
|
raw_data = reinterpret_cast<char *>( realloc( raw_data, raw_data_size ) );
|
||||||
|
if ( !raw_data ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.next_out = reinterpret_cast<Bytef *>( raw_data + strm.total_out );
|
||||||
|
strm.avail_out = static_cast<uInt>( static_cast<uLong>( raw_data_size ) - strm.total_out );
|
||||||
|
|
||||||
|
/* Inflate another chunk. */
|
||||||
|
int err = inflate( &strm, Z_SYNC_FLUSH );
|
||||||
|
if ( err == Z_STREAM_END )
|
||||||
|
done = true;
|
||||||
|
else if ( err != Z_OK )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( inflateEnd(&strm) != Z_OK )
|
||||||
|
{
|
||||||
|
free( raw_data );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_begin = raw_data;
|
||||||
|
m_size = static_cast<long>( strm.total_out );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
|
|
||||||
|
|
||||||
// Callback_Reader
|
// Callback_Reader
|
||||||
|
|
||||||
Callback_Reader::Callback_Reader( callback_t c, long size, void* d ) :
|
Callback_Reader::Callback_Reader( callback_t c, long size, void* d ) :
|
||||||
callback( c ),
|
callback( c ),
|
||||||
data( d )
|
data( d )
|
||||||
{
|
{
|
||||||
remain_ = size;
|
remain_ = max( 0l, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
long Callback_Reader::remain() const { return remain_; }
|
long Callback_Reader::remain() const { return remain_; }
|
||||||
|
@ -175,34 +286,82 @@ long Callback_Reader::read_avail( void* out, long count )
|
||||||
{
|
{
|
||||||
if ( count > remain_ )
|
if ( count > remain_ )
|
||||||
count = remain_;
|
count = remain_;
|
||||||
if ( Callback_Reader::read( out, count ) )
|
if ( count < 0 || Callback_Reader::read( out, count ) )
|
||||||
count = -1;
|
count = -1;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
blargg_err_t Callback_Reader::read( void* out, long count )
|
blargg_err_t Callback_Reader::read( void* out, long count )
|
||||||
{
|
{
|
||||||
|
RETURN_VALIDITY_CHECK( count >= 0 );
|
||||||
if ( count > remain_ )
|
if ( count > remain_ )
|
||||||
return eof_error;
|
return eof_error;
|
||||||
return callback( data, out, count );
|
return callback( data, out, (int) count );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Std_File_Reader
|
// Std_File_Reader
|
||||||
|
|
||||||
Std_File_Reader::Std_File_Reader() : file_( 0 ) { }
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
|
||||||
|
static const char* get_gzip_eof( const char* path, long* eof )
|
||||||
|
{
|
||||||
|
FILE* file = fopen( path, "rb" );
|
||||||
|
if ( !file )
|
||||||
|
return "Couldn't open file";
|
||||||
|
|
||||||
|
unsigned char buf [4];
|
||||||
|
bool found_eof = false;
|
||||||
|
if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B )
|
||||||
|
{
|
||||||
|
fseek( file, -4, SEEK_END );
|
||||||
|
if ( fread( buf, 4, 1, file ) > 0 ) {
|
||||||
|
*eof = get_le32( buf );
|
||||||
|
found_eof = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !found_eof )
|
||||||
|
{
|
||||||
|
fseek( file, 0, SEEK_END );
|
||||||
|
*eof = ftell( file );
|
||||||
|
}
|
||||||
|
const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : nullptr;
|
||||||
|
fclose( file );
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Std_File_Reader::Std_File_Reader() :
|
||||||
|
file_( nullptr )
|
||||||
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
, size_( 0 )
|
||||||
|
#endif
|
||||||
|
{ }
|
||||||
|
|
||||||
Std_File_Reader::~Std_File_Reader() { close(); }
|
Std_File_Reader::~Std_File_Reader() { close(); }
|
||||||
|
|
||||||
blargg_err_t Std_File_Reader::open( const char* path )
|
blargg_err_t Std_File_Reader::open( const char* path )
|
||||||
{
|
{
|
||||||
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
// zlib transparently handles uncompressed data if magic header
|
||||||
|
// not present but we still need to grab size
|
||||||
|
RETURN_ERR( get_gzip_eof( path, &size_ ) );
|
||||||
|
file_ = gzopen( path, "rb" );
|
||||||
|
#else
|
||||||
file_ = fopen( path, "rb" );
|
file_ = fopen( path, "rb" );
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( !file_ )
|
if ( !file_ )
|
||||||
return "Couldn't open file";
|
return "Couldn't open file";
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Std_File_Reader::size() const
|
long Std_File_Reader::size() const
|
||||||
{
|
{
|
||||||
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
if ( file_ )
|
||||||
|
return size_; // Set for both compressed and uncompressed modes
|
||||||
|
#endif
|
||||||
long pos = tell();
|
long pos = tell();
|
||||||
fseek( (FILE*) file_, 0, SEEK_END );
|
fseek( (FILE*) file_, 0, SEEK_END );
|
||||||
long result = tell();
|
long result = tell();
|
||||||
|
@ -212,24 +371,64 @@ long Std_File_Reader::size() const
|
||||||
|
|
||||||
long Std_File_Reader::read_avail( void* p, long s )
|
long Std_File_Reader::read_avail( void* p, long s )
|
||||||
{
|
{
|
||||||
return (long)fread( p, 1, s, (FILE*) file_ );
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
if ( file_ && s > 0 && s <= UINT_MAX ) {
|
||||||
|
return gzread( reinterpret_cast<gzFile>(file_),
|
||||||
|
p, static_cast<unsigned>(s) );
|
||||||
|
}
|
||||||
|
return 0l;
|
||||||
|
#else
|
||||||
|
const size_t readLength = static_cast<size_t>( max( 0l, s ) );
|
||||||
|
const auto result = fread( p, 1, readLength, reinterpret_cast<FILE*>(file_) );
|
||||||
|
return static_cast<long>( result );
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
}
|
}
|
||||||
|
|
||||||
blargg_err_t Std_File_Reader::read( void* p, long s )
|
blargg_err_t Std_File_Reader::read( void* p, long s )
|
||||||
{
|
{
|
||||||
if ( s == (long) fread( p, 1, s, (FILE*) file_ ) )
|
RETURN_VALIDITY_CHECK( s > 0 && s <= UINT_MAX );
|
||||||
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
if ( file_ )
|
||||||
|
{
|
||||||
|
const auto &gzfile = reinterpret_cast<gzFile>( file_ );
|
||||||
|
if ( s == gzread( gzfile, p, static_cast<unsigned>( s ) ) )
|
||||||
|
return nullptr;
|
||||||
|
if ( gzeof( gzfile ) )
|
||||||
|
return eof_error;
|
||||||
|
return "Couldn't read from GZ file";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
const auto &file = reinterpret_cast<FILE*>( file_ );
|
||||||
|
if ( s == static_cast<long>( fread( p, 1, static_cast<size_t>(s), file ) ) )
|
||||||
return 0;
|
return 0;
|
||||||
if ( feof( (FILE*) file_ ) )
|
if ( feof( file ) )
|
||||||
return eof_error;
|
return eof_error;
|
||||||
return "Couldn't read from file";
|
return "Couldn't read from file";
|
||||||
}
|
}
|
||||||
|
|
||||||
long Std_File_Reader::tell() const { return ftell( (FILE*) file_ ); }
|
long Std_File_Reader::tell() const
|
||||||
|
{
|
||||||
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
|
if ( file_ )
|
||||||
|
return gztell( reinterpret_cast<gzFile>( file_ ) );
|
||||||
|
#endif
|
||||||
|
return ftell( reinterpret_cast<FILE*>( file_ ) );
|
||||||
|
}
|
||||||
|
|
||||||
blargg_err_t Std_File_Reader::seek( long n )
|
blargg_err_t Std_File_Reader::seek( long n )
|
||||||
{
|
{
|
||||||
if ( !fseek( (FILE*) file_, n, SEEK_SET ) )
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
return 0;
|
if ( file_ )
|
||||||
|
{
|
||||||
|
if ( gzseek( reinterpret_cast<gzFile>( file_ ), n, SEEK_SET ) >= 0 )
|
||||||
|
return nullptr;
|
||||||
|
if ( n > size_ )
|
||||||
|
return eof_error;
|
||||||
|
return "Error seeking in GZ file";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ( !fseek( reinterpret_cast<FILE*>( file_ ), n, SEEK_SET ) )
|
||||||
|
return nullptr;
|
||||||
if ( n > size() )
|
if ( n > size() )
|
||||||
return eof_error;
|
return eof_error;
|
||||||
return "Error seeking in file";
|
return "Error seeking in file";
|
||||||
|
@ -239,79 +438,12 @@ void Std_File_Reader::close()
|
||||||
{
|
{
|
||||||
if ( file_ )
|
if ( file_ )
|
||||||
{
|
{
|
||||||
fclose( (FILE*) file_ );
|
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||||
file_ = 0;
|
gzclose( reinterpret_cast<gzFile>( file_ ) );
|
||||||
}
|
#else
|
||||||
}
|
fclose( reinterpret_cast<FILE*>( file_ ) );
|
||||||
|
|
||||||
// Gzip_File_Reader
|
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB_H
|
|
||||||
|
|
||||||
#include "zlib.h"
|
|
||||||
|
|
||||||
static const char* get_gzip_eof( const char* path, long* eof )
|
|
||||||
{
|
|
||||||
FILE* file = fopen( path, "rb" );
|
|
||||||
if ( !file )
|
|
||||||
return "Couldn't open file";
|
|
||||||
|
|
||||||
unsigned char buf [4];
|
|
||||||
if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B )
|
|
||||||
{
|
|
||||||
fseek( file, -4, SEEK_END );
|
|
||||||
fread( buf, 4, 1, file );
|
|
||||||
*eof = get_le32( buf );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fseek( file, 0, SEEK_END );
|
|
||||||
*eof = ftell( file );
|
|
||||||
}
|
|
||||||
const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : 0;
|
|
||||||
fclose( file );
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gzip_File_Reader::Gzip_File_Reader() : file_( 0 ) { }
|
|
||||||
|
|
||||||
Gzip_File_Reader::~Gzip_File_Reader() { close(); }
|
|
||||||
|
|
||||||
blargg_err_t Gzip_File_Reader::open( const char* path )
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
|
|
||||||
RETURN_ERR( get_gzip_eof( path, &size_ ) );
|
|
||||||
|
|
||||||
file_ = gzopen( path, "rb" );
|
|
||||||
if ( !file_ )
|
|
||||||
return "Couldn't open file";
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Gzip_File_Reader::size() const { return size_; }
|
|
||||||
|
|
||||||
long Gzip_File_Reader::read_avail( void* p, long s ) { return gzread( file_, p, s ); }
|
|
||||||
|
|
||||||
long Gzip_File_Reader::tell() const { return gztell( file_ ); }
|
|
||||||
|
|
||||||
blargg_err_t Gzip_File_Reader::seek( long n )
|
|
||||||
{
|
|
||||||
if ( gzseek( file_, n, SEEK_SET ) >= 0 )
|
|
||||||
return 0;
|
|
||||||
if ( n > size_ )
|
|
||||||
return eof_error;
|
|
||||||
return "Error seeking in file";
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gzip_File_Reader::close()
|
|
||||||
{
|
|
||||||
if ( file_ )
|
|
||||||
{
|
|
||||||
gzclose( file_ );
|
|
||||||
file_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
file_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
#include "blargg_common.h"
|
#include "blargg_common.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_ZLIB_H
|
||||||
|
#include <zlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Supports reading and finding out how many bytes are remaining
|
// Supports reading and finding out how many bytes are remaining
|
||||||
class Data_Reader {
|
class Data_Reader {
|
||||||
public:
|
public:
|
||||||
|
@ -65,13 +69,19 @@ public:
|
||||||
long tell() const;
|
long tell() const;
|
||||||
blargg_err_t seek( long );
|
blargg_err_t seek( long );
|
||||||
private:
|
private:
|
||||||
void* file_;
|
void* file_; // Either FILE* or zlib's gzFile
|
||||||
|
#if 0//[ZDOOM:unneeded] def HAVE_ZLIB_H
|
||||||
|
long size_; // TODO: Fix ABI compat
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
};
|
};
|
||||||
|
|
||||||
// Treats range of memory as a file
|
// Treats range of memory as a file
|
||||||
class Mem_File_Reader : public File_Reader {
|
class Mem_File_Reader : public File_Reader {
|
||||||
public:
|
public:
|
||||||
Mem_File_Reader( const void*, long size );
|
Mem_File_Reader( const void*, long size );
|
||||||
|
#ifdef HAVE_ZLIB_H
|
||||||
|
~Mem_File_Reader( );
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
long size() const;
|
long size() const;
|
||||||
|
@ -79,11 +89,19 @@ public:
|
||||||
long tell() const;
|
long tell() const;
|
||||||
blargg_err_t seek( long );
|
blargg_err_t seek( long );
|
||||||
private:
|
private:
|
||||||
const char* const begin;
|
#ifdef HAVE_ZLIB_H
|
||||||
const long size_;
|
bool gz_decompress();
|
||||||
long pos;
|
#endif /* HAVE_ZLIB_H */
|
||||||
|
|
||||||
|
const char* m_begin;
|
||||||
|
long m_size;
|
||||||
|
long m_pos;
|
||||||
|
#ifdef HAVE_ZLIB_H
|
||||||
|
bool m_ownedPtr = false; // set if we must free m_begin
|
||||||
|
#endif /* HAVE_ZLIB_H */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Makes it look like there are only count bytes remaining
|
// Makes it look like there are only count bytes remaining
|
||||||
class Subset_Reader : public Data_Reader {
|
class Subset_Reader : public Data_Reader {
|
||||||
public:
|
public:
|
||||||
|
@ -128,26 +146,4 @@ private:
|
||||||
long remain_;
|
long remain_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB_H
|
|
||||||
#include <zlib.h>
|
|
||||||
|
|
||||||
// Gzip compressed file reader
|
|
||||||
class Gzip_File_Reader : public File_Reader {
|
|
||||||
public:
|
|
||||||
blargg_err_t open( const char* path );
|
|
||||||
void close();
|
|
||||||
|
|
||||||
public:
|
|
||||||
Gzip_File_Reader();
|
|
||||||
~Gzip_File_Reader();
|
|
||||||
long size() const;
|
|
||||||
long read_avail( void*, long );
|
|
||||||
long tell() const;
|
|
||||||
blargg_err_t seek( long );
|
|
||||||
private:
|
|
||||||
gzFile file_;
|
|
||||||
long size_;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Dual_Resampler.h"
|
#include "Dual_Resampler.h"
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
#include "blargg_source.h"
|
#include "blargg_source.h"
|
||||||
|
|
||||||
//unsigned const resampler_extra = 256;
|
unsigned const resampler_extra = 256;
|
||||||
|
|
||||||
Dual_Resampler::Dual_Resampler() :
|
Dual_Resampler::Dual_Resampler() :
|
||||||
sample_buf_size(0),
|
sample_buf_size(0),
|
||||||
|
@ -69,9 +69,12 @@ void Dual_Resampler::play_frame_( Blip_Buffer& blip_buf, dsample_t* out )
|
||||||
|
|
||||||
resampler.write( new_count );
|
resampler.write( new_count );
|
||||||
|
|
||||||
|
#ifdef NDEBUG // Avoid warning when asserts are disabled
|
||||||
|
resampler.read( sample_buf.begin(), sample_buf_size );
|
||||||
|
#else
|
||||||
long count = resampler.read( sample_buf.begin(), sample_buf_size );
|
long count = resampler.read( sample_buf.begin(), sample_buf_size );
|
||||||
assert( count == (long) sample_buf_size );
|
assert( count == (long) sample_buf_size );
|
||||||
(void)count; // Silence warning in non-debug build
|
#endif
|
||||||
|
|
||||||
mix_samples( blip_buf, out );
|
mix_samples( blip_buf, out );
|
||||||
blip_buf.remove_samples( pair_count );
|
blip_buf.remove_samples( pair_count );
|
||||||
|
@ -119,17 +122,17 @@ void Dual_Resampler::mix_samples( Blip_Buffer& blip_buf, dsample_t* out )
|
||||||
{
|
{
|
||||||
int s = sn.read();
|
int s = sn.read();
|
||||||
blargg_long l = (blargg_long) in [0] * 2 + s;
|
blargg_long l = (blargg_long) in [0] * 2 + s;
|
||||||
if ( (BOOST::int16_t) l != l )
|
if ( (int16_t) l != l )
|
||||||
l = 0x7FFF - (l >> 24);
|
l = 0x7FFF - (l >> 24);
|
||||||
|
|
||||||
sn.next( bass );
|
sn.next( bass );
|
||||||
blargg_long r = (blargg_long) in [1] * 2 + s;
|
blargg_long r = (blargg_long) in [1] * 2 + s;
|
||||||
if ( (BOOST::int16_t) r != r )
|
if ( (int16_t) r != r )
|
||||||
r = 0x7FFF - (r >> 24);
|
r = 0x7FFF - (r >> 24);
|
||||||
|
|
||||||
in += 2;
|
in += 2;
|
||||||
out [0] = (dsample_t)l;
|
out [0] = l;
|
||||||
out [1] = (dsample_t)r;
|
out [1] = r;
|
||||||
out += 2;
|
out += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Combination of Fir_Resampler and Blip_Buffer mixing. Used by Sega FM emulators.
|
// Combination of Fir_Resampler and Blip_Buffer mixing. Used by Sega FM emulators.
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef DUAL_RESAMPLER_H
|
#ifndef DUAL_RESAMPLER_H
|
||||||
#define DUAL_RESAMPLER_H
|
#define DUAL_RESAMPLER_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Effects_Buffer.h"
|
#include "Effects_Buffer.h"
|
||||||
|
|
||||||
|
@ -63,28 +63,48 @@ void Effects_Buffer::set_depth( double d )
|
||||||
config( c );
|
config( c );
|
||||||
}
|
}
|
||||||
|
|
||||||
Effects_Buffer::Effects_Buffer( bool center_only ) : Multi_Buffer( 2 )
|
Effects_Buffer::Effects_Buffer( int num_voices, bool center_only )
|
||||||
|
: Multi_Buffer( 2*num_voices )
|
||||||
|
, max_voices(num_voices)
|
||||||
|
, bufs(max_voices * (center_only ? (max_buf_count - 4) : max_buf_count))
|
||||||
|
, chan_types(max_voices * chan_types_count)
|
||||||
|
, stereo_remain(0)
|
||||||
|
, effect_remain(0)
|
||||||
|
// TODO: Reorder buf_count to be initialized before bufs to factor out channel sizing
|
||||||
|
, buf_count(max_voices * (center_only ? (max_buf_count - 4) : max_buf_count))
|
||||||
|
, effects_enabled(false)
|
||||||
|
, reverb_buf(max_voices, std::vector<blip_sample_t>(reverb_size))
|
||||||
|
, echo_buf(max_voices, std::vector<blip_sample_t>(echo_size))
|
||||||
|
, reverb_pos(max_voices)
|
||||||
|
, echo_pos(max_voices)
|
||||||
{
|
{
|
||||||
buf_count = center_only ? max_buf_count - 4 : max_buf_count;
|
|
||||||
|
|
||||||
echo_pos = 0;
|
|
||||||
reverb_pos = 0;
|
|
||||||
|
|
||||||
stereo_remain = 0;
|
|
||||||
effect_remain = 0;
|
|
||||||
effects_enabled = false;
|
|
||||||
set_depth( 0 );
|
set_depth( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
Effects_Buffer::~Effects_Buffer() { }
|
Effects_Buffer::~Effects_Buffer()
|
||||||
|
{}
|
||||||
|
|
||||||
blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec )
|
blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec )
|
||||||
{
|
{
|
||||||
if ( !echo_buf.size() )
|
try
|
||||||
RETURN_ERR( echo_buf.resize( echo_size ) );
|
{
|
||||||
|
for(int i=0; i<max_voices; i++)
|
||||||
|
{
|
||||||
|
if ( !echo_buf[i].size() )
|
||||||
|
{
|
||||||
|
echo_buf[i].resize( echo_size );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !reverb_buf.size() )
|
if ( !reverb_buf[i].size() )
|
||||||
RETURN_ERR( reverb_buf.resize( reverb_size ) );
|
{
|
||||||
|
reverb_buf[i].resize( reverb_size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(std::bad_alloc& ba)
|
||||||
|
{
|
||||||
|
return "Out of memory";
|
||||||
|
}
|
||||||
|
|
||||||
for ( int i = 0; i < buf_count; i++ )
|
for ( int i = 0; i < buf_count; i++ )
|
||||||
RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
|
RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
|
||||||
|
@ -111,11 +131,15 @@ void Effects_Buffer::clear()
|
||||||
{
|
{
|
||||||
stereo_remain = 0;
|
stereo_remain = 0;
|
||||||
effect_remain = 0;
|
effect_remain = 0;
|
||||||
if ( echo_buf.size() )
|
|
||||||
memset( &echo_buf [0], 0, echo_size * sizeof echo_buf [0] );
|
|
||||||
|
|
||||||
if ( reverb_buf.size() )
|
for(int i=0; i<max_voices; i++)
|
||||||
memset( &reverb_buf [0], 0, reverb_size * sizeof reverb_buf [0] );
|
{
|
||||||
|
if ( echo_buf[i].size() )
|
||||||
|
memset( &echo_buf[i][0], 0, echo_size * sizeof echo_buf[i][0] );
|
||||||
|
|
||||||
|
if ( reverb_buf[i].size() )
|
||||||
|
memset( &reverb_buf[i][0], 0, reverb_size * sizeof reverb_buf[i][0] );
|
||||||
|
}
|
||||||
|
|
||||||
for ( int i = 0; i < buf_count; i++ )
|
for ( int i = 0; i < buf_count; i++ )
|
||||||
bufs [i].clear();
|
bufs [i].clear();
|
||||||
|
@ -135,10 +159,15 @@ void Effects_Buffer::config( const config_t& cfg )
|
||||||
channels_changed();
|
channels_changed();
|
||||||
|
|
||||||
// clear echo and reverb buffers
|
// clear echo and reverb buffers
|
||||||
if ( !config_.effects_enabled && cfg.effects_enabled && echo_buf.size() )
|
// ensure the echo/reverb buffers have already been allocated, so this method can be
|
||||||
|
// called before set_sample_rate is called
|
||||||
|
if ( !config_.effects_enabled && cfg.effects_enabled && echo_buf[0].size() )
|
||||||
{
|
{
|
||||||
memset( &echo_buf [0], 0, echo_size * sizeof echo_buf [0] );
|
for(int i=0; i<max_voices; i++)
|
||||||
memset( &reverb_buf [0], 0, reverb_size * sizeof reverb_buf [0] );
|
{
|
||||||
|
memset( &echo_buf[i][0], 0, echo_size * sizeof echo_buf[i][0] );
|
||||||
|
memset( &reverb_buf[i][0], 0, reverb_size * sizeof reverb_buf[i][0] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config_ = cfg;
|
config_ = cfg;
|
||||||
|
@ -170,73 +199,87 @@ void Effects_Buffer::config( const config_t& cfg )
|
||||||
chans.echo_delay_r = pin_range( echo_size - 1 - (echo_sample_delay + delay_offset),
|
chans.echo_delay_r = pin_range( echo_size - 1 - (echo_sample_delay + delay_offset),
|
||||||
echo_size - 1 );
|
echo_size - 1 );
|
||||||
|
|
||||||
chan_types [0].center = &bufs [0];
|
for(int i=0; i<max_voices; i++)
|
||||||
chan_types [0].left = &bufs [3];
|
{
|
||||||
chan_types [0].right = &bufs [4];
|
chan_types [i*chan_types_count+0].center = &bufs [i*max_buf_count+0];
|
||||||
|
chan_types [i*chan_types_count+0].left = &bufs [i*max_buf_count+3];
|
||||||
|
chan_types [i*chan_types_count+0].right = &bufs [i*max_buf_count+4];
|
||||||
|
|
||||||
chan_types [1].center = &bufs [1];
|
chan_types [i*chan_types_count+1].center = &bufs [i*max_buf_count+1];
|
||||||
chan_types [1].left = &bufs [3];
|
chan_types [i*chan_types_count+1].left = &bufs [i*max_buf_count+3];
|
||||||
chan_types [1].right = &bufs [4];
|
chan_types [i*chan_types_count+1].right = &bufs [i*max_buf_count+4];
|
||||||
|
|
||||||
chan_types [2].center = &bufs [2];
|
chan_types [i*chan_types_count+2].center = &bufs [i*max_buf_count+2];
|
||||||
chan_types [2].left = &bufs [5];
|
chan_types [i*chan_types_count+2].left = &bufs [i*max_buf_count+5];
|
||||||
chan_types [2].right = &bufs [6];
|
chan_types [i*chan_types_count+2].right = &bufs [i*max_buf_count+6];
|
||||||
|
}
|
||||||
assert( 2 < chan_types_count );
|
assert( 2 < chan_types_count );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// set up outputs
|
for(int i=0; i<max_voices; i++)
|
||||||
for ( unsigned i = 0; i < chan_types_count; i++ )
|
|
||||||
{
|
{
|
||||||
channel_t& c = chan_types [i];
|
// set up outputs
|
||||||
c.center = &bufs [0];
|
for ( int j = 0; j < chan_types_count; j++ )
|
||||||
c.left = &bufs [1];
|
{
|
||||||
c.right = &bufs [2];
|
channel_t& c = chan_types [i*chan_types_count+j];
|
||||||
|
c.center = &bufs [i*max_buf_count+0];
|
||||||
|
c.left = &bufs [i*max_buf_count+1];
|
||||||
|
c.right = &bufs [i*max_buf_count+2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( buf_count < max_buf_count )
|
if ( buf_count < max_buf_count ) // if center_only
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < chan_types_count; i++ )
|
for(int i=0; i<max_voices; i++)
|
||||||
{
|
{
|
||||||
channel_t& c = chan_types [i];
|
for ( int j = 0; j < chan_types_count; j++ )
|
||||||
|
{
|
||||||
|
channel_t& c = chan_types [i*chan_types_count+j];
|
||||||
c.left = c.center;
|
c.left = c.center;
|
||||||
c.right = c.center;
|
c.right = c.center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Effects_Buffer::channel_t Effects_Buffer::channel( int i, int type )
|
Effects_Buffer::channel_t Effects_Buffer::channel( int i, int type )
|
||||||
{
|
{
|
||||||
int out = 2;
|
int out = chan_types_count-1;
|
||||||
if ( !type )
|
if ( !type )
|
||||||
{
|
{
|
||||||
out = i % 5;
|
out = i % 5;
|
||||||
if ( out > 2 )
|
if ( out > chan_types_count-1 )
|
||||||
out = 2;
|
out = chan_types_count-1;
|
||||||
}
|
}
|
||||||
else if ( !(type & noise_type) && (type & type_index_mask) % 3 != 0 )
|
else if ( !(type & noise_type) && (type & type_index_mask) % 3 != 0 )
|
||||||
{
|
{
|
||||||
out = type & 1;
|
out = type & 1;
|
||||||
}
|
}
|
||||||
return chan_types [out];
|
return chan_types [(i%max_voices)*chan_types_count+out];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effects_Buffer::end_frame( blip_time_t clock_count )
|
void Effects_Buffer::end_frame( blip_time_t clock_count )
|
||||||
{
|
{
|
||||||
int bufs_used = 0;
|
int bufs_used = 0;
|
||||||
for ( int i = 0; i < buf_count; i++ )
|
|
||||||
{
|
|
||||||
bufs_used |= bufs [i].clear_modified() << i;
|
|
||||||
bufs [i].end_frame( clock_count );
|
|
||||||
}
|
|
||||||
|
|
||||||
int stereo_mask = (config_.effects_enabled ? 0x78 : 0x06);
|
int stereo_mask = (config_.effects_enabled ? 0x78 : 0x06);
|
||||||
if ( (bufs_used & stereo_mask) && buf_count == max_buf_count )
|
|
||||||
stereo_remain = bufs [0].samples_avail() + bufs [0].output_latency();
|
|
||||||
|
|
||||||
|
const int buf_count_per_voice = buf_count/max_voices;
|
||||||
|
for ( int v = 0; v < max_voices; v++ ) // foreach voice
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < buf_count_per_voice; i++) // foreach buffer of that voice
|
||||||
|
{
|
||||||
|
bufs_used |= bufs [v*buf_count_per_voice + i].clear_modified() << i;
|
||||||
|
bufs [v*buf_count_per_voice + i].end_frame( clock_count );
|
||||||
|
|
||||||
|
if ( (bufs_used & stereo_mask) && buf_count == max_voices*max_buf_count )
|
||||||
|
stereo_remain = max(stereo_remain, bufs [v*buf_count_per_voice + i].samples_avail() + bufs [v*buf_count_per_voice + i].output_latency());
|
||||||
if ( effects_enabled || config_.effects_enabled )
|
if ( effects_enabled || config_.effects_enabled )
|
||||||
effect_remain = bufs [0].samples_avail() + bufs [0].output_latency();
|
effect_remain = max(effect_remain, bufs [v*buf_count_per_voice + i].samples_avail() + bufs [v*buf_count_per_voice + i].output_latency());
|
||||||
|
}
|
||||||
|
bufs_used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
effects_enabled = config_.effects_enabled;
|
effects_enabled = config_.effects_enabled;
|
||||||
}
|
}
|
||||||
|
@ -248,15 +291,17 @@ long Effects_Buffer::samples_avail() const
|
||||||
|
|
||||||
long Effects_Buffer::read_samples( blip_sample_t* out, long total_samples )
|
long Effects_Buffer::read_samples( blip_sample_t* out, long total_samples )
|
||||||
{
|
{
|
||||||
require( total_samples % 2 == 0 ); // count must be even
|
const int n_channels = max_voices * 2;
|
||||||
|
const int buf_count_per_voice = buf_count/max_voices;
|
||||||
|
|
||||||
|
require( total_samples % n_channels == 0 ); // as many items needed to fill at least one frame
|
||||||
|
|
||||||
long remain = bufs [0].samples_avail();
|
long remain = bufs [0].samples_avail();
|
||||||
if ( remain > (total_samples >> 1) )
|
total_samples = remain = min( remain, total_samples/n_channels );
|
||||||
remain = (total_samples >> 1);
|
|
||||||
total_samples = remain;
|
|
||||||
while ( remain )
|
while ( remain )
|
||||||
{
|
{
|
||||||
int active_bufs = buf_count;
|
int active_bufs = buf_count_per_voice;
|
||||||
long count = remain;
|
long count = remain;
|
||||||
|
|
||||||
// optimizing mixing to skip any channels which had nothing added
|
// optimizing mixing to skip any channels which had nothing added
|
||||||
|
@ -286,7 +331,7 @@ long Effects_Buffer::read_samples( blip_sample_t* out, long total_samples )
|
||||||
active_bufs = 1;
|
active_bufs = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out += count * 2;
|
out += count * n_channels;
|
||||||
remain -= count;
|
remain -= count;
|
||||||
|
|
||||||
stereo_remain -= count;
|
stereo_remain -= count;
|
||||||
|
@ -297,23 +342,31 @@ long Effects_Buffer::read_samples( blip_sample_t* out, long total_samples )
|
||||||
if ( effect_remain < 0 )
|
if ( effect_remain < 0 )
|
||||||
effect_remain = 0;
|
effect_remain = 0;
|
||||||
|
|
||||||
for ( int i = 0; i < buf_count; i++ )
|
// skip the output from any buffers that didn't contribute to the sound output
|
||||||
|
// during this frame (e.g. if we only render mono then only the very first buf
|
||||||
|
// is 'active')
|
||||||
|
for ( int v = 0; v < max_voices; v++ ) // foreach voice
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < buf_count_per_voice; i++) // foreach buffer of that voice
|
||||||
{
|
{
|
||||||
if ( i < active_bufs )
|
if ( i < active_bufs )
|
||||||
bufs [i].remove_samples( count );
|
bufs [v*buf_count_per_voice + i].remove_samples( count );
|
||||||
else
|
else // keep time synchronized
|
||||||
bufs [i].remove_silence( count ); // keep time synchronized
|
bufs [v*buf_count_per_voice + i].remove_silence( count );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return total_samples * 2;
|
return total_samples * n_channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effects_Buffer::mix_mono( blip_sample_t* out_, blargg_long count )
|
void Effects_Buffer::mix_mono( blip_sample_t* out_, blargg_long count )
|
||||||
|
{
|
||||||
|
for(int i=0; i<max_voices; i++)
|
||||||
{
|
{
|
||||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||||
int const bass = BLIP_READER_BASS( bufs [0] );
|
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_BEGIN( c, bufs [0] );
|
BLIP_READER_BEGIN( c, bufs [i*max_buf_count+0] );
|
||||||
|
|
||||||
// unrolled loop
|
// unrolled loop
|
||||||
for ( blargg_long n = count >> 1; n; --n )
|
for ( blargg_long n = count >> 1; n; --n )
|
||||||
|
@ -324,41 +377,45 @@ void Effects_Buffer::mix_mono( blip_sample_t* out_, blargg_long count )
|
||||||
blargg_long cs1 = BLIP_READER_READ( c );
|
blargg_long cs1 = BLIP_READER_READ( c );
|
||||||
BLIP_READER_NEXT( c, bass );
|
BLIP_READER_NEXT( c, bass );
|
||||||
|
|
||||||
if ( (BOOST::int16_t) cs0 != cs0 )
|
if ( (int16_t) cs0 != cs0 )
|
||||||
cs0 = 0x7FFF - (cs0 >> 24);
|
cs0 = 0x7FFF - (cs0 >> 24);
|
||||||
((BOOST::uint32_t*) out) [0] = ((BOOST::uint16_t) cs0) | (cs0 << 16);
|
((uint32_t*) out) [i*2+0] = ((uint16_t) cs0) | (uint16_t(cs0) << 16);
|
||||||
|
|
||||||
if ( (BOOST::int16_t) cs1 != cs1 )
|
if ( (int16_t) cs1 != cs1 )
|
||||||
cs1 = 0x7FFF - (cs1 >> 24);
|
cs1 = 0x7FFF - (cs1 >> 24);
|
||||||
((BOOST::uint32_t*) out) [1] = ((BOOST::uint16_t) cs1) | (cs1 << 16);
|
((uint32_t*) out) [i*2+1] = ((uint16_t) cs1) | (uint16_t(cs1) << 16);
|
||||||
out += 4;
|
out += max_voices*4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( count & 1 )
|
if ( count & 1 )
|
||||||
{
|
{
|
||||||
int s = BLIP_READER_READ( c );
|
int s = BLIP_READER_READ( c );
|
||||||
BLIP_READER_NEXT( c, bass );
|
BLIP_READER_NEXT( c, bass );
|
||||||
out [0] = s;
|
out [i*2+0] = s;
|
||||||
out [1] = s;
|
out [i*2+1] = s;
|
||||||
if ( (BOOST::int16_t) s != s )
|
if ( (int16_t) s != s )
|
||||||
{
|
{
|
||||||
s = 0x7FFF - (s >> 24);
|
s = 0x7FFF - (s >> 24);
|
||||||
out [0] = s;
|
out [i*2+0] = s;
|
||||||
out [1] = s;
|
out [i*2+1] = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLIP_READER_END( c, bufs [0] );
|
BLIP_READER_END( c, bufs [i*max_buf_count+0] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effects_Buffer::mix_stereo( blip_sample_t* out_, blargg_long count )
|
void Effects_Buffer::mix_stereo( blip_sample_t* out_, blargg_long frames )
|
||||||
|
{
|
||||||
|
for(int i=0; i<max_voices; i++)
|
||||||
{
|
{
|
||||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||||
int const bass = BLIP_READER_BASS( bufs [0] );
|
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_BEGIN( c, bufs [0] );
|
BLIP_READER_BEGIN( c, bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_BEGIN( l, bufs [1] );
|
BLIP_READER_BEGIN( l, bufs [i*max_buf_count+1] );
|
||||||
BLIP_READER_BEGIN( r, bufs [2] );
|
BLIP_READER_BEGIN( r, bufs [i*max_buf_count+2] );
|
||||||
|
|
||||||
|
int count = frames;
|
||||||
while ( count-- )
|
while ( count-- )
|
||||||
{
|
{
|
||||||
int cs = BLIP_READER_READ( c );
|
int cs = BLIP_READER_READ( c );
|
||||||
|
@ -368,36 +425,41 @@ void Effects_Buffer::mix_stereo( blip_sample_t* out_, blargg_long count )
|
||||||
BLIP_READER_NEXT( l, bass );
|
BLIP_READER_NEXT( l, bass );
|
||||||
BLIP_READER_NEXT( r, bass );
|
BLIP_READER_NEXT( r, bass );
|
||||||
|
|
||||||
if ( (BOOST::int16_t) left != left )
|
if ( (int16_t) left != left )
|
||||||
left = 0x7FFF - (left >> 24);
|
left = 0x7FFF - (left >> 24);
|
||||||
|
|
||||||
out [0] = left;
|
if ( (int16_t) right != right )
|
||||||
out [1] = right;
|
right = 0x7FFF - (right >> 24);
|
||||||
|
|
||||||
out += 2;
|
out [i*2+0] = left;
|
||||||
|
out [i*2+1] = right;
|
||||||
|
|
||||||
|
out += max_voices*2;
|
||||||
|
|
||||||
if ( (BOOST::int16_t) right != right )
|
|
||||||
out [-1] = 0x7FFF - (right >> 24);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BLIP_READER_END( r, bufs [2] );
|
BLIP_READER_END( r, bufs [i*max_buf_count+2] );
|
||||||
BLIP_READER_END( l, bufs [1] );
|
BLIP_READER_END( l, bufs [i*max_buf_count+1] );
|
||||||
BLIP_READER_END( c, bufs [0] );
|
BLIP_READER_END( c, bufs [i*max_buf_count+0] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effects_Buffer::mix_mono_enhanced( blip_sample_t* out_, blargg_long count )
|
void Effects_Buffer::mix_mono_enhanced( blip_sample_t* out_, blargg_long frames )
|
||||||
|
{
|
||||||
|
for(int i=0; i<max_voices; i++)
|
||||||
{
|
{
|
||||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||||
int const bass = BLIP_READER_BASS( bufs [2] );
|
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+2] );
|
||||||
BLIP_READER_BEGIN( center, bufs [2] );
|
BLIP_READER_BEGIN( center, bufs [i*max_buf_count+2] );
|
||||||
BLIP_READER_BEGIN( sq1, bufs [0] );
|
BLIP_READER_BEGIN( sq1, bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_BEGIN( sq2, bufs [1] );
|
BLIP_READER_BEGIN( sq2, bufs [i*max_buf_count+1] );
|
||||||
|
|
||||||
blip_sample_t* const reverb_buf = this->reverb_buf.begin();
|
blip_sample_t* const reverb_buf = &this->reverb_buf[i][0];
|
||||||
blip_sample_t* const echo_buf = this->echo_buf.begin();
|
blip_sample_t* const echo_buf = &this->echo_buf[i][0];
|
||||||
int echo_pos = this->echo_pos;
|
int echo_pos = this->echo_pos[i];
|
||||||
int reverb_pos = this->reverb_pos;
|
int reverb_pos = this->reverb_pos[i];
|
||||||
|
|
||||||
|
int count = frames;
|
||||||
while ( count-- )
|
while ( count-- )
|
||||||
{
|
{
|
||||||
int sum1_s = BLIP_READER_READ( sq1 );
|
int sum1_s = BLIP_READER_READ( sq1 );
|
||||||
|
@ -430,42 +492,45 @@ void Effects_Buffer::mix_mono_enhanced( blip_sample_t* out_, blargg_long count )
|
||||||
echo_buf [echo_pos] = sum3_s;
|
echo_buf [echo_pos] = sum3_s;
|
||||||
echo_pos = (echo_pos + 1) & echo_mask;
|
echo_pos = (echo_pos + 1) & echo_mask;
|
||||||
|
|
||||||
if ( (BOOST::int16_t) left != left )
|
if ( (int16_t) left != left )
|
||||||
left = 0x7FFF - (left >> 24);
|
left = 0x7FFF - (left >> 24);
|
||||||
|
|
||||||
out [0] = left;
|
if ( (int16_t) right != right )
|
||||||
out [1] = right;
|
right = 0x7FFF - (right >> 24);
|
||||||
|
|
||||||
out += 2;
|
out [i*2+0] = left;
|
||||||
|
out [i*2+1] = right;
|
||||||
if ( (BOOST::int16_t) right != right )
|
out += max_voices*2;
|
||||||
out [-1] = 0x7FFF - (right >> 24);
|
|
||||||
}
|
}
|
||||||
this->reverb_pos = reverb_pos;
|
this->reverb_pos[i] = reverb_pos;
|
||||||
this->echo_pos = echo_pos;
|
this->echo_pos[i] = echo_pos;
|
||||||
|
|
||||||
BLIP_READER_END( sq1, bufs [0] );
|
BLIP_READER_END( sq1, bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_END( sq2, bufs [1] );
|
BLIP_READER_END( sq2, bufs [i*max_buf_count+1] );
|
||||||
BLIP_READER_END( center, bufs [2] );
|
BLIP_READER_END( center, bufs [i*max_buf_count+2] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effects_Buffer::mix_enhanced( blip_sample_t* out_, blargg_long count )
|
void Effects_Buffer::mix_enhanced( blip_sample_t* out_, blargg_long frames )
|
||||||
|
{
|
||||||
|
for(int i=0; i<max_voices; i++)
|
||||||
{
|
{
|
||||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||||
int const bass = BLIP_READER_BASS( bufs [2] );
|
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+2] );
|
||||||
BLIP_READER_BEGIN( center, bufs [2] );
|
BLIP_READER_BEGIN( center, bufs [i*max_buf_count+2] );
|
||||||
BLIP_READER_BEGIN( l1, bufs [3] );
|
BLIP_READER_BEGIN( l1, bufs [i*max_buf_count+3] );
|
||||||
BLIP_READER_BEGIN( r1, bufs [4] );
|
BLIP_READER_BEGIN( r1, bufs [i*max_buf_count+4] );
|
||||||
BLIP_READER_BEGIN( l2, bufs [5] );
|
BLIP_READER_BEGIN( l2, bufs [i*max_buf_count+5] );
|
||||||
BLIP_READER_BEGIN( r2, bufs [6] );
|
BLIP_READER_BEGIN( r2, bufs [i*max_buf_count+6] );
|
||||||
BLIP_READER_BEGIN( sq1, bufs [0] );
|
BLIP_READER_BEGIN( sq1, bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_BEGIN( sq2, bufs [1] );
|
BLIP_READER_BEGIN( sq2, bufs [i*max_buf_count+1] );
|
||||||
|
|
||||||
blip_sample_t* const reverb_buf = this->reverb_buf.begin();
|
blip_sample_t* const reverb_buf = &this->reverb_buf[i][0];
|
||||||
blip_sample_t* const echo_buf = this->echo_buf.begin();
|
blip_sample_t* const echo_buf = &this->echo_buf[i][0];
|
||||||
int echo_pos = this->echo_pos;
|
int echo_pos = this->echo_pos[i];
|
||||||
int reverb_pos = this->reverb_pos;
|
int reverb_pos = this->reverb_pos[i];
|
||||||
|
|
||||||
|
int count = frames;
|
||||||
while ( count-- )
|
while ( count-- )
|
||||||
{
|
{
|
||||||
int sum1_s = BLIP_READER_READ( sq1 );
|
int sum1_s = BLIP_READER_READ( sq1 );
|
||||||
|
@ -504,26 +569,27 @@ void Effects_Buffer::mix_enhanced( blip_sample_t* out_, blargg_long count )
|
||||||
echo_buf [echo_pos] = sum3_s;
|
echo_buf [echo_pos] = sum3_s;
|
||||||
echo_pos = (echo_pos + 1) & echo_mask;
|
echo_pos = (echo_pos + 1) & echo_mask;
|
||||||
|
|
||||||
if ( (BOOST::int16_t) left != left )
|
if ( (int16_t) left != left )
|
||||||
left = 0x7FFF - (left >> 24);
|
left = 0x7FFF - (left >> 24);
|
||||||
|
|
||||||
out [0] = left;
|
if ( (int16_t) right != right )
|
||||||
out [1] = right;
|
right = 0x7FFF - (right >> 24);
|
||||||
|
|
||||||
out += 2;
|
out [i*2+0] = left;
|
||||||
|
out [i*2+1] = right;
|
||||||
|
|
||||||
if ( (BOOST::int16_t) right != right )
|
out += max_voices*2;
|
||||||
out [-1] = 0x7FFF - (right >> 24);
|
|
||||||
}
|
}
|
||||||
this->reverb_pos = reverb_pos;
|
this->reverb_pos[i] = reverb_pos;
|
||||||
this->echo_pos = echo_pos;
|
this->echo_pos[i] = echo_pos;
|
||||||
|
|
||||||
BLIP_READER_END( l1, bufs [3] );
|
BLIP_READER_END( l1, bufs [i*max_buf_count+3] );
|
||||||
BLIP_READER_END( r1, bufs [4] );
|
BLIP_READER_END( r1, bufs [i*max_buf_count+4] );
|
||||||
BLIP_READER_END( l2, bufs [5] );
|
BLIP_READER_END( l2, bufs [i*max_buf_count+5] );
|
||||||
BLIP_READER_END( r2, bufs [6] );
|
BLIP_READER_END( r2, bufs [i*max_buf_count+6] );
|
||||||
BLIP_READER_END( sq1, bufs [0] );
|
BLIP_READER_END( sq1, bufs [i*max_buf_count+0] );
|
||||||
BLIP_READER_END( sq2, bufs [1] );
|
BLIP_READER_END( sq2, bufs [i*max_buf_count+1] );
|
||||||
BLIP_READER_END( center, bufs [2] );
|
BLIP_READER_END( center, bufs [i*max_buf_count+2] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// Multi-channel effects buffer with panning, echo and reverb
|
// Multi-channel effects buffer with panning, echo and reverb
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef EFFECTS_BUFFER_H
|
#ifndef EFFECTS_BUFFER_H
|
||||||
#define EFFECTS_BUFFER_H
|
#define EFFECTS_BUFFER_H
|
||||||
|
|
||||||
#include "Multi_Buffer.h"
|
#include "Multi_Buffer.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// Effects_Buffer uses several buffers and outputs stereo sample pairs.
|
// Effects_Buffer uses several buffers and outputs stereo sample pairs.
|
||||||
class Effects_Buffer : public Multi_Buffer {
|
class Effects_Buffer : public Multi_Buffer {
|
||||||
public:
|
public:
|
||||||
|
// nVoices indicates the number of voices for which buffers will be allocated
|
||||||
|
// to make Effects_Buffer work as "mix everything to one", nVoices will be 1
|
||||||
// If center_only is true, only center buffers are created and
|
// If center_only is true, only center buffers are created and
|
||||||
// less memory is used.
|
// less memory is used.
|
||||||
Effects_Buffer( bool center_only = false );
|
Effects_Buffer( int nVoices = 1, bool center_only = false );
|
||||||
|
|
||||||
// Channel Effect Center Pan
|
// Channel Effect Center Pan
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
|
@ -50,21 +54,21 @@ public:
|
||||||
long samples_avail() const;
|
long samples_avail() const;
|
||||||
private:
|
private:
|
||||||
typedef long fixed_t;
|
typedef long fixed_t;
|
||||||
|
int max_voices;
|
||||||
enum { max_buf_count = 7 };
|
enum { max_buf_count = 7 };
|
||||||
Blip_Buffer bufs [max_buf_count];
|
std::vector<Blip_Buffer> bufs;
|
||||||
enum { chan_types_count = 3 };
|
enum { chan_types_count = 3 };
|
||||||
channel_t chan_types [3];
|
std::vector<channel_t> chan_types;
|
||||||
config_t config_;
|
config_t config_;
|
||||||
long stereo_remain;
|
long stereo_remain;
|
||||||
long effect_remain;
|
long effect_remain;
|
||||||
int buf_count;
|
int buf_count;
|
||||||
bool effects_enabled;
|
bool effects_enabled;
|
||||||
|
|
||||||
blargg_vector<blip_sample_t> reverb_buf;
|
std::vector<std::vector<blip_sample_t> > reverb_buf;
|
||||||
blargg_vector<blip_sample_t> echo_buf;
|
std::vector<std::vector<blip_sample_t> > echo_buf;
|
||||||
int reverb_pos;
|
std::vector<int> reverb_pos;
|
||||||
int echo_pos;
|
std::vector<int> echo_pos;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
fixed_t pan_1_levels [2];
|
fixed_t pan_1_levels [2];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Fir_Resampler.h"
|
#include "Fir_Resampler.h"
|
||||||
|
|
||||||
|
@ -23,10 +23,6 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
#undef PI
|
#undef PI
|
||||||
#define PI 3.1415926535897932384626433832795029
|
#define PI 3.1415926535897932384626433832795029
|
||||||
|
|
||||||
#if _MSC_VER >= 1911
|
|
||||||
#pragma float_control(precise, on, push)
|
|
||||||
#endif // _MSC_VER >= 1911
|
|
||||||
|
|
||||||
static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale,
|
static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale,
|
||||||
int count, short* out )
|
int count, short* out )
|
||||||
{
|
{
|
||||||
|
@ -56,10 +52,6 @@ static void gen_sinc( double rolloff, int width, double offset, double spacing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _MSC_VER >= 1911
|
|
||||||
#pragma float_control(pop)
|
|
||||||
#endif // _MSC_VER >= 1911
|
|
||||||
|
|
||||||
Fir_Resampler_::Fir_Resampler_( int width, sample_t* impulses_ ) :
|
Fir_Resampler_::Fir_Resampler_( int width, sample_t* impulses_ ) :
|
||||||
width_( width ),
|
width_( width ),
|
||||||
write_offset( width * stereo - stereo ),
|
write_offset( width * stereo - stereo ),
|
||||||
|
@ -164,7 +156,7 @@ int Fir_Resampler_::input_needed( blargg_long output_count ) const
|
||||||
output_count -= 2;
|
output_count -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
long input_extra = (long)(input_count - (write_pos - &buf [(width_ - 1) * stereo]));
|
long input_extra = input_count - (write_pos - &buf [(width_ - 1) * stereo]);
|
||||||
if ( input_extra < 0 )
|
if ( input_extra < 0 )
|
||||||
input_extra = 0;
|
input_extra = 0;
|
||||||
return input_extra;
|
return input_extra;
|
||||||
|
@ -194,8 +186,8 @@ int Fir_Resampler_::avail_( blargg_long input_count ) const
|
||||||
|
|
||||||
int Fir_Resampler_::skip_input( long count )
|
int Fir_Resampler_::skip_input( long count )
|
||||||
{
|
{
|
||||||
int remain = int(write_pos - buf.begin());
|
int remain = write_pos - buf.begin();
|
||||||
int max_count = int(remain - width_ * stereo);
|
int max_count = remain - width_ * stereo;
|
||||||
if ( count > max_count )
|
if ( count > max_count )
|
||||||
count = max_count;
|
count = max_count;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Finite impulse response (FIR) resampler with adjustable FIR size
|
// Finite impulse response (FIR) resampler with adjustable FIR size
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef FIR_RESAMPLER_H
|
#ifndef FIR_RESAMPLER_H
|
||||||
#define FIR_RESAMPLER_H
|
#define FIR_RESAMPLER_H
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public:
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// Number of input samples that can be written
|
// Number of input samples that can be written
|
||||||
int max_write() const { return int(buf.end() - write_pos); }
|
int max_write() const { return buf.end() - write_pos; }
|
||||||
|
|
||||||
// Pointer to place to write input samples
|
// Pointer to place to write input samples
|
||||||
sample_t* buffer() { return write_pos; }
|
sample_t* buffer() { return write_pos; }
|
||||||
|
@ -40,7 +40,7 @@ public:
|
||||||
void write( long count );
|
void write( long count );
|
||||||
|
|
||||||
// Number of input samples in buffer
|
// Number of input samples in buffer
|
||||||
int written() const { return int(write_pos - &buf [write_offset]); }
|
int written() const { return write_pos - &buf [write_offset]; }
|
||||||
|
|
||||||
// Skip 'count' input samples. Returns number of samples actually skipped.
|
// Skip 'count' input samples. Returns number of samples actually skipped.
|
||||||
int skip_input( long count );
|
int skip_input( long count );
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
int input_needed( blargg_long count ) const;
|
int input_needed( blargg_long count ) const;
|
||||||
|
|
||||||
// Number of output samples available
|
// Number of output samples available
|
||||||
int avail() const { return avail_( blargg_long(write_pos - &buf [width_ * stereo] )); }
|
int avail() const { return avail_( write_pos - &buf [width_ * stereo] ); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Fir_Resampler_();
|
~Fir_Resampler_();
|
||||||
|
@ -161,11 +161,11 @@ int Fir_Resampler<width>::read( sample_t* out_begin, blargg_long count )
|
||||||
|
|
||||||
imp_phase = res - remain;
|
imp_phase = res - remain;
|
||||||
|
|
||||||
int left = int(write_pos - in);
|
int left = write_pos - in;
|
||||||
write_pos = &buf [left];
|
write_pos = &buf [left];
|
||||||
memmove( buf.begin(), in, left * sizeof *in );
|
memmove( buf.begin(), in, left * sizeof *in );
|
||||||
|
|
||||||
return int(out - out_begin);
|
return out - out_begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -123,7 +123,7 @@ void Gb_Apu::reset()
|
||||||
0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
|
0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
|
||||||
0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
|
0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
|
||||||
};
|
};
|
||||||
memcpy( wave.wave, initial_wave, sizeof wave.wave );
|
memcpy( wave.wave, initial_wave, sizeof initial_wave );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gb_Apu::run_until( blip_time_t end_time )
|
void Gb_Apu::run_until( blip_time_t end_time )
|
||||||
|
|
|
@ -68,7 +68,7 @@ private:
|
||||||
Gb_Square square2;
|
Gb_Square square2;
|
||||||
Gb_Wave wave;
|
Gb_Wave wave;
|
||||||
Gb_Noise noise;
|
Gb_Noise noise;
|
||||||
BOOST::uint8_t regs [register_count];
|
uint8_t regs [register_count];
|
||||||
Gb_Square::Synth square_synth; // used by squares
|
Gb_Square::Synth square_synth; // used by squares
|
||||||
Gb_Wave::Synth other_synth; // used by wave and noise
|
Gb_Wave::Synth other_synth; // used by wave and noise
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Gb_Cpu.h"
|
#include "Gb_Cpu.h"
|
||||||
|
|
||||||
|
@ -89,12 +89,6 @@ unsigned const n_flag = 0x40;
|
||||||
unsigned const h_flag = 0x20;
|
unsigned const h_flag = 0x20;
|
||||||
unsigned const c_flag = 0x10;
|
unsigned const c_flag = 0x10;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// warning C4101: 'blargg_failed_' : unreferenced local variable
|
|
||||||
// -- produced by the BOOST_STATIC_ASSERT line below
|
|
||||||
#pragma warning(disable:4101)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool Gb_Cpu::run( blargg_long cycle_count )
|
bool Gb_Cpu::run( blargg_long cycle_count )
|
||||||
{
|
{
|
||||||
state_.remain = blargg_ulong (cycle_count + clocks_per_instr) / clocks_per_instr;
|
state_.remain = blargg_ulong (cycle_count + clocks_per_instr) / clocks_per_instr;
|
||||||
|
@ -102,8 +96,6 @@ bool Gb_Cpu::run( blargg_long cycle_count )
|
||||||
this->state = &s;
|
this->state = &s;
|
||||||
memcpy( &s, &this->state_, sizeof s );
|
memcpy( &s, &this->state_, sizeof s );
|
||||||
|
|
||||||
typedef BOOST::uint16_t uint16_t;
|
|
||||||
|
|
||||||
#if BLARGG_BIG_ENDIAN
|
#if BLARGG_BIG_ENDIAN
|
||||||
#define R8( n ) (r8_ [n])
|
#define R8( n ) (r8_ [n])
|
||||||
#elif BLARGG_LITTLE_ENDIAN
|
#elif BLARGG_LITTLE_ENDIAN
|
||||||
|
@ -116,11 +108,11 @@ bool Gb_Cpu::run( blargg_long cycle_count )
|
||||||
core_regs_t rg; // individual registers
|
core_regs_t rg; // individual registers
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
BOOST::uint16_t bc, de, hl, unused; // pairs
|
uint16_t bc, de, hl, unused; // pairs
|
||||||
} rp;
|
} rp;
|
||||||
|
|
||||||
uint8_t r8_ [8]; // indexed registers (use R8 macro due to endian dependence)
|
uint8_t r8_ [8]; // indexed registers (use R8 macro due to endian dependence)
|
||||||
BOOST::uint16_t r16 [4]; // indexed pairs
|
uint16_t r16 [4]; // indexed pairs
|
||||||
};
|
};
|
||||||
BOOST_STATIC_ASSERT( sizeof rg == 8 && sizeof rp == 8 );
|
BOOST_STATIC_ASSERT( sizeof rg == 8 && sizeof rp == 8 );
|
||||||
|
|
||||||
|
@ -168,7 +160,7 @@ loop:
|
||||||
#define BRANCH( cond )\
|
#define BRANCH( cond )\
|
||||||
{\
|
{\
|
||||||
pc++;\
|
pc++;\
|
||||||
int offset = (BOOST::int8_t) data;\
|
int offset = (int8_t) data;\
|
||||||
if ( !(cond) ) goto loop;\
|
if ( !(cond) ) goto loop;\
|
||||||
pc = uint16_t (pc + offset);\
|
pc = uint16_t (pc + offset);\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
|
@ -688,7 +680,7 @@ loop:
|
||||||
unsigned prev;
|
unsigned prev;
|
||||||
|
|
||||||
case 0xF8: // LD HL,SP+imm
|
case 0xF8: // LD HL,SP+imm
|
||||||
temp = BOOST::int8_t (data); // sign-extend to 16 bits
|
temp = int8_t (data); // sign-extend to 16 bits
|
||||||
pc++;
|
pc++;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
temp += sp;
|
temp += sp;
|
||||||
|
@ -696,7 +688,7 @@ loop:
|
||||||
goto add_16_hl;
|
goto add_16_hl;
|
||||||
|
|
||||||
case 0xE8: // ADD SP,IMM
|
case 0xE8: // ADD SP,IMM
|
||||||
temp = BOOST::int8_t (data); // sign-extend to 16 bits
|
temp = int8_t (data); // sign-extend to 16 bits
|
||||||
pc++;
|
pc++;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
temp += sp;
|
temp += sp;
|
||||||
|
@ -717,7 +709,7 @@ loop:
|
||||||
temp += prev;
|
temp += prev;
|
||||||
flags &= z_flag;
|
flags &= z_flag;
|
||||||
add_16_hl:
|
add_16_hl:
|
||||||
rp.hl = (uint16_t)temp;
|
rp.hl = temp;
|
||||||
add_16_comm:
|
add_16_comm:
|
||||||
flags |= (temp >> 12) & c_flag;
|
flags |= (temp >> 12) & c_flag;
|
||||||
flags |= (((temp & 0x0FFF) - (prev & 0x0FFF)) >> 7) & h_flag;
|
flags |= (((temp & 0x0FFF) - (prev & 0x0FFF)) >> 7) & h_flag;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Nintendo Game Boy CPU emulator
|
// Nintendo Game Boy CPU emulator
|
||||||
// Treats every instruction as taking 4 cycles
|
// Treats every instruction as taking 4 cycles
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef GB_CPU_H
|
#ifndef GB_CPU_H
|
||||||
#define GB_CPU_H
|
#define GB_CPU_H
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@ typedef unsigned gb_addr_t; // 16-bit CPU address
|
||||||
class Gb_Cpu {
|
class Gb_Cpu {
|
||||||
enum { clocks_per_instr = 4 };
|
enum { clocks_per_instr = 4 };
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
// Clear registers and map all pages to unmapped
|
// Clear registers and map all pages to unmapped
|
||||||
void reset( void* unmapped = 0 );
|
void reset( void* unmapped = 0 );
|
||||||
|
|
||||||
|
@ -39,7 +37,7 @@ public:
|
||||||
|
|
||||||
struct registers_t : core_regs_t {
|
struct registers_t : core_regs_t {
|
||||||
long pc; // more than 16 bits to allow overflow detection
|
long pc; // more than 16 bits to allow overflow detection
|
||||||
BOOST::uint16_t sp;
|
uint16_t sp;
|
||||||
};
|
};
|
||||||
registers_t r;
|
registers_t r;
|
||||||
|
|
||||||
|
@ -81,7 +79,7 @@ private:
|
||||||
void set_code_page( int, uint8_t* );
|
void set_code_page( int, uint8_t* );
|
||||||
};
|
};
|
||||||
|
|
||||||
inline BOOST::uint8_t* Gb_Cpu::get_code( gb_addr_t addr )
|
inline uint8_t* Gb_Cpu::get_code( gb_addr_t addr )
|
||||||
{
|
{
|
||||||
return state->code_map [addr >> page_shift] + addr
|
return state->code_map [addr >> page_shift] + addr
|
||||||
#if !BLARGG_NONPORTABLE
|
#if !BLARGG_NONPORTABLE
|
||||||
|
|
|
@ -15,7 +15,7 @@ struct Gb_Osc
|
||||||
Blip_Buffer* outputs [4]; // NULL, right, left, center
|
Blip_Buffer* outputs [4]; // NULL, right, left, center
|
||||||
Blip_Buffer* output;
|
Blip_Buffer* output;
|
||||||
int output_select;
|
int output_select;
|
||||||
BOOST::uint8_t* regs; // osc's 5 registers
|
uint8_t* regs; // osc's 5 registers
|
||||||
|
|
||||||
int delay;
|
int delay;
|
||||||
int last_amp;
|
int last_amp;
|
||||||
|
@ -68,7 +68,7 @@ struct Gb_Wave : Gb_Osc
|
||||||
Synth const* synth;
|
Synth const* synth;
|
||||||
int wave_pos;
|
int wave_pos;
|
||||||
enum { wave_size = 32 };
|
enum { wave_size = 32 };
|
||||||
BOOST::uint8_t wave [wave_size];
|
uint8_t wave [wave_size];
|
||||||
|
|
||||||
void write_register( int, int );
|
void write_register( int, int );
|
||||||
void run( blip_time_t, blip_time_t, int playing );
|
void run( blip_time_t, blip_time_t, int playing );
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Gbs_Emu.h"
|
#include "Gbs_Emu.h"
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; }
|
||||||
static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; }
|
static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_gbs_type_ = { "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 };
|
static gme_type_t_ const gme_gbs_type_ = { "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 };
|
||||||
gme_type_t const gme_gbs_type = &gme_gbs_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_gbs_type = &gme_gbs_type_;
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ void Gbs_Emu::update_timer()
|
||||||
play_period = blip_time_t (play_period / tempo());
|
play_period = blip_time_t (play_period / tempo());
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOST::uint8_t const sound_data [Gb_Apu::register_count] = {
|
static uint8_t const sound_data [Gb_Apu::register_count] = {
|
||||||
0x80, 0xBF, 0x00, 0x00, 0xBF, // square 1
|
0x80, 0xBF, 0x00, 0x00, 0xBF, // square 1
|
||||||
0x00, 0x3F, 0x00, 0x00, 0xBF, // square 2
|
0x00, 0x3F, 0x00, 0x00, 0xBF, // square 2
|
||||||
0x7F, 0xFF, 0x9F, 0x00, 0xBF, // wave
|
0x7F, 0xFF, 0x9F, 0x00, 0xBF, // wave
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Nintendo Game Boy GBS music file emulator
|
// Nintendo Game Boy GBS music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef GBS_EMU_H
|
#ifndef GBS_EMU_H
|
||||||
#define GBS_EMU_H
|
#define GBS_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Gme_File.h"
|
#include "Gme_File.h"
|
||||||
|
|
||||||
|
@ -60,8 +60,8 @@ blargg_err_t Gme_File::load_mem_( byte const* data, long size )
|
||||||
blargg_err_t Gme_File::load_( Data_Reader& in )
|
blargg_err_t Gme_File::load_( Data_Reader& in )
|
||||||
{
|
{
|
||||||
RETURN_ERR( file_data.resize( in.remain() ) );
|
RETURN_ERR( file_data.resize( in.remain() ) );
|
||||||
RETURN_ERR( in.read( file_data.begin(), (long)file_data.size() ) );
|
RETURN_ERR( in.read( file_data.begin(), file_data.size() ) );
|
||||||
return load_mem_( file_data.begin(), (long)file_data.size() );
|
return load_mem_( file_data.begin(), file_data.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// public load functions call this at beginning
|
// public load functions call this at beginning
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Common interface to game music file loading and information
|
// Common interface to game music file loading and information
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef GME_FILE_H
|
#ifndef GME_FILE_H
|
||||||
#define GME_FILE_H
|
#define GME_FILE_H
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ public:
|
||||||
Gme_File();
|
Gme_File();
|
||||||
virtual ~Gme_File();
|
virtual ~Gme_File();
|
||||||
BLARGG_DISABLE_NOTHROW
|
BLARGG_DISABLE_NOTHROW
|
||||||
typedef BOOST::uint8_t byte;
|
typedef uint8_t byte;
|
||||||
protected:
|
protected:
|
||||||
// Services
|
// Services
|
||||||
void set_track_count( int n ) { track_count_ = raw_track_count_ = n; }
|
void set_track_count( int n ) { track_count_ = raw_track_count_ = n; }
|
||||||
|
@ -154,11 +154,7 @@ Music_Emu* gme_new_( Music_Emu*, long sample_rate );
|
||||||
{ Gme_File::copy_field_( out->name, in.name, sizeof in.name ); }
|
{ Gme_File::copy_field_( out->name, in.name, sizeof in.name ); }
|
||||||
|
|
||||||
#ifndef GME_FILE_READER
|
#ifndef GME_FILE_READER
|
||||||
#ifdef HAVE_ZLIB_H
|
|
||||||
#define GME_FILE_READER Gzip_File_Reader
|
|
||||||
#else
|
|
||||||
#define GME_FILE_READER Std_File_Reader
|
#define GME_FILE_READER Std_File_Reader
|
||||||
#endif
|
|
||||||
#elif defined (GME_FILE_READER_INCLUDE)
|
#elif defined (GME_FILE_READER_INCLUDE)
|
||||||
#include GME_FILE_READER_INCLUDE
|
#include GME_FILE_READER_INCLUDE
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Gym_Emu.h"
|
#include "Gym_Emu.h"
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ static Music_Emu* new_gym_emu () { return BLARGG_NEW Gym_Emu ; }
|
||||||
static Music_Emu* new_gym_file() { return BLARGG_NEW Gym_File; }
|
static Music_Emu* new_gym_file() { return BLARGG_NEW Gym_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_gym_type_ = { "Sega Genesis", 1, &new_gym_emu, &new_gym_file, "GYM", 0 };
|
static gme_type_t_ const gme_gym_type_ = { "Sega Genesis", 1, &new_gym_emu, &new_gym_file, "GYM", 0 };
|
||||||
gme_type_t const gme_gym_type = &gme_gym_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_gym_type = &gme_gym_type_;
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Sega Genesis/Mega Drive GYM music file emulator
|
// Sega Genesis/Mega Drive GYM music file emulator
|
||||||
// Includes with PCM timing recovery to improve sample quality.
|
// Includes with PCM timing recovery to improve sample quality.
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef GYM_EMU_H
|
#ifndef GYM_EMU_H
|
||||||
#define GYM_EMU_H
|
#define GYM_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Hes_Apu.h"
|
#include "Hes_Apu.h"
|
||||||
|
|
||||||
|
@ -106,10 +106,10 @@ void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time )
|
||||||
unsigned noise_lfsr = this->noise_lfsr;
|
unsigned noise_lfsr = this->noise_lfsr;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int new_dac = 0x1F & (unsigned)-(int)(noise_lfsr >> 1 & 1);
|
int new_dac = 0x1F & -(noise_lfsr >> 1 & 1);
|
||||||
// Implemented using "Galios configuration"
|
// Implemented using "Galios configuration"
|
||||||
// TODO: find correct LFSR algorithm
|
// TODO: find correct LFSR algorithm
|
||||||
noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & (unsigned)-(int)(noise_lfsr & 1));
|
noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1));
|
||||||
//noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
|
//noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
|
||||||
int delta = new_dac - dac;
|
int delta = new_dac - dac;
|
||||||
if ( delta )
|
if ( delta )
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Turbo Grafx 16 (PC Engine) PSG sound chip emulator
|
// Turbo Grafx 16 (PC Engine) PSG sound chip emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef HES_APU_H
|
#ifndef HES_APU_H
|
||||||
#define HES_APU_H
|
#define HES_APU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Hes_Cpu.h"
|
#include "Hes_Cpu.h"
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ int const ram_addr = 0x2000;
|
||||||
// status flags
|
// status flags
|
||||||
int const st_n = 0x80;
|
int const st_n = 0x80;
|
||||||
int const st_v = 0x40;
|
int const st_v = 0x40;
|
||||||
//unused: int const st_t = 0x20;
|
int const st_t = 0x20;
|
||||||
int const st_b = 0x10;
|
int const st_b = 0x10;
|
||||||
int const st_d = 0x08;
|
int const st_d = 0x08;
|
||||||
int const st_i = 0x04;
|
int const st_i = 0x04;
|
||||||
|
@ -87,12 +87,6 @@ void Hes_Cpu::set_mmr( int reg, int bank )
|
||||||
#define GET_SP() ((sp - 1) & 0xFF)
|
#define GET_SP() ((sp - 1) & 0xFF)
|
||||||
#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
|
#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
|
||||||
|
|
||||||
// even on x86, using short and unsigned char was slower
|
|
||||||
typedef int fint16;
|
|
||||||
typedef unsigned fuint16;
|
|
||||||
typedef unsigned fuint8;
|
|
||||||
typedef blargg_long fint32;
|
|
||||||
|
|
||||||
bool Hes_Cpu::run( hes_time_t end_time )
|
bool Hes_Cpu::run( hes_time_t end_time )
|
||||||
{
|
{
|
||||||
bool illegal_encountered = false;
|
bool illegal_encountered = false;
|
||||||
|
@ -100,14 +94,14 @@ bool Hes_Cpu::run( hes_time_t end_time )
|
||||||
state_t s = this->state_;
|
state_t s = this->state_;
|
||||||
this->state = &s;
|
this->state = &s;
|
||||||
// even on x86, using s.time in place of s_time was slower
|
// even on x86, using s.time in place of s_time was slower
|
||||||
fint16 s_time = s.time;
|
int16_t s_time = s.time;
|
||||||
|
|
||||||
// registers
|
// registers
|
||||||
fuint16 pc = r.pc;
|
uint16_t pc = r.pc;
|
||||||
fuint8 a = r.a;
|
uint8_t a = r.a;
|
||||||
fuint8 x = r.x;
|
uint8_t x = r.x;
|
||||||
fuint8 y = r.y;
|
uint8_t y = r.y;
|
||||||
fuint16 sp;
|
uint16_t sp;
|
||||||
SET_SP( r.sp );
|
SET_SP( r.sp );
|
||||||
|
|
||||||
#define IS_NEG (nz & 0x8080)
|
#define IS_NEG (nz & 0x8080)
|
||||||
|
@ -126,11 +120,11 @@ bool Hes_Cpu::run( hes_time_t end_time )
|
||||||
nz |= ~in & st_z;\
|
nz |= ~in & st_z;\
|
||||||
} while ( 0 )
|
} while ( 0 )
|
||||||
|
|
||||||
fuint8 status;
|
uint8_t status;
|
||||||
fuint16 c; // carry set if (c & 0x100) != 0
|
uint16_t c; // carry set if (c & 0x100) != 0
|
||||||
fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
||||||
{
|
{
|
||||||
fuint8 temp = r.status;
|
uint8_t temp = r.status;
|
||||||
SET_STATUS( temp );
|
SET_STATUS( temp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +153,7 @@ loop:
|
||||||
check( (unsigned) x < 0x100 );
|
check( (unsigned) x < 0x100 );
|
||||||
|
|
||||||
uint8_t const* instr = s.code_map [pc >> page_shift];
|
uint8_t const* instr = s.code_map [pc >> page_shift];
|
||||||
fuint8 opcode;
|
uint8_t opcode;
|
||||||
|
|
||||||
// TODO: eliminate this special case
|
// TODO: eliminate this special case
|
||||||
#if BLARGG_NONPORTABLE
|
#if BLARGG_NONPORTABLE
|
||||||
|
@ -193,7 +187,7 @@ loop:
|
||||||
4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F
|
4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F
|
||||||
}; // 0x00 was 8
|
}; // 0x00 was 8
|
||||||
|
|
||||||
fuint16 data;
|
uint16_t data;
|
||||||
data = clock_table [opcode];
|
data = clock_table [opcode];
|
||||||
if ( (s_time += data) >= 0 )
|
if ( (s_time += data) >= 0 )
|
||||||
goto possibly_out_of_time;
|
goto possibly_out_of_time;
|
||||||
|
@ -230,10 +224,10 @@ possibly_out_of_time:
|
||||||
// TODO: more efficient way to handle negative branch that wraps PC around
|
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||||
#define BRANCH( cond )\
|
#define BRANCH( cond )\
|
||||||
{\
|
{\
|
||||||
fint16 offset = (BOOST::int8_t) data;\
|
int16_t offset = (int8_t) data;\
|
||||||
pc++;\
|
pc++;\
|
||||||
if ( !(cond) ) goto branch_not_taken;\
|
if ( !(cond) ) goto branch_not_taken;\
|
||||||
pc = BOOST::uint16_t (pc + offset);\
|
pc = uint16_t (pc + offset);\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +277,7 @@ possibly_out_of_time:
|
||||||
case 0xCF:
|
case 0xCF:
|
||||||
case 0xDF:
|
case 0xDF:
|
||||||
case 0xEF: {
|
case 0xEF: {
|
||||||
fuint16 t = 0x101 * READ_LOW( data );
|
uint16_t t = 0x101 * READ_LOW( data );
|
||||||
t ^= 0xFF;
|
t ^= 0xFF;
|
||||||
pc++;
|
pc++;
|
||||||
data = GET_MSB();
|
data = GET_MSB();
|
||||||
|
@ -311,7 +305,7 @@ possibly_out_of_time:
|
||||||
goto branch_taken;
|
goto branch_taken;
|
||||||
|
|
||||||
case 0x20: { // JSR
|
case 0x20: { // JSR
|
||||||
fuint16 temp = pc + 1;
|
uint16_t temp = pc + 1;
|
||||||
pc = GET_ADDR();
|
pc = GET_ADDR();
|
||||||
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
||||||
sp = (sp - 2) | 0x100;
|
sp = (sp - 2) | 0x100;
|
||||||
|
@ -332,7 +326,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0xBD:{// LDA abs,X
|
case 0xBD:{// LDA abs,X
|
||||||
PAGE_CROSS_PENALTY( data + x );
|
PAGE_CROSS_PENALTY( data + x );
|
||||||
fuint16 addr = GET_ADDR() + x;
|
uint16_t addr = GET_ADDR() + x;
|
||||||
pc += 2;
|
pc += 2;
|
||||||
CPU_READ_FAST( this, addr, TIME, nz );
|
CPU_READ_FAST( this, addr, TIME, nz );
|
||||||
a = nz;
|
a = nz;
|
||||||
|
@ -340,7 +334,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9D:{// STA abs,X
|
case 0x9D:{// STA abs,X
|
||||||
fuint16 addr = GET_ADDR() + x;
|
uint16_t addr = GET_ADDR() + x;
|
||||||
pc += 2;
|
pc += 2;
|
||||||
CPU_WRITE_FAST( this, addr, a, TIME );
|
CPU_WRITE_FAST( this, addr, a, TIME );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -354,7 +348,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xAE:{// LDX abs
|
case 0xAE:{// LDX abs
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
CPU_READ_FAST( this, addr, TIME, nz );
|
CPU_READ_FAST( this, addr, TIME, nz );
|
||||||
x = nz;
|
x = nz;
|
||||||
|
@ -369,7 +363,7 @@ possibly_out_of_time:
|
||||||
// Load/store
|
// Load/store
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
case 0x91: // STA (ind),Y
|
case 0x91: // STA (ind),Y
|
||||||
addr = 0x100 * READ_LOW( uint8_t (data + 1) );
|
addr = 0x100 * READ_LOW( uint8_t (data + 1) );
|
||||||
addr += READ_LOW( data ) + y;
|
addr += READ_LOW( data ) + y;
|
||||||
|
@ -395,7 +389,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
case 0xA1: // LDA (ind,X)
|
case 0xA1: // LDA (ind,X)
|
||||||
data = uint8_t (data + x);
|
data = uint8_t (data + x);
|
||||||
case 0xB2: // LDA (ind)
|
case 0xB2: // LDA (ind)
|
||||||
|
@ -425,7 +419,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0xBE:{// LDX abs,y
|
case 0xBE:{// LDX abs,y
|
||||||
PAGE_CROSS_PENALTY( data + y );
|
PAGE_CROSS_PENALTY( data + y );
|
||||||
fuint16 addr = GET_ADDR() + y;
|
uint16_t addr = GET_ADDR() + y;
|
||||||
pc += 2;
|
pc += 2;
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
x = nz = READ( addr );
|
x = nz = READ( addr );
|
||||||
|
@ -449,7 +443,7 @@ possibly_out_of_time:
|
||||||
case 0x3C: // BIT abs,x
|
case 0x3C: // BIT abs,x
|
||||||
data += x;
|
data += x;
|
||||||
case 0x2C:{// BIT abs
|
case 0x2C:{// BIT abs
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
ADD_PAGE( addr );
|
ADD_PAGE( addr );
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
nz = READ( addr );
|
nz = READ( addr );
|
||||||
|
@ -472,7 +466,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
|
|
||||||
case 0xB3: // TST abs,x
|
case 0xB3: // TST abs,x
|
||||||
addr = GET_MSB() + x;
|
addr = GET_MSB() + x;
|
||||||
|
@ -505,7 +499,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
case 0x0C: // TSB abs
|
case 0x0C: // TSB abs
|
||||||
case 0x1C: // TRB abs
|
case 0x1C: // TRB abs
|
||||||
addr = GET_ADDR();
|
addr = GET_ADDR();
|
||||||
|
@ -610,7 +604,7 @@ possibly_out_of_time:
|
||||||
data += x;
|
data += x;
|
||||||
PAGE_CROSS_PENALTY( data );
|
PAGE_CROSS_PENALTY( data );
|
||||||
case 0xAC:{// LDY abs
|
case 0xAC:{// LDY abs
|
||||||
fuint16 addr = data + 0x100 * GET_MSB();
|
uint16_t addr = data + 0x100 * GET_MSB();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
y = nz = READ( addr );
|
y = nz = READ( addr );
|
||||||
|
@ -619,7 +613,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
case 0x8C: // STY abs
|
case 0x8C: // STY abs
|
||||||
temp = y;
|
temp = y;
|
||||||
goto store_abs;
|
goto store_abs;
|
||||||
|
@ -627,7 +621,7 @@ possibly_out_of_time:
|
||||||
case 0x8E: // STX abs
|
case 0x8E: // STX abs
|
||||||
temp = x;
|
temp = x;
|
||||||
store_abs:
|
store_abs:
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
WRITE( addr, temp );
|
WRITE( addr, temp );
|
||||||
|
@ -638,7 +632,7 @@ possibly_out_of_time:
|
||||||
// Compare
|
// Compare
|
||||||
|
|
||||||
case 0xEC:{// CPX abs
|
case 0xEC:{// CPX abs
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc++;
|
pc++;
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
data = READ( addr );
|
data = READ( addr );
|
||||||
|
@ -657,7 +651,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xCC:{// CPY abs
|
case 0xCC:{// CPY abs
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc++;
|
pc++;
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
data = READ( addr );
|
data = READ( addr );
|
||||||
|
@ -684,7 +678,7 @@ possibly_out_of_time:
|
||||||
data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\
|
data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\
|
||||||
goto ptr##op;\
|
goto ptr##op;\
|
||||||
case op + 0x0C:{/* (ind),y */\
|
case op + 0x0C:{/* (ind),y */\
|
||||||
fuint16 temp = READ_LOW( data ) + y;\
|
uint16_t temp = READ_LOW( data ) + y;\
|
||||||
PAGE_CROSS_PENALTY( temp );\
|
PAGE_CROSS_PENALTY( temp );\
|
||||||
data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
||||||
goto ptr##op;\
|
goto ptr##op;\
|
||||||
|
@ -742,8 +736,8 @@ possibly_out_of_time:
|
||||||
adc_imm: {
|
adc_imm: {
|
||||||
if ( status & st_d )
|
if ( status & st_d )
|
||||||
debug_printf( "Decimal mode not supported\n" );
|
debug_printf( "Decimal mode not supported\n" );
|
||||||
fint16 carry = c >> 8 & 1;
|
int16_t carry = c >> 8 & 1;
|
||||||
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
|
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
|
||||||
status &= ~st_v;
|
status &= ~st_v;
|
||||||
status |= ov >> 2 & 0x40;
|
status |= ov >> 2 & 0x40;
|
||||||
c = nz = a + data + carry;
|
c = nz = a + data + carry;
|
||||||
|
@ -771,7 +765,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0x2A: { // ROL A
|
case 0x2A: { // ROL A
|
||||||
nz = a << 1;
|
nz = a << 1;
|
||||||
fint16 temp = c >> 8 & 1;
|
int16_t temp = c >> 8 & 1;
|
||||||
c = nz;
|
c = nz;
|
||||||
nz |= temp;
|
nz |= temp;
|
||||||
a = (uint8_t) nz;
|
a = (uint8_t) nz;
|
||||||
|
@ -877,7 +871,7 @@ possibly_out_of_time:
|
||||||
case 0xD6: // DEC zp,x
|
case 0xD6: // DEC zp,x
|
||||||
data = uint8_t (data + x);
|
data = uint8_t (data + x);
|
||||||
case 0xC6: // DEC zp
|
case 0xC6: // DEC zp
|
||||||
nz = (unsigned) -1;
|
nz = (uint16_t) -1;
|
||||||
add_nz_zp:
|
add_nz_zp:
|
||||||
nz += READ_LOW( data );
|
nz += READ_LOW( data );
|
||||||
write_nz_zp:
|
write_nz_zp:
|
||||||
|
@ -902,7 +896,7 @@ possibly_out_of_time:
|
||||||
case 0xCE: // DEC abs
|
case 0xCE: // DEC abs
|
||||||
data = GET_ADDR();
|
data = GET_ADDR();
|
||||||
dec_ptr:
|
dec_ptr:
|
||||||
nz = (unsigned) -1;
|
nz = (uint16_t) -1;
|
||||||
inc_common:
|
inc_common:
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
nz += READ( data );
|
nz += READ( data );
|
||||||
|
@ -942,7 +936,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
#define SWAP_REGS( r1, r2 ) {\
|
#define SWAP_REGS( r1, r2 ) {\
|
||||||
fuint8 t = r1;\
|
uint8_t t = r1;\
|
||||||
r1 = r2;\
|
r1 = r2;\
|
||||||
r2 = t;\
|
r2 = t;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
|
@ -984,7 +978,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x40:{// RTI
|
case 0x40:{// RTI
|
||||||
fuint8 temp = READ_LOW( sp );
|
uint8_t temp = READ_LOW( sp );
|
||||||
pc = READ_LOW( 0x100 | (sp - 0xFF) );
|
pc = READ_LOW( 0x100 | (sp - 0xFF) );
|
||||||
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
|
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
|
||||||
sp = (sp - 0xFD) | 0x100;
|
sp = (sp - 0xFD) | 0x100;
|
||||||
|
@ -1018,8 +1012,8 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x28:{// PLP
|
case 0x28:{// PLP
|
||||||
fuint8 temp = POP();
|
uint8_t temp = POP();
|
||||||
fuint8 changed = status ^ temp;
|
uint8_t changed = status ^ temp;
|
||||||
SET_STATUS( temp );
|
SET_STATUS( temp );
|
||||||
if ( !(changed & st_i) )
|
if ( !(changed & st_i) )
|
||||||
goto loop; // I flag didn't change
|
goto loop; // I flag didn't change
|
||||||
|
@ -1030,7 +1024,7 @@ possibly_out_of_time:
|
||||||
#undef POP
|
#undef POP
|
||||||
|
|
||||||
case 0x08: { // PHP
|
case 0x08: { // PHP
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
PUSH( temp | st_b );
|
PUSH( temp | st_b );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -1039,7 +1033,7 @@ possibly_out_of_time:
|
||||||
// Flags
|
// Flags
|
||||||
|
|
||||||
case 0x38: // SEC
|
case 0x38: // SEC
|
||||||
c = (unsigned) ~0;
|
c = (uint16_t) ~0;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x18: // CLC
|
case 0x18: // CLC
|
||||||
|
@ -1107,7 +1101,7 @@ possibly_out_of_time:
|
||||||
// Special
|
// Special
|
||||||
|
|
||||||
case 0x53:{// TAM
|
case 0x53:{// TAM
|
||||||
fuint8 const bits = data; // avoid using data across function call
|
uint8_t const bits = data; // avoid using data across function call
|
||||||
pc++;
|
pc++;
|
||||||
for ( int i = 0; i < 8; i++ )
|
for ( int i = 0; i < 8; i++ )
|
||||||
if ( bits & (1 << i) )
|
if ( bits & (1 << i) )
|
||||||
|
@ -1131,7 +1125,7 @@ possibly_out_of_time:
|
||||||
case 0x03: // ST0
|
case 0x03: // ST0
|
||||||
case 0x13: // ST1
|
case 0x13: // ST1
|
||||||
case 0x23:{// ST2
|
case 0x23:{// ST2
|
||||||
fuint16 addr = opcode >> 4;
|
uint16_t addr = opcode >> 4;
|
||||||
if ( addr )
|
if ( addr )
|
||||||
addr++;
|
addr++;
|
||||||
pc++;
|
pc++;
|
||||||
|
@ -1153,7 +1147,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xF4: { // SET
|
case 0xF4: { // SET
|
||||||
//fuint16 operand = GET_MSB();
|
//uint16_t operand = GET_MSB();
|
||||||
debug_printf( "SET not handled\n" );
|
debug_printf( "SET not handled\n" );
|
||||||
//switch ( data )
|
//switch ( data )
|
||||||
//{
|
//{
|
||||||
|
@ -1165,10 +1159,10 @@ possibly_out_of_time:
|
||||||
// Block transfer
|
// Block transfer
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 in_alt;
|
uint16_t in_alt;
|
||||||
fint16 in_inc;
|
int16_t in_inc;
|
||||||
fuint16 out_alt;
|
uint16_t out_alt;
|
||||||
fint16 out_inc;
|
int16_t out_inc;
|
||||||
|
|
||||||
case 0xE3: // TIA
|
case 0xE3: // TIA
|
||||||
in_alt = 0;
|
in_alt = 0;
|
||||||
|
@ -1199,8 +1193,8 @@ possibly_out_of_time:
|
||||||
in_alt = 0;
|
in_alt = 0;
|
||||||
out_alt = 0;
|
out_alt = 0;
|
||||||
bxfer:
|
bxfer:
|
||||||
fuint16 in = GET_LE16( instr + 0 );
|
uint16_t in = GET_LE16( instr + 0 );
|
||||||
fuint16 out = GET_LE16( instr + 2 );
|
uint16_t out = GET_LE16( instr + 2 );
|
||||||
int count = GET_LE16( instr + 4 );
|
int count = GET_LE16( instr + 4 );
|
||||||
if ( !count )
|
if ( !count )
|
||||||
count = 0x10000;
|
count = 0x10000;
|
||||||
|
@ -1212,7 +1206,7 @@ possibly_out_of_time:
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O
|
// TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O
|
||||||
fuint8 t = READ( in );
|
uint8_t t = READ( in );
|
||||||
in += in_inc;
|
in += in_inc;
|
||||||
in &= 0xFFFF;
|
in &= 0xFFFF;
|
||||||
s.time += 6;
|
s.time += 6;
|
||||||
|
@ -1232,7 +1226,6 @@ possibly_out_of_time:
|
||||||
// Illegal
|
// Illegal
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert( (unsigned) opcode <= 0xFF );
|
|
||||||
debug_printf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 );
|
debug_printf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 );
|
||||||
illegal_encountered = true;
|
illegal_encountered = true;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -1253,7 +1246,7 @@ interrupt:
|
||||||
pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ );
|
pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ );
|
||||||
|
|
||||||
sp = (sp - 3) | 0x100;
|
sp = (sp - 3) | 0x100;
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
if ( result_ == 6 )
|
if ( result_ == 6 )
|
||||||
temp |= st_b;
|
temp |= st_b;
|
||||||
|
@ -1290,7 +1283,7 @@ out_of_time:
|
||||||
r.y = y;
|
r.y = y;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
r.status = temp;
|
r.status = temp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// PC Engine CPU emulator for use with HES music files
|
// PC Engine CPU emulator for use with HES music files
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef HES_CPU_H
|
#ifndef HES_CPU_H
|
||||||
#define HES_CPU_H
|
#define HES_CPU_H
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@ enum { future_hes_time = INT_MAX / 2 + 1 };
|
||||||
|
|
||||||
class Hes_Cpu {
|
class Hes_Cpu {
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
enum { page_size = 0x2000 };
|
enum { page_size = 0x2000 };
|
||||||
|
@ -27,7 +25,7 @@ public:
|
||||||
|
|
||||||
// not kept updated during a call to run()
|
// not kept updated during a call to run()
|
||||||
struct registers_t {
|
struct registers_t {
|
||||||
BOOST::uint16_t pc;
|
uint16_t pc;
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
uint8_t x;
|
uint8_t x;
|
||||||
uint8_t y;
|
uint8_t y;
|
||||||
|
@ -86,7 +84,7 @@ private:
|
||||||
inline int update_end_time( hes_time_t end, hes_time_t irq );
|
inline int update_end_time( hes_time_t end, hes_time_t irq );
|
||||||
};
|
};
|
||||||
|
|
||||||
inline BOOST::uint8_t const* Hes_Cpu::get_code( hes_addr_t addr )
|
inline uint8_t const* Hes_Cpu::get_code( hes_addr_t addr )
|
||||||
{
|
{
|
||||||
return state->code_map [addr >> page_shift] + addr
|
return state->code_map [addr >> page_shift] + addr
|
||||||
#if !BLARGG_NONPORTABLE
|
#if !BLARGG_NONPORTABLE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Hes_Emu.h"
|
#include "Hes_Emu.h"
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ static Music_Emu* new_hes_emu () { return BLARGG_NEW Hes_Emu ; }
|
||||||
static Music_Emu* new_hes_file() { return BLARGG_NEW Hes_File; }
|
static Music_Emu* new_hes_file() { return BLARGG_NEW Hes_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_hes_type_ = { "PC Engine", 256, &new_hes_emu, &new_hes_file, "HES", 1 };
|
static gme_type_t_ const gme_hes_type_ = { "PC Engine", 256, &new_hes_emu, &new_hes_file, "HES", 1 };
|
||||||
gme_type_t const gme_hes_type = &gme_hes_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_hes_type = &gme_hes_type_;
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// TurboGrafx-16/PC Engine HES music file emulator
|
// TurboGrafx-16/PC Engine HES music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef HES_EMU_H
|
#ifndef HES_EMU_H
|
||||||
#define HES_EMU_H
|
#define HES_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Last validated with zexall 2006.11.14 2:19 PM
|
Last validated with zexall 2006.11.14 2:19 PM
|
||||||
|
@ -162,11 +162,6 @@ static byte const ed_dd_timing [0x100] = {
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
// even on x86, using short and unsigned char was slower
|
|
||||||
typedef int fint16;
|
|
||||||
typedef unsigned fuint16;
|
|
||||||
typedef unsigned fuint8;
|
|
||||||
|
|
||||||
bool Kss_Cpu::run( cpu_time_t end_time )
|
bool Kss_Cpu::run( cpu_time_t end_time )
|
||||||
{
|
{
|
||||||
set_end_time( end_time );
|
set_end_time( end_time );
|
||||||
|
@ -174,8 +169,6 @@ bool Kss_Cpu::run( cpu_time_t end_time )
|
||||||
this->state = &s;
|
this->state = &s;
|
||||||
bool warning = false;
|
bool warning = false;
|
||||||
|
|
||||||
typedef BOOST::int8_t int8_t;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
regs_t rg;
|
regs_t rg;
|
||||||
pairs_t rp;
|
pairs_t rp;
|
||||||
|
@ -185,10 +178,10 @@ bool Kss_Cpu::run( cpu_time_t end_time )
|
||||||
rg = this->r.b;
|
rg = this->r.b;
|
||||||
|
|
||||||
cpu_time_t s_time = s.time;
|
cpu_time_t s_time = s.time;
|
||||||
fuint16 pc = r.pc;
|
uint16_t pc = r.pc;
|
||||||
fuint16 sp = r.sp;
|
uint16_t sp = r.sp;
|
||||||
fuint16 ix = r.ix; // TODO: keep in memory for direct access?
|
uint16_t ix = r.ix; // TODO: keep in memory for direct access?
|
||||||
fuint16 iy = r.iy;
|
uint16_t iy = r.iy;
|
||||||
int flags = r.b.flags;
|
int flags = r.b.flags;
|
||||||
|
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -210,7 +203,7 @@ loop:
|
||||||
uint8_t const* instr = s.read [pc >> page_shift];
|
uint8_t const* instr = s.read [pc >> page_shift];
|
||||||
#define GET_ADDR() GET_LE16( instr )
|
#define GET_ADDR() GET_LE16( instr )
|
||||||
|
|
||||||
fuint8 opcode;
|
uint8_t opcode;
|
||||||
|
|
||||||
// TODO: eliminate this special case
|
// TODO: eliminate this special case
|
||||||
#if BLARGG_NONPORTABLE
|
#if BLARGG_NONPORTABLE
|
||||||
|
@ -243,7 +236,7 @@ loop:
|
||||||
11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
|
11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F
|
||||||
};
|
};
|
||||||
|
|
||||||
fuint16 data;
|
uint16_t data;
|
||||||
data = base_timing [opcode];
|
data = base_timing [opcode];
|
||||||
if ( (s_time += data) >= 0 )
|
if ( (s_time += data) >= 0 )
|
||||||
goto possibly_out_of_time;
|
goto possibly_out_of_time;
|
||||||
|
@ -299,7 +292,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x3A:{// LD A,(addr)
|
case 0x3A:{// LD A,(addr)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
rg.a = READ( addr );
|
rg.a = READ( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -315,7 +308,7 @@ possibly_out_of_time:
|
||||||
// JR
|
// JR
|
||||||
// TODO: more efficient way to handle negative branch that wraps PC around
|
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||||
#define JR( cond ) {\
|
#define JR( cond ) {\
|
||||||
int offset = (BOOST::int8_t) data;\
|
int offset = (int8_t) data;\
|
||||||
pc++;\
|
pc++;\
|
||||||
if ( !(cond) )\
|
if ( !(cond) )\
|
||||||
goto jr_not_taken;\
|
goto jr_not_taken;\
|
||||||
|
@ -387,7 +380,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0xCD:{// CALL addr
|
case 0xCD:{// CALL addr
|
||||||
call_taken:
|
call_taken:
|
||||||
fuint16 addr = pc + 2;
|
uint16_t addr = pc + 2;
|
||||||
pc = GET_ADDR();
|
pc = GET_ADDR();
|
||||||
sp = uint16_t (sp - 2);
|
sp = uint16_t (sp - 2);
|
||||||
WRITE_WORD( sp, addr );
|
WRITE_WORD( sp, addr );
|
||||||
|
@ -395,7 +388,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xFF: // RST
|
case 0xFF: // RST
|
||||||
if ( pc > idle_addr )
|
if ( pc >= idle_addr )
|
||||||
goto hit_idle_addr;
|
goto hit_idle_addr;
|
||||||
CASE7( C7, CF, D7, DF, E7, EF, F7 ):
|
CASE7( C7, CF, D7, DF, E7, EF, F7 ):
|
||||||
data = pc;
|
data = pc;
|
||||||
|
@ -503,7 +496,7 @@ possibly_out_of_time:
|
||||||
add_hl_data: {
|
add_hl_data: {
|
||||||
blargg_ulong sum = rp.hl + data;
|
blargg_ulong sum = rp.hl + data;
|
||||||
data ^= rp.hl;
|
data ^= rp.hl;
|
||||||
rp.hl = (uint16_t)sum;
|
rp.hl = sum;
|
||||||
flags = (flags & (S80 | Z40 | V04)) |
|
flags = (flags & (S80 | Z40 | V04)) |
|
||||||
(sum >> 16) |
|
(sum >> 16) |
|
||||||
(sum >> 8 & (F20 | F08)) |
|
(sum >> 8 & (F20 | F08)) |
|
||||||
|
@ -693,21 +686,21 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x2A:{// LD HL,(addr)
|
case 0x2A:{// LD HL,(addr)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
rp.hl = READ_WORD( addr );
|
rp.hl = READ_WORD( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x32:{// LD (addr),A
|
case 0x32:{// LD (addr),A
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE( addr, rg.a );
|
WRITE( addr, rg.a );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x22:{// LD (addr),HL
|
case 0x22:{// LD (addr),HL
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE_WORD( addr, rp.hl );
|
WRITE_WORD( addr, rp.hl );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -730,7 +723,7 @@ possibly_out_of_time:
|
||||||
// Rotate
|
// Rotate
|
||||||
|
|
||||||
case 0x07:{// RLCA
|
case 0x07:{// RLCA
|
||||||
fuint16 temp = rg.a;
|
uint16_t temp = rg.a;
|
||||||
temp = (temp << 1) | (temp >> 7);
|
temp = (temp << 1) | (temp >> 7);
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & (F20 | F08 | C01));
|
(temp & (F20 | F08 | C01));
|
||||||
|
@ -739,7 +732,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x0F:{// RRCA
|
case 0x0F:{// RRCA
|
||||||
fuint16 temp = rg.a;
|
uint16_t temp = rg.a;
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & C01);
|
(temp & C01);
|
||||||
temp = (temp << 7) | (temp >> 1);
|
temp = (temp << 7) | (temp >> 1);
|
||||||
|
@ -753,12 +746,12 @@ possibly_out_of_time:
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & (F20 | F08)) |
|
(temp & (F20 | F08)) |
|
||||||
(temp >> 8);
|
(temp >> 8);
|
||||||
rg.a = (uint8_t)temp;
|
rg.a = temp;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x1F:{// RRA
|
case 0x1F:{// RRA
|
||||||
fuint16 temp = (flags << 7) | (rg.a >> 1);
|
uint16_t temp = (flags << 7) | (rg.a >> 1);
|
||||||
flags = (flags & (S80 | Z40 | P04)) |
|
flags = (flags & (S80 | Z40 | P04)) |
|
||||||
(temp & (F20 | F08)) |
|
(temp & (F20 | F08)) |
|
||||||
(rg.a & C01);
|
(rg.a & C01);
|
||||||
|
@ -768,7 +761,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
case 0x2F:{// CPL
|
case 0x2F:{// CPL
|
||||||
fuint16 temp = ~rg.a;
|
uint16_t temp = ~rg.a;
|
||||||
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
||||||
(temp & (F20 | F08)) |
|
(temp & (F20 | F08)) |
|
||||||
(H10 | N02);
|
(H10 | N02);
|
||||||
|
@ -794,21 +787,21 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xE3:{// EX (SP),HL
|
case 0xE3:{// EX (SP),HL
|
||||||
fuint16 temp = READ_WORD( sp );
|
uint16_t temp = READ_WORD( sp );
|
||||||
WRITE_WORD( sp, rp.hl );
|
WRITE_WORD( sp, rp.hl );
|
||||||
rp.hl = temp;
|
rp.hl = temp;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xEB:{// EX DE,HL
|
case 0xEB:{// EX DE,HL
|
||||||
fuint16 temp = rp.hl;
|
uint16_t temp = rp.hl;
|
||||||
rp.hl = rp.de;
|
rp.hl = rp.de;
|
||||||
rp.de = temp;
|
rp.de = temp;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xD9:{// EXX DE,HL
|
case 0xD9:{// EXX DE,HL
|
||||||
fuint16 temp = r.alt.w.bc;
|
uint16_t temp = r.alt.w.bc;
|
||||||
r.alt.w.bc = rp.bc;
|
r.alt.w.bc = rp.bc;
|
||||||
rp.bc = temp;
|
rp.bc = temp;
|
||||||
|
|
||||||
|
@ -849,7 +842,7 @@ possibly_out_of_time:
|
||||||
// Rotate left
|
// Rotate left
|
||||||
|
|
||||||
#define RLC( read, write ) {\
|
#define RLC( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
result = uint8_t (result << 1) | (result >> 7);\
|
result = uint8_t (result << 1) | (result >> 7);\
|
||||||
flags = SZ28P( result ) | (result & C01);\
|
flags = SZ28P( result ) | (result & C01);\
|
||||||
write;\
|
write;\
|
||||||
|
@ -868,7 +861,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RL( read, write ) {\
|
#define RL( read, write ) {\
|
||||||
fuint16 result = (read << 1) | (flags & C01);\
|
uint16_t result = (read << 1) | (flags & C01);\
|
||||||
flags = SZ28PC( result );\
|
flags = SZ28PC( result );\
|
||||||
write;\
|
write;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
|
@ -886,7 +879,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SLA( read, add, write ) {\
|
#define SLA( read, add, write ) {\
|
||||||
fuint16 result = (read << 1) | add;\
|
uint16_t result = (read << 1) | add;\
|
||||||
flags = SZ28PC( result );\
|
flags = SZ28PC( result );\
|
||||||
write;\
|
write;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
|
@ -917,7 +910,7 @@ possibly_out_of_time:
|
||||||
// Rotate right
|
// Rotate right
|
||||||
|
|
||||||
#define RRC( read, write ) {\
|
#define RRC( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
flags = result & C01;\
|
flags = result & C01;\
|
||||||
result = uint8_t (result << 7) | (result >> 1);\
|
result = uint8_t (result << 7) | (result >> 1);\
|
||||||
flags |= SZ28P( result );\
|
flags |= SZ28P( result );\
|
||||||
|
@ -937,8 +930,8 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RR( read, write ) {\
|
#define RR( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
fuint8 temp = result & C01;\
|
uint8_t temp = result & C01;\
|
||||||
result = uint8_t (flags << 7) | (result >> 1);\
|
result = uint8_t (flags << 7) | (result >> 1);\
|
||||||
flags = SZ28P( result ) | temp;\
|
flags = SZ28P( result ) | temp;\
|
||||||
write;\
|
write;\
|
||||||
|
@ -957,7 +950,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SRA( read, write ) {\
|
#define SRA( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
flags = result & C01;\
|
flags = result & C01;\
|
||||||
result = (result & 0x80) | (result >> 1);\
|
result = (result & 0x80) | (result >> 1);\
|
||||||
flags |= SZ28P( result );\
|
flags |= SZ28P( result );\
|
||||||
|
@ -977,7 +970,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SRL( read, write ) {\
|
#define SRL( read, write ) {\
|
||||||
fuint8 result = read;\
|
uint8_t result = read;\
|
||||||
flags = result & C01;\
|
flags = result & C01;\
|
||||||
result >>= 1;\
|
result >>= 1;\
|
||||||
flags |= SZ28P( result );\
|
flags |= SZ28P( result );\
|
||||||
|
@ -1085,7 +1078,7 @@ possibly_out_of_time:
|
||||||
blargg_ulong sum = temp + (flags & C01);
|
blargg_ulong sum = temp + (flags & C01);
|
||||||
flags = ~data >> 2 & N02;
|
flags = ~data >> 2 & N02;
|
||||||
if ( flags )
|
if ( flags )
|
||||||
sum = (blargg_ulong)-(blargg_long)sum;
|
sum = -sum;
|
||||||
sum += rp.hl;
|
sum += rp.hl;
|
||||||
temp ^= rp.hl;
|
temp ^= rp.hl;
|
||||||
temp ^= sum;
|
temp ^= sum;
|
||||||
|
@ -1093,7 +1086,7 @@ possibly_out_of_time:
|
||||||
(temp >> 8 & H10) |
|
(temp >> 8 & H10) |
|
||||||
(sum >> 8 & (S80 | F20 | F08)) |
|
(sum >> 8 & (S80 | F20 | F08)) |
|
||||||
((temp - -0x8000) >> 14 & V04);
|
((temp - -0x8000) >> 14 & V04);
|
||||||
rp.hl = (uint16_t)sum;
|
rp.hl = sum;
|
||||||
if ( (uint16_t) sum )
|
if ( (uint16_t) sum )
|
||||||
goto loop;
|
goto loop;
|
||||||
flags |= Z40;
|
flags |= Z40;
|
||||||
|
@ -1121,7 +1114,7 @@ possibly_out_of_time:
|
||||||
case 0x43: // LD (ADDR),BC
|
case 0x43: // LD (ADDR),BC
|
||||||
case 0x53: // LD (ADDR),DE
|
case 0x53: // LD (ADDR),DE
|
||||||
temp = R16( data, 4, 0x43 );
|
temp = R16( data, 4, 0x43 );
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE_WORD( addr, temp );
|
WRITE_WORD( addr, temp );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -1129,21 +1122,21 @@ possibly_out_of_time:
|
||||||
|
|
||||||
case 0x4B: // LD BC,(ADDR)
|
case 0x4B: // LD BC,(ADDR)
|
||||||
case 0x5B:{// LD DE,(ADDR)
|
case 0x5B:{// LD DE,(ADDR)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x7B:{// LD SP,(ADDR)
|
case 0x7B:{// LD SP,(ADDR)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
sp = READ_WORD( addr );
|
sp = READ_WORD( addr );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x67:{// RRD
|
case 0x67:{// RRD
|
||||||
fuint8 temp = READ( rp.hl );
|
uint8_t temp = READ( rp.hl );
|
||||||
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
||||||
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
||||||
flags = (flags & C01) | SZ28P( temp );
|
flags = (flags & C01) | SZ28P( temp );
|
||||||
|
@ -1152,7 +1145,7 @@ possibly_out_of_time:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x6F:{// RLD
|
case 0x6F:{// RLD
|
||||||
fuint8 temp = READ( rp.hl );
|
uint8_t temp = READ( rp.hl );
|
||||||
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
||||||
temp = (rg.a & 0xF0) | (temp >> 4);
|
temp = (rg.a & 0xF0) | (temp >> 4);
|
||||||
flags = (flags & C01) | SZ28P( temp );
|
flags = (flags & C01) | SZ28P( temp );
|
||||||
|
@ -1176,7 +1169,7 @@ possibly_out_of_time:
|
||||||
case 0xA1: // CPI
|
case 0xA1: // CPI
|
||||||
case 0xB1: // CPIR
|
case 0xB1: // CPIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
int temp = READ( addr );
|
int temp = READ( addr );
|
||||||
|
|
||||||
|
@ -1209,7 +1202,7 @@ possibly_out_of_time:
|
||||||
case 0xA0: // LDI
|
case 0xA0: // LDI
|
||||||
case 0xB0: // LDIR
|
case 0xB0: // LDIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
int temp = READ( addr );
|
int temp = READ( addr );
|
||||||
|
|
||||||
|
@ -1241,7 +1234,7 @@ possibly_out_of_time:
|
||||||
case 0xA3: // OUTI
|
case 0xA3: // OUTI
|
||||||
case 0xB3: // OTIR
|
case 0xB3: // OTIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
int temp = READ( addr );
|
int temp = READ( addr );
|
||||||
|
|
||||||
|
@ -1267,7 +1260,7 @@ possibly_out_of_time:
|
||||||
case 0xB2: // INIR
|
case 0xB2: // INIR
|
||||||
inc = +1;
|
inc = +1;
|
||||||
|
|
||||||
fuint16 addr = rp.hl;
|
uint16_t addr = rp.hl;
|
||||||
rp.hl = addr + inc;
|
rp.hl = addr + inc;
|
||||||
|
|
||||||
int temp = IN( rp.bc );
|
int temp = IN( rp.bc );
|
||||||
|
@ -1332,7 +1325,7 @@ possibly_out_of_time:
|
||||||
|
|
||||||
//////////////////////////////////////// DD/FD prefix
|
//////////////////////////////////////// DD/FD prefix
|
||||||
{
|
{
|
||||||
fuint16 ixy;
|
uint16_t ixy;
|
||||||
case 0xDD:
|
case 0xDD:
|
||||||
ixy = ix;
|
ixy = ix;
|
||||||
goto ix_prefix;
|
goto ix_prefix;
|
||||||
|
@ -1528,7 +1521,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x22:{// LD (ADDR),IXY
|
case 0x22:{// LD (ADDR),IXY
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
pc += 2;
|
pc += 2;
|
||||||
WRITE_WORD( addr, ixy );
|
WRITE_WORD( addr, ixy );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -1540,7 +1533,7 @@ possibly_out_of_time:
|
||||||
goto set_ixy;
|
goto set_ixy;
|
||||||
|
|
||||||
case 0x2A:{// LD IXY,(addr)
|
case 0x2A:{// LD IXY,(addr)
|
||||||
fuint16 addr = GET_ADDR();
|
uint16_t addr = GET_ADDR();
|
||||||
ixy = READ_WORD( addr );
|
ixy = READ_WORD( addr );
|
||||||
pc += 2;
|
pc += 2;
|
||||||
goto set_ixy;
|
goto set_ixy;
|
||||||
|
@ -1564,7 +1557,7 @@ possibly_out_of_time:
|
||||||
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
||||||
|
|
||||||
CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
|
CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp)
|
||||||
fuint8 temp = READ( data );
|
uint8_t temp = READ( data );
|
||||||
int masked = temp & 1 << (data2 >> 3 & 7);
|
int masked = temp & 1 << (data2 >> 3 & 7);
|
||||||
flags = (flags & C01) | H10 |
|
flags = (flags & C01) | H10 |
|
||||||
(masked & S80) |
|
(masked & S80) |
|
||||||
|
@ -1666,7 +1659,7 @@ possibly_out_of_time:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xE3:{// EX (SP),IXY
|
case 0xE3:{// EX (SP),IXY
|
||||||
fuint16 temp = READ_WORD( sp );
|
uint16_t temp = READ_WORD( sp );
|
||||||
WRITE_WORD( sp, ixy );
|
WRITE_WORD( sp, ixy );
|
||||||
ixy = temp;
|
ixy = temp;
|
||||||
goto set_ixy;
|
goto set_ixy;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Z80 CPU emulator
|
// Z80 CPU emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef KSS_CPU_H
|
#ifndef KSS_CPU_H
|
||||||
#define KSS_CPU_H
|
#define KSS_CPU_H
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ void kss_cpu_write( class Kss_Cpu*, unsigned addr, int data );
|
||||||
|
|
||||||
class Kss_Cpu {
|
class Kss_Cpu {
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
// Clear registers and map all pages to unmapped
|
// Clear registers and map all pages to unmapped
|
||||||
void reset( void* unmapped_write, void const* unmapped_read );
|
void reset( void* unmapped_write, void const* unmapped_read );
|
||||||
|
|
||||||
|
@ -39,8 +37,6 @@ public:
|
||||||
void set_time( cpu_time_t t ) { state->time = t - state->base; }
|
void set_time( cpu_time_t t ) { state->time = t - state->base; }
|
||||||
void adjust_time( int delta ) { state->time += delta; }
|
void adjust_time( int delta ) { state->time += delta; }
|
||||||
|
|
||||||
typedef BOOST::uint16_t uint16_t;
|
|
||||||
|
|
||||||
#if BLARGG_BIG_ENDIAN
|
#if BLARGG_BIG_ENDIAN
|
||||||
struct regs_t { uint8_t b, c, d, e, h, l, flags, a; };
|
struct regs_t { uint8_t b, c, d, e, h, l, flags, a; };
|
||||||
#else
|
#else
|
||||||
|
@ -104,12 +100,12 @@ public:
|
||||||
#define KSS_CPU_PAGE_OFFSET( addr ) ((addr) & (page_size - 1))
|
#define KSS_CPU_PAGE_OFFSET( addr ) ((addr) & (page_size - 1))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline BOOST::uint8_t* Kss_Cpu::write( unsigned addr )
|
inline uint8_t* Kss_Cpu::write( unsigned addr )
|
||||||
{
|
{
|
||||||
return state->write [addr >> page_shift] + KSS_CPU_PAGE_OFFSET( addr );
|
return state->write [addr >> page_shift] + KSS_CPU_PAGE_OFFSET( addr );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BOOST::uint8_t const* Kss_Cpu::read( unsigned addr )
|
inline uint8_t const* Kss_Cpu::read( unsigned addr )
|
||||||
{
|
{
|
||||||
return state->read [addr >> page_shift] + KSS_CPU_PAGE_OFFSET( addr );
|
return state->read [addr >> page_shift] + KSS_CPU_PAGE_OFFSET( addr );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Kss_Emu.h"
|
#include "Kss_Emu.h"
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ static Music_Emu* new_kss_emu () { return BLARGG_NEW Kss_Emu ; }
|
||||||
static Music_Emu* new_kss_file() { return BLARGG_NEW Kss_File; }
|
static Music_Emu* new_kss_file() { return BLARGG_NEW Kss_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_kss_type_ = { "MSX", 256, &new_kss_emu, &new_kss_file, "KSS", 0x03 };
|
static gme_type_t_ const gme_kss_type_ = { "MSX", 256, &new_kss_emu, &new_kss_file, "KSS", 0x03 };
|
||||||
gme_type_t const gme_kss_type = &gme_kss_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_kss_type = &gme_kss_type_;
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// MSX computer KSS music file emulator
|
// MSX computer KSS music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef KSS_EMU_H
|
#ifndef KSS_EMU_H
|
||||||
#define KSS_EMU_H
|
#define KSS_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Kss_Scc_Apu.h"
|
#include "Kss_Scc_Apu.h"
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ void Scc_Apu::run_until( blip_time_t end_time )
|
||||||
volume = (regs [0x8A + index] & 0x0F) * (amp_range / 256 / 15);
|
volume = (regs [0x8A + index] & 0x0F) * (amp_range / 256 / 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST::int8_t const* wave = (BOOST::int8_t*) regs + index * wave_size;
|
int8_t const* wave = (int8_t*) regs + index * wave_size;
|
||||||
if ( index == osc_count - 1 )
|
if ( index == osc_count - 1 )
|
||||||
wave -= wave_size; // last two oscs share wave
|
wave -= wave_size; // last two oscs share wave
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Konami SCC sound chip emulator
|
// Konami SCC sound chip emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef KSS_SCC_APU_H
|
#ifndef KSS_SCC_APU_H
|
||||||
#define KSS_SCC_APU_H
|
#define KSS_SCC_APU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "M3u_Playlist.h"
|
#include "M3u_Playlist.h"
|
||||||
#include "Music_Emu.h"
|
#include "Music_Emu.h"
|
||||||
|
@ -407,7 +407,7 @@ blargg_err_t M3u_Playlist::parse()
|
||||||
blargg_err_t M3u_Playlist::load( Data_Reader& in )
|
blargg_err_t M3u_Playlist::load( Data_Reader& in )
|
||||||
{
|
{
|
||||||
RETURN_ERR( data.resize( in.remain() + 1 ) );
|
RETURN_ERR( data.resize( in.remain() + 1 ) );
|
||||||
RETURN_ERR( in.read( data.begin(), long(data.size() - 1) ) );
|
RETURN_ERR( in.read( data.begin(), data.size() - 1 ) );
|
||||||
return parse();
|
return parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// M3U playlist file parser, with support for subtrack information
|
// M3U playlist file parser, with support for subtrack information
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef M3U_PLAYLIST_H
|
#ifndef M3U_PLAYLIST_H
|
||||||
#define M3U_PLAYLIST_H
|
#define M3U_PLAYLIST_H
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public:
|
||||||
int repeat; // count
|
int repeat; // count
|
||||||
};
|
};
|
||||||
entry_t const& operator [] ( int i ) const { return entries [i]; }
|
entry_t const& operator [] ( int i ) const { return entries [i]; }
|
||||||
int size() const { return int(entries.size()); }
|
int size() const { return entries.size(); }
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ void Stereo_Buffer::clock_rate( long rate )
|
||||||
|
|
||||||
void Stereo_Buffer::bass_freq( int bass )
|
void Stereo_Buffer::bass_freq( int bass )
|
||||||
{
|
{
|
||||||
for ( unsigned i = 0; i < buf_count; i++ )
|
for ( int i = 0; i < buf_count; i++ )
|
||||||
bufs [i].bass_freq( bass );
|
bufs [i].bass_freq( bass );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ void Stereo_Buffer::clear()
|
||||||
void Stereo_Buffer::end_frame( blip_time_t clock_count )
|
void Stereo_Buffer::end_frame( blip_time_t clock_count )
|
||||||
{
|
{
|
||||||
stereo_added = 0;
|
stereo_added = 0;
|
||||||
for ( unsigned i = 0; i < buf_count; i++ )
|
for ( int i = 0; i < buf_count; i++ )
|
||||||
{
|
{
|
||||||
stereo_added |= bufs [i].clear_modified() << i;
|
stereo_added |= bufs [i].clear_modified() << i;
|
||||||
bufs [i].end_frame( clock_count );
|
bufs [i].end_frame( clock_count );
|
||||||
|
@ -161,18 +161,18 @@ void Stereo_Buffer::mix_stereo( blip_sample_t* out_, blargg_long count )
|
||||||
int c = BLIP_READER_READ( center );
|
int c = BLIP_READER_READ( center );
|
||||||
blargg_long l = c + BLIP_READER_READ( left );
|
blargg_long l = c + BLIP_READER_READ( left );
|
||||||
blargg_long r = c + BLIP_READER_READ( right );
|
blargg_long r = c + BLIP_READER_READ( right );
|
||||||
if ( (BOOST::int16_t) l != l )
|
if ( (int16_t) l != l )
|
||||||
l = 0x7FFF - (l >> 24);
|
l = 0x7FFF - (l >> 24);
|
||||||
|
|
||||||
BLIP_READER_NEXT( center, bass );
|
BLIP_READER_NEXT( center, bass );
|
||||||
if ( (BOOST::int16_t) r != r )
|
if ( (int16_t) r != r )
|
||||||
r = 0x7FFF - (r >> 24);
|
r = 0x7FFF - (r >> 24);
|
||||||
|
|
||||||
BLIP_READER_NEXT( left, bass );
|
BLIP_READER_NEXT( left, bass );
|
||||||
BLIP_READER_NEXT( right, bass );
|
BLIP_READER_NEXT( right, bass );
|
||||||
|
|
||||||
out [0] = (blip_sample_t)l;
|
out [0] = l;
|
||||||
out [1] = (blip_sample_t)r;
|
out [1] = r;
|
||||||
out += 2;
|
out += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,18 +191,18 @@ void Stereo_Buffer::mix_stereo_no_center( blip_sample_t* out_, blargg_long count
|
||||||
for ( ; count; --count )
|
for ( ; count; --count )
|
||||||
{
|
{
|
||||||
blargg_long l = BLIP_READER_READ( left );
|
blargg_long l = BLIP_READER_READ( left );
|
||||||
if ( (BOOST::int16_t) l != l )
|
if ( (int16_t) l != l )
|
||||||
l = 0x7FFF - (l >> 24);
|
l = 0x7FFF - (l >> 24);
|
||||||
|
|
||||||
blargg_long r = BLIP_READER_READ( right );
|
blargg_long r = BLIP_READER_READ( right );
|
||||||
if ( (BOOST::int16_t) r != r )
|
if ( (int16_t) r != r )
|
||||||
r = 0x7FFF - (r >> 24);
|
r = 0x7FFF - (r >> 24);
|
||||||
|
|
||||||
BLIP_READER_NEXT( left, bass );
|
BLIP_READER_NEXT( left, bass );
|
||||||
BLIP_READER_NEXT( right, bass );
|
BLIP_READER_NEXT( right, bass );
|
||||||
|
|
||||||
out [0] = (blip_sample_t)l;
|
out [0] = l;
|
||||||
out [1] = (blip_sample_t)r;
|
out [1] = r;
|
||||||
out += 2;
|
out += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,12 +219,12 @@ void Stereo_Buffer::mix_mono( blip_sample_t* out_, blargg_long count )
|
||||||
for ( ; count; --count )
|
for ( ; count; --count )
|
||||||
{
|
{
|
||||||
blargg_long s = BLIP_READER_READ( center );
|
blargg_long s = BLIP_READER_READ( center );
|
||||||
if ( (BOOST::int16_t) s != s )
|
if ( (int16_t) s != s )
|
||||||
s = 0x7FFF - (s >> 24);
|
s = 0x7FFF - (s >> 24);
|
||||||
|
|
||||||
BLIP_READER_NEXT( center, bass );
|
BLIP_READER_NEXT( center, bass );
|
||||||
out [0] = (blip_sample_t)s;
|
out [0] = s;
|
||||||
out [1] = (blip_sample_t)s;
|
out [1] = s;
|
||||||
out += 2;
|
out += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Music_Emu.h"
|
#include "Music_Emu.h"
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
#include "blargg_source.h"
|
#include "blargg_source.h"
|
||||||
|
|
||||||
int const stereo = 2; // number of channels for stereo
|
|
||||||
int const silence_max = 6; // seconds
|
int const silence_max = 6; // seconds
|
||||||
int const silence_threshold = 0x10;
|
int const silence_threshold = 0x10;
|
||||||
long const fade_block_size = 512;
|
long const fade_block_size = 512;
|
||||||
|
@ -52,7 +51,7 @@ void Music_Emu::unload()
|
||||||
Music_Emu::Music_Emu()
|
Music_Emu::Music_Emu()
|
||||||
{
|
{
|
||||||
effects_buffer = 0;
|
effects_buffer = 0;
|
||||||
|
multi_channel_ = false;
|
||||||
sample_rate_ = 0;
|
sample_rate_ = 0;
|
||||||
mute_mask_ = 0;
|
mute_mask_ = 0;
|
||||||
tempo_ = 1.0;
|
tempo_ = 1.0;
|
||||||
|
@ -96,6 +95,25 @@ void Music_Emu::set_equalizer( equalizer_t const& eq )
|
||||||
set_equalizer_( eq );
|
set_equalizer_( eq );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Music_Emu::multi_channel() const
|
||||||
|
{
|
||||||
|
return this->multi_channel_;
|
||||||
|
}
|
||||||
|
|
||||||
|
blargg_err_t Music_Emu::set_multi_channel( bool )
|
||||||
|
{
|
||||||
|
// by default not supported, derived may override this
|
||||||
|
return "unsupported for this emulator type";
|
||||||
|
}
|
||||||
|
|
||||||
|
blargg_err_t Music_Emu::set_multi_channel_( bool isEnabled )
|
||||||
|
{
|
||||||
|
// multi channel support must be set at the very beginning
|
||||||
|
require( !sample_rate() );
|
||||||
|
multi_channel_ = isEnabled;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Music_Emu::mute_voice( int index, bool mute )
|
void Music_Emu::mute_voice( int index, bool mute )
|
||||||
{
|
{
|
||||||
require( (unsigned) index < (unsigned) voice_count() );
|
require( (unsigned) index < (unsigned) voice_count() );
|
||||||
|
@ -145,7 +163,7 @@ blargg_err_t Music_Emu::start_track( int track )
|
||||||
if ( !ignore_silence_ )
|
if ( !ignore_silence_ )
|
||||||
{
|
{
|
||||||
// play until non-silence or end of track
|
// play until non-silence or end of track
|
||||||
for ( long end = max_initial_silence * stereo * sample_rate(); emu_time < end; )
|
for ( long end = max_initial_silence * out_channels() * sample_rate(); emu_time < end; )
|
||||||
{
|
{
|
||||||
fill_buf();
|
fill_buf();
|
||||||
if ( buf_remain | (int) emu_track_ended_ )
|
if ( buf_remain | (int) emu_track_ended_ )
|
||||||
|
@ -175,7 +193,7 @@ blargg_long Music_Emu::msec_to_samples( blargg_long msec ) const
|
||||||
{
|
{
|
||||||
blargg_long sec = msec / 1000;
|
blargg_long sec = msec / 1000;
|
||||||
msec -= sec * 1000;
|
msec -= sec * 1000;
|
||||||
return (sec * sample_rate() + msec * sample_rate() / 1000) * stereo;
|
return (sec * sample_rate() + msec * sample_rate() / 1000) * out_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
long Music_Emu::tell_samples() const
|
long Music_Emu::tell_samples() const
|
||||||
|
@ -185,7 +203,7 @@ long Music_Emu::tell_samples() const
|
||||||
|
|
||||||
long Music_Emu::tell() const
|
long Music_Emu::tell() const
|
||||||
{
|
{
|
||||||
blargg_long rate = sample_rate() * stereo;
|
blargg_long rate = sample_rate() * out_channels();
|
||||||
blargg_long sec = out_time / rate;
|
blargg_long sec = out_time / rate;
|
||||||
return sec * 1000 + (out_time - sec * rate) * 1000 / rate;
|
return sec * 1000 + (out_time - sec * rate) * 1000 / rate;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +281,7 @@ blargg_err_t Music_Emu::skip_( long count )
|
||||||
|
|
||||||
void Music_Emu::set_fade( long start_msec, long length_msec )
|
void Music_Emu::set_fade( long start_msec, long length_msec )
|
||||||
{
|
{
|
||||||
fade_step = sample_rate() * length_msec / (fade_block_size * fade_shift * 1000 / stereo);
|
fade_step = sample_rate() * length_msec / (fade_block_size * fade_shift * 1000 / out_channels());
|
||||||
fade_start = msec_to_samples( start_msec );
|
fade_start = msec_to_samples( start_msec );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +363,7 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
require( current_track() >= 0 );
|
require( current_track() >= 0 );
|
||||||
require( out_count % stereo == 0 );
|
require( out_count % out_channels() == 0 );
|
||||||
|
|
||||||
assert( emu_time >= out_time );
|
assert( emu_time >= out_time );
|
||||||
|
|
||||||
|
@ -357,7 +375,7 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
|
||||||
{
|
{
|
||||||
// during a run of silence, run emulator at >=2x speed so it gets ahead
|
// during a run of silence, run emulator at >=2x speed so it gets ahead
|
||||||
long ahead_time = silence_lookahead * (out_time + out_count - silence_time) + silence_time;
|
long ahead_time = silence_lookahead * (out_time + out_count - silence_time) + silence_time;
|
||||||
while ( emu_time < ahead_time && !(buf_remain || emu_track_ended_) )
|
while ( emu_time < ahead_time && !(buf_remain | emu_track_ended_) )
|
||||||
fill_buf();
|
fill_buf();
|
||||||
|
|
||||||
// fill with silence
|
// fill with silence
|
||||||
|
@ -365,7 +383,7 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
|
||||||
memset( out, 0, pos * sizeof *out );
|
memset( out, 0, pos * sizeof *out );
|
||||||
silence_count -= pos;
|
silence_count -= pos;
|
||||||
|
|
||||||
if ( emu_time - silence_time > silence_max * stereo * sample_rate() )
|
if ( emu_time - silence_time > silence_max * out_channels() * sample_rate() )
|
||||||
{
|
{
|
||||||
track_ended_ = emu_track_ended_ = true;
|
track_ended_ = emu_track_ended_ = true;
|
||||||
silence_count = 0;
|
silence_count = 0;
|
||||||
|
@ -401,7 +419,7 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( out_time > fade_start )
|
if ( fade_start >= 0 && out_time > fade_start )
|
||||||
handle_fade( out_count, out );
|
handle_fade( out_count, out );
|
||||||
}
|
}
|
||||||
out_time += out_count;
|
out_time += out_count;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Common interface to game music file emulators
|
// Common interface to game music file emulators
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef MUSIC_EMU_H
|
#ifndef MUSIC_EMU_H
|
||||||
#define MUSIC_EMU_H
|
#define MUSIC_EMU_H
|
||||||
|
|
||||||
|
@ -14,6 +14,11 @@ public:
|
||||||
// Set output sample rate. Must be called only once before loading file.
|
// Set output sample rate. Must be called only once before loading file.
|
||||||
blargg_err_t set_sample_rate( long sample_rate );
|
blargg_err_t set_sample_rate( long sample_rate );
|
||||||
|
|
||||||
|
// specifies if all 8 voices get rendered to their own stereo channel
|
||||||
|
// default implementation of Music_Emu always returns not supported error (i.e. no multichannel support by default)
|
||||||
|
// derived emus must override this if they support multichannel rendering
|
||||||
|
virtual blargg_err_t set_multi_channel( bool is_enabled );
|
||||||
|
|
||||||
// Start a track, where 0 is the first track. Also clears warning string.
|
// Start a track, where 0 is the first track. Also clears warning string.
|
||||||
blargg_err_t start_track( int );
|
blargg_err_t start_track( int );
|
||||||
|
|
||||||
|
@ -36,6 +41,8 @@ public:
|
||||||
// Names of voices
|
// Names of voices
|
||||||
const char** voice_names() const;
|
const char** voice_names() const;
|
||||||
|
|
||||||
|
bool multi_channel() const;
|
||||||
|
|
||||||
// Track status/control
|
// Track status/control
|
||||||
|
|
||||||
// Number of milliseconds (1000 msec = 1 second) played since beginning of track
|
// Number of milliseconds (1000 msec = 1 second) played since beginning of track
|
||||||
|
@ -127,6 +134,7 @@ protected:
|
||||||
double gain() const { return gain_; }
|
double gain() const { return gain_; }
|
||||||
double tempo() const { return tempo_; }
|
double tempo() const { return tempo_; }
|
||||||
void remute_voices();
|
void remute_voices();
|
||||||
|
blargg_err_t set_multi_channel_( bool is_enabled );
|
||||||
|
|
||||||
virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
|
virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
|
||||||
virtual void set_equalizer_( equalizer_t const& ) { }
|
virtual void set_equalizer_( equalizer_t const& ) { }
|
||||||
|
@ -149,6 +157,10 @@ private:
|
||||||
int mute_mask_;
|
int mute_mask_;
|
||||||
double tempo_;
|
double tempo_;
|
||||||
double gain_;
|
double gain_;
|
||||||
|
bool multi_channel_;
|
||||||
|
|
||||||
|
// returns the number of output channels, i.e. usually 2 for stereo, unlesss multi_channel_ == true
|
||||||
|
int out_channels() const { return this->multi_channel() ? 2*8 : 2; }
|
||||||
|
|
||||||
long sample_rate_;
|
long sample_rate_;
|
||||||
blargg_long msec_to_samples( blargg_long msec ) const;
|
blargg_long msec_to_samples( blargg_long msec ) const;
|
||||||
|
@ -179,7 +191,7 @@ private:
|
||||||
void emu_play( long count, sample_t* out );
|
void emu_play( long count, sample_t* out );
|
||||||
|
|
||||||
Multi_Buffer* effects_buffer;
|
Multi_Buffer* effects_buffer;
|
||||||
friend Music_Emu* gme_new_emu( gme_type_t, int );
|
friend Music_Emu* gme_internal_new_emu_( gme_type_t, int, bool );
|
||||||
friend void gme_set_stereo_depth( Music_Emu*, double );
|
friend void gme_set_stereo_depth( Music_Emu*, double );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Nes_Cpu.h"
|
#include "Nes_Cpu.h"
|
||||||
|
|
||||||
|
@ -114,25 +114,20 @@ void Nes_Cpu::map_code( nes_addr_t start, unsigned size, void const* data, bool
|
||||||
#define GET_SP() ((sp - 1) & 0xFF)
|
#define GET_SP() ((sp - 1) & 0xFF)
|
||||||
#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
|
#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
|
||||||
|
|
||||||
// even on x86, using short and unsigned char was slower
|
|
||||||
typedef int fint16;
|
|
||||||
typedef unsigned fuint16;
|
|
||||||
typedef unsigned fuint8;
|
|
||||||
|
|
||||||
bool Nes_Cpu::run( nes_time_t end_time )
|
bool Nes_Cpu::run( nes_time_t end_time )
|
||||||
{
|
{
|
||||||
set_end_time( end_time );
|
set_end_time( end_time );
|
||||||
state_t s = this->state_;
|
state_t s = this->state_;
|
||||||
this->state = &s;
|
this->state = &s;
|
||||||
// even on x86, using s.time in place of s_time was slower
|
// even on x86, using s.time in place of s_time was slower
|
||||||
fint16 s_time = s.time;
|
int16_t s_time = s.time;
|
||||||
|
|
||||||
// registers
|
// registers
|
||||||
fuint16 pc = r.pc;
|
uint16_t pc = r.pc;
|
||||||
fuint8 a = r.a;
|
uint8_t a = r.a;
|
||||||
fuint8 x = r.x;
|
uint8_t x = r.x;
|
||||||
fuint8 y = r.y;
|
uint8_t y = r.y;
|
||||||
fuint16 sp;
|
uint16_t sp;
|
||||||
SET_SP( r.sp );
|
SET_SP( r.sp );
|
||||||
|
|
||||||
// status flags
|
// status flags
|
||||||
|
@ -152,11 +147,11 @@ bool Nes_Cpu::run( nes_time_t end_time )
|
||||||
nz |= ~in & st_z;\
|
nz |= ~in & st_z;\
|
||||||
} while ( 0 )
|
} while ( 0 )
|
||||||
|
|
||||||
fuint8 status;
|
uint8_t status;
|
||||||
fuint16 c; // carry set if (c & 0x100) != 0
|
uint16_t c; // carry set if (c & 0x100) != 0
|
||||||
fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
||||||
{
|
{
|
||||||
fuint8 temp = r.status;
|
uint8_t temp = r.status;
|
||||||
SET_STATUS( temp );
|
SET_STATUS( temp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +168,7 @@ loop:
|
||||||
check( -32768 <= s_time && s_time < 32767 );
|
check( -32768 <= s_time && s_time < 32767 );
|
||||||
|
|
||||||
uint8_t const* instr = s.code_map [pc >> page_bits];
|
uint8_t const* instr = s.code_map [pc >> page_bits];
|
||||||
fuint8 opcode;
|
uint8_t opcode;
|
||||||
|
|
||||||
// TODO: eliminate this special case
|
// TODO: eliminate this special case
|
||||||
#if BLARGG_NONPORTABLE
|
#if BLARGG_NONPORTABLE
|
||||||
|
@ -206,7 +201,7 @@ loop:
|
||||||
3,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
|
3,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
|
||||||
}; // 0x00 was 7 and 0xF2 was 2
|
}; // 0x00 was 7 and 0xF2 was 2
|
||||||
|
|
||||||
fuint16 data;
|
uint16_t data;
|
||||||
|
|
||||||
#if !BLARGG_CPU_X86
|
#if !BLARGG_CPU_X86
|
||||||
if ( s_time >= 0 )
|
if ( s_time >= 0 )
|
||||||
|
@ -247,13 +242,13 @@ possibly_out_of_time:
|
||||||
#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop;
|
#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop;
|
||||||
|
|
||||||
#define IND_Y( cross, out ) {\
|
#define IND_Y( cross, out ) {\
|
||||||
fuint16 temp = READ_LOW( data ) + y;\
|
uint16_t temp = READ_LOW( data ) + y;\
|
||||||
out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
||||||
cross( temp );\
|
cross( temp );\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IND_X( out ) {\
|
#define IND_X( out ) {\
|
||||||
fuint16 temp = data + x;\
|
uint16_t temp = data + x;\
|
||||||
out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\
|
out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,10 +283,10 @@ imm##op:
|
||||||
// TODO: more efficient way to handle negative branch that wraps PC around
|
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||||
#define BRANCH( cond )\
|
#define BRANCH( cond )\
|
||||||
{\
|
{\
|
||||||
fint16 offset = (BOOST::int8_t) data;\
|
int16_t offset = (int8_t) data;\
|
||||||
fuint16 extra_clock = (++pc & 0xFF) + offset;\
|
uint16_t extra_clock = (++pc & 0xFF) + offset;\
|
||||||
if ( !(cond) ) goto dec_clock_loop;\
|
if ( !(cond) ) goto dec_clock_loop;\
|
||||||
pc = BOOST::uint16_t (pc + offset);\
|
pc = uint16_t (pc + offset);\
|
||||||
s_time += extra_clock >> 8 & 1;\
|
s_time += extra_clock >> 8 & 1;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
}
|
}
|
||||||
|
@ -312,7 +307,7 @@ imm##op:
|
||||||
BRANCH( (uint8_t) nz );
|
BRANCH( (uint8_t) nz );
|
||||||
|
|
||||||
case 0x20: { // JSR
|
case 0x20: { // JSR
|
||||||
fuint16 temp = pc + 1;
|
uint16_t temp = pc + 1;
|
||||||
pc = GET_ADDR();
|
pc = GET_ADDR();
|
||||||
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
||||||
sp = (sp - 2) | 0x100;
|
sp = (sp - 2) | 0x100;
|
||||||
|
@ -378,7 +373,7 @@ imm##op:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
|
|
||||||
case 0x99: // STA abs,Y
|
case 0x99: // STA abs,Y
|
||||||
addr = y + GET_ADDR();
|
addr = y + GET_ADDR();
|
||||||
|
@ -434,7 +429,7 @@ imm##op:
|
||||||
|
|
||||||
// common read instructions
|
// common read instructions
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
|
|
||||||
case 0xA1: // LDA (ind,X)
|
case 0xA1: // LDA (ind,X)
|
||||||
IND_X( addr )
|
IND_X( addr )
|
||||||
|
@ -550,7 +545,7 @@ imm##op:
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
case 0x8C: // STY abs
|
case 0x8C: // STY abs
|
||||||
temp = y;
|
temp = y;
|
||||||
goto store_abs;
|
goto store_abs;
|
||||||
|
@ -659,8 +654,8 @@ imm##op:
|
||||||
|
|
||||||
ARITH_ADDR_MODES( 0x65 ) // ADC
|
ARITH_ADDR_MODES( 0x65 ) // ADC
|
||||||
adc_imm: {
|
adc_imm: {
|
||||||
fint16 carry = c >> 8 & 1;
|
int16_t carry = c >> 8 & 1;
|
||||||
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
|
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
|
||||||
status &= ~st_v;
|
status &= ~st_v;
|
||||||
status |= ov >> 2 & 0x40;
|
status |= ov >> 2 & 0x40;
|
||||||
c = nz = a + data + carry;
|
c = nz = a + data + carry;
|
||||||
|
@ -688,7 +683,7 @@ imm##op:
|
||||||
|
|
||||||
case 0x2A: { // ROL A
|
case 0x2A: { // ROL A
|
||||||
nz = a << 1;
|
nz = a << 1;
|
||||||
fint16 temp = c >> 8 & 1;
|
int16_t temp = c >> 8 & 1;
|
||||||
c = nz;
|
c = nz;
|
||||||
nz |= temp;
|
nz |= temp;
|
||||||
a = (uint8_t) nz;
|
a = (uint8_t) nz;
|
||||||
|
@ -780,7 +775,7 @@ imm##op:
|
||||||
case 0xD6: // DEC zp,x
|
case 0xD6: // DEC zp,x
|
||||||
data = uint8_t (data + x);
|
data = uint8_t (data + x);
|
||||||
case 0xC6: // DEC zp
|
case 0xC6: // DEC zp
|
||||||
nz = (unsigned) -1;
|
nz = (uint16_t) -1;
|
||||||
add_nz_zp:
|
add_nz_zp:
|
||||||
nz += READ_LOW( data );
|
nz += READ_LOW( data );
|
||||||
write_nz_zp:
|
write_nz_zp:
|
||||||
|
@ -805,7 +800,7 @@ imm##op:
|
||||||
case 0xCE: // DEC abs
|
case 0xCE: // DEC abs
|
||||||
data = GET_ADDR();
|
data = GET_ADDR();
|
||||||
dec_ptr:
|
dec_ptr:
|
||||||
nz = (unsigned) -1;
|
nz = (uint16_t) -1;
|
||||||
inc_common:
|
inc_common:
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
nz += READ( data );
|
nz += READ( data );
|
||||||
|
@ -846,7 +841,7 @@ imm##op:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x40:{// RTI
|
case 0x40:{// RTI
|
||||||
fuint8 temp = READ_LOW( sp );
|
uint8_t temp = READ_LOW( sp );
|
||||||
pc = READ_LOW( 0x100 | (sp - 0xFF) );
|
pc = READ_LOW( 0x100 | (sp - 0xFF) );
|
||||||
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
|
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
|
||||||
sp = (sp - 0xFD) | 0x100;
|
sp = (sp - 0xFD) | 0x100;
|
||||||
|
@ -863,9 +858,9 @@ imm##op:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x28:{// PLP
|
case 0x28:{// PLP
|
||||||
fuint8 temp = READ_LOW( sp );
|
uint8_t temp = READ_LOW( sp );
|
||||||
sp = (sp - 0xFF) | 0x100;
|
sp = (sp - 0xFF) | 0x100;
|
||||||
fuint8 changed = status ^ temp;
|
uint8_t changed = status ^ temp;
|
||||||
SET_STATUS( temp );
|
SET_STATUS( temp );
|
||||||
if ( !(changed & st_i) )
|
if ( !(changed & st_i) )
|
||||||
goto loop; // I flag didn't change
|
goto loop; // I flag didn't change
|
||||||
|
@ -875,7 +870,7 @@ imm##op:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x08: { // PHP
|
case 0x08: { // PHP
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
PUSH( temp | (st_b | st_r) );
|
PUSH( temp | (st_b | st_r) );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -897,7 +892,7 @@ imm##op:
|
||||||
// Flags
|
// Flags
|
||||||
|
|
||||||
case 0x38: // SEC
|
case 0x38: // SEC
|
||||||
c = (unsigned) ~0;
|
c = (uint16_t) ~0;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x18: // CLC
|
case 0x18: // CLC
|
||||||
|
@ -983,12 +978,6 @@ imm##op:
|
||||||
|
|
||||||
case bad_opcode: // HLT
|
case bad_opcode: // HLT
|
||||||
pc--;
|
pc--;
|
||||||
if ( pc > 0xFFFF )
|
|
||||||
{
|
|
||||||
// handle wrap-around (assumes caller has put page of HLT at 0x10000)
|
|
||||||
pc &= 0xFFFF;
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52:
|
case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52:
|
||||||
case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2:
|
case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2:
|
||||||
goto stop;
|
goto stop;
|
||||||
|
@ -1003,8 +992,8 @@ imm##op:
|
||||||
static unsigned char const illop_lens [8] = {
|
static unsigned char const illop_lens [8] = {
|
||||||
0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0
|
0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0
|
||||||
};
|
};
|
||||||
fuint8 opcode = instr [-1];
|
uint8_t opcode = instr [-1];
|
||||||
fint16 len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
|
int16_t len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
|
||||||
if ( opcode == 0x9C )
|
if ( opcode == 0x9C )
|
||||||
len = 2;
|
len = 2;
|
||||||
pc += len;
|
pc += len;
|
||||||
|
@ -1035,7 +1024,7 @@ interrupt:
|
||||||
pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ );
|
pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ );
|
||||||
|
|
||||||
sp = (sp - 3) | 0x100;
|
sp = (sp - 3) | 0x100;
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
temp |= st_r;
|
temp |= st_r;
|
||||||
if ( result_ )
|
if ( result_ )
|
||||||
|
@ -1071,7 +1060,7 @@ stop:
|
||||||
r.y = y;
|
r.y = y;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
r.status = temp;
|
r.status = temp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// NES 6502 CPU emulator
|
// NES 6502 CPU emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef NES_CPU_H
|
#ifndef NES_CPU_H
|
||||||
#define NES_CPU_H
|
#define NES_CPU_H
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@ enum { future_nes_time = INT_MAX / 2 + 1 };
|
||||||
|
|
||||||
class Nes_Cpu {
|
class Nes_Cpu {
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
// Clear registers, map low memory and its three mirrors to address 0,
|
// Clear registers, map low memory and its three mirrors to address 0,
|
||||||
// and mirror unmapped_page in remaining memory
|
// and mirror unmapped_page in remaining memory
|
||||||
void reset( void const* unmapped_page = 0 );
|
void reset( void const* unmapped_page = 0 );
|
||||||
|
@ -32,12 +30,12 @@ public:
|
||||||
|
|
||||||
// NES 6502 registers. Not kept updated during a call to run().
|
// NES 6502 registers. Not kept updated during a call to run().
|
||||||
struct registers_t {
|
struct registers_t {
|
||||||
BOOST::uint16_t pc;
|
uint16_t pc;
|
||||||
BOOST::uint8_t a;
|
uint8_t a;
|
||||||
BOOST::uint8_t x;
|
uint8_t x;
|
||||||
BOOST::uint8_t y;
|
uint8_t y;
|
||||||
BOOST::uint8_t status;
|
uint8_t status;
|
||||||
BOOST::uint8_t sp;
|
uint8_t sp;
|
||||||
};
|
};
|
||||||
registers_t r;
|
registers_t r;
|
||||||
|
|
||||||
|
@ -84,7 +82,7 @@ private:
|
||||||
inline int update_end_time( nes_time_t end, nes_time_t irq );
|
inline int update_end_time( nes_time_t end, nes_time_t irq );
|
||||||
};
|
};
|
||||||
|
|
||||||
inline BOOST::uint8_t const* Nes_Cpu::get_code( nes_addr_t addr )
|
inline uint8_t const* Nes_Cpu::get_code( nes_addr_t addr )
|
||||||
{
|
{
|
||||||
return state->code_map [addr >> page_bits] + addr
|
return state->code_map [addr >> page_bits] + addr
|
||||||
#if !BLARGG_NONPORTABLE
|
#if !BLARGG_NONPORTABLE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Nes_Fme7_Apu.h"
|
#include "Nes_Fme7_Apu.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Sunsoft FME-7 sound emulator
|
// Sunsoft FME-7 sound emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef NES_FME7_APU_H
|
#ifndef NES_FME7_APU_H
|
||||||
#define NES_FME7_APU_H
|
#define NES_FME7_APU_H
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@
|
||||||
struct fme7_apu_state_t
|
struct fme7_apu_state_t
|
||||||
{
|
{
|
||||||
enum { reg_count = 14 };
|
enum { reg_count = 14 };
|
||||||
BOOST::uint8_t regs [reg_count];
|
uint8_t regs [reg_count];
|
||||||
BOOST::uint8_t phases [3]; // 0 or 1
|
uint8_t phases [3]; // 0 or 1
|
||||||
BOOST::uint8_t latch;
|
uint8_t latch;
|
||||||
BOOST::uint16_t delays [3]; // a, b, c
|
uint16_t delays [3]; // a, b, c
|
||||||
};
|
};
|
||||||
|
|
||||||
class Nes_Fme7_Apu : private fme7_apu_state_t {
|
class Nes_Fme7_Apu : private fme7_apu_state_t {
|
||||||
|
|
|
@ -90,7 +90,7 @@ void Nes_Namco_Apu::run_until( blip_time_t nes_end_time )
|
||||||
osc.delay = 0;
|
osc.delay = 0;
|
||||||
if ( time < end_time )
|
if ( time < end_time )
|
||||||
{
|
{
|
||||||
const BOOST::uint8_t* osc_reg = ® [i * 8 + 0x40];
|
const uint8_t* osc_reg = ® [i * 8 + 0x40];
|
||||||
if ( !(osc_reg [4] & 0xE0) )
|
if ( !(osc_reg [4] & 0xE0) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -54,24 +54,24 @@ private:
|
||||||
int addr_reg;
|
int addr_reg;
|
||||||
|
|
||||||
enum { reg_count = 0x80 };
|
enum { reg_count = 0x80 };
|
||||||
BOOST::uint8_t reg [reg_count];
|
uint8_t reg [reg_count];
|
||||||
Blip_Synth<blip_good_quality,15> synth;
|
Blip_Synth<blip_good_quality,15> synth;
|
||||||
|
|
||||||
BOOST::uint8_t& access();
|
uint8_t& access();
|
||||||
void run_until( blip_time_t );
|
void run_until( blip_time_t );
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
struct namco_state_t
|
struct namco_state_t
|
||||||
{
|
{
|
||||||
BOOST::uint8_t regs [0x80];
|
uint8_t regs [0x80];
|
||||||
BOOST::uint8_t addr;
|
uint8_t addr;
|
||||||
BOOST::uint8_t unused;
|
uint8_t unused;
|
||||||
BOOST::uint8_t positions [8];
|
uint8_t positions [8];
|
||||||
BOOST::uint32_t delays [8];
|
uint32_t delays [8];
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline BOOST::uint8_t& Nes_Namco_Apu::access()
|
inline uint8_t& Nes_Namco_Apu::access()
|
||||||
{
|
{
|
||||||
int addr = addr_reg & 0x7F;
|
int addr = addr_reg & 0x7F;
|
||||||
if ( addr_reg & 0x80 )
|
if ( addr_reg & 0x80 )
|
||||||
|
|
|
@ -40,7 +40,7 @@ private:
|
||||||
|
|
||||||
struct Vrc6_Osc
|
struct Vrc6_Osc
|
||||||
{
|
{
|
||||||
BOOST::uint8_t regs [3];
|
uint8_t regs [3];
|
||||||
Blip_Buffer* output;
|
Blip_Buffer* output;
|
||||||
int delay;
|
int delay;
|
||||||
int last_amp;
|
int last_amp;
|
||||||
|
@ -66,11 +66,11 @@ private:
|
||||||
|
|
||||||
struct vrc6_apu_state_t
|
struct vrc6_apu_state_t
|
||||||
{
|
{
|
||||||
BOOST::uint8_t regs [3] [3];
|
uint8_t regs [3] [3];
|
||||||
BOOST::uint8_t saw_amp;
|
uint8_t saw_amp;
|
||||||
BOOST::uint16_t delays [3];
|
uint16_t delays [3];
|
||||||
BOOST::uint8_t phases [3];
|
uint8_t phases [3];
|
||||||
BOOST::uint8_t unused;
|
uint8_t unused;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void Nes_Vrc6_Apu::osc_output( int i, Blip_Buffer* buf )
|
inline void Nes_Vrc6_Apu::osc_output( int i, Blip_Buffer* buf )
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Nsf_Emu.h"
|
#include "Nsf_Emu.h"
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; }
|
||||||
static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; }
|
static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_nsf_type_ = { "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 };
|
static gme_type_t_ const gme_nsf_type_ = { "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 };
|
||||||
gme_type_t const gme_nsf_type = &gme_nsf_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_nsf_type = &gme_nsf_type_;
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Nintendo NES/Famicom NSF music file emulator
|
// Nintendo NES/Famicom NSF music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef NSF_EMU_H
|
#ifndef NSF_EMU_H
|
||||||
#define NSF_EMU_H
|
#define NSF_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
|
|
||||||
#include "Nsfe_Emu.h"
|
#include "Nsfe_Emu.h"
|
||||||
|
|
||||||
|
@ -37,7 +35,7 @@ inline void Nsfe_Info::unload()
|
||||||
void Nsfe_Info::disable_playlist( bool b )
|
void Nsfe_Info::disable_playlist( bool b )
|
||||||
{
|
{
|
||||||
playlist_disabled = b;
|
playlist_disabled = b;
|
||||||
info.track_count = (byte)playlist.size();
|
info.track_count = playlist.size();
|
||||||
if ( !info.track_count || playlist_disabled )
|
if ( !info.track_count || playlist_disabled )
|
||||||
info.track_count = actual_track_count_;
|
info.track_count = actual_track_count_;
|
||||||
}
|
}
|
||||||
|
@ -137,6 +135,9 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
|
||||||
blargg_long size = get_le32( block_header [0] );
|
blargg_long size = get_le32( block_header [0] );
|
||||||
blargg_long tag = get_le32( block_header [1] );
|
blargg_long tag = get_le32( block_header [1] );
|
||||||
|
|
||||||
|
if ( size < 0 )
|
||||||
|
return "Corrupt file";
|
||||||
|
|
||||||
//debug_printf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) );
|
//debug_printf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) );
|
||||||
|
|
||||||
switch ( tag )
|
switch ( tag )
|
||||||
|
@ -173,7 +174,7 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
|
||||||
blargg_vector<char> chars;
|
blargg_vector<char> chars;
|
||||||
blargg_vector<const char*> strs;
|
blargg_vector<const char*> strs;
|
||||||
RETURN_ERR( read_strs( in, size, chars, strs ) );
|
RETURN_ERR( read_strs( in, size, chars, strs ) );
|
||||||
int n = (int)strs.size();
|
int n = strs.size();
|
||||||
|
|
||||||
if ( n > 3 )
|
if ( n > 3 )
|
||||||
copy_str( strs [3], info.dumper, sizeof info.dumper );
|
copy_str( strs [3], info.dumper, sizeof info.dumper );
|
||||||
|
@ -192,7 +193,7 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
|
||||||
|
|
||||||
case BLARGG_4CHAR('e','m','i','t'):
|
case BLARGG_4CHAR('e','m','i','t'):
|
||||||
RETURN_ERR( track_times.resize( size / 4 ) );
|
RETURN_ERR( track_times.resize( size / 4 ) );
|
||||||
RETURN_ERR( in.read( track_times.begin(), (long)track_times.size() * 4 ) );
|
RETURN_ERR( in.read( track_times.begin(), track_times.size() * 4 ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLARGG_4CHAR('l','b','l','t'):
|
case BLARGG_4CHAR('l','b','l','t'):
|
||||||
|
@ -242,7 +243,7 @@ blargg_err_t Nsfe_Info::track_info_( track_info_t* out, int track ) const
|
||||||
int remapped = remap_track( track );
|
int remapped = remap_track( track );
|
||||||
if ( (unsigned) remapped < track_times.size() )
|
if ( (unsigned) remapped < track_times.size() )
|
||||||
{
|
{
|
||||||
long length = (BOOST::int32_t) get_le32( track_times [remapped] );
|
long length = (int32_t) get_le32( track_times [remapped] );
|
||||||
if ( length > 0 )
|
if ( length > 0 )
|
||||||
out->length = length;
|
out->length = length;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +301,7 @@ static Music_Emu* new_nsfe_emu () { return BLARGG_NEW Nsfe_Emu ; }
|
||||||
static Music_Emu* new_nsfe_file() { return BLARGG_NEW Nsfe_File; }
|
static Music_Emu* new_nsfe_file() { return BLARGG_NEW Nsfe_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_nsfe_type_ = { "Nintendo NES", 0, &new_nsfe_emu, &new_nsfe_file, "NSFE", 1 };
|
static gme_type_t_ const gme_nsfe_type_ = { "Nintendo NES", 0, &new_nsfe_emu, &new_nsfe_file, "NSFE", 1 };
|
||||||
gme_type_t const gme_nsfe_type = &gme_nsfe_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_nsfe_type = &gme_nsfe_type_;
|
||||||
|
|
||||||
|
|
||||||
blargg_err_t Nsfe_Emu::load_( Data_Reader& in )
|
blargg_err_t Nsfe_Emu::load_( Data_Reader& in )
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Nintendo NES/Famicom NSFE music file emulator
|
// Nintendo NES/Famicom NSFE music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef NSFE_EMU_H
|
#ifndef NSFE_EMU_H
|
||||||
#define NSFE_EMU_H
|
#define NSFE_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Sap_Apu.h"
|
#include "Sap_Apu.h"
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ static void gen_poly( blargg_ulong mask, int count, byte* out )
|
||||||
{
|
{
|
||||||
// implemented using "Galios configuration"
|
// implemented using "Galios configuration"
|
||||||
bits |= (n & 1) << b;
|
bits |= (n & 1) << b;
|
||||||
n = (n >> 1) ^ (mask & (blargg_ulong)-(blargg_long)(n & 1));
|
n = (n >> 1) ^ (mask & -(n & 1));
|
||||||
}
|
}
|
||||||
while ( b++ < 7 );
|
while ( b++ < 7 );
|
||||||
*out++ = bits;
|
*out++ = bits;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Atari POKEY sound chip emulator
|
// Atari POKEY sound chip emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SAP_APU_H
|
#ifndef SAP_APU_H
|
||||||
#define SAP_APU_H
|
#define SAP_APU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Sap_Cpu.h"
|
#include "Sap_Cpu.h"
|
||||||
|
|
||||||
|
@ -68,27 +68,21 @@ void Sap_Cpu::reset( void* new_mem )
|
||||||
#define GET_SP() ((sp - 1) & 0xFF)
|
#define GET_SP() ((sp - 1) & 0xFF)
|
||||||
#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
|
#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v ))
|
||||||
|
|
||||||
// even on x86, using short and unsigned char was slower
|
|
||||||
typedef int fint16;
|
|
||||||
typedef unsigned fuint16;
|
|
||||||
typedef unsigned fuint8;
|
|
||||||
typedef blargg_long fint32;
|
|
||||||
|
|
||||||
bool Sap_Cpu::run( sap_time_t end_time )
|
bool Sap_Cpu::run( sap_time_t end_time )
|
||||||
{
|
{
|
||||||
bool illegal_encountered = false;
|
bool illegal_encountered = false;
|
||||||
set_end_time( end_time );
|
set_end_time( end_time );
|
||||||
state_t s = this->state_;
|
state_t s = this->state_;
|
||||||
this->state = &s;
|
this->state = &s;
|
||||||
fint32 s_time = s.time;
|
int32_t s_time = s.time;
|
||||||
uint8_t* const mem = this->mem; // cache
|
uint8_t* const mem = this->mem; // cache
|
||||||
|
|
||||||
// registers
|
// registers
|
||||||
fuint16 pc = r.pc;
|
uint16_t pc = r.pc;
|
||||||
fuint8 a = r.a;
|
uint8_t a = r.a;
|
||||||
fuint8 x = r.x;
|
uint8_t x = r.x;
|
||||||
fuint8 y = r.y;
|
uint8_t y = r.y;
|
||||||
fuint16 sp;
|
uint16_t sp;
|
||||||
SET_SP( r.sp );
|
SET_SP( r.sp );
|
||||||
|
|
||||||
// status flags
|
// status flags
|
||||||
|
@ -108,11 +102,11 @@ bool Sap_Cpu::run( sap_time_t end_time )
|
||||||
nz |= ~in & st_z;\
|
nz |= ~in & st_z;\
|
||||||
} while ( 0 )
|
} while ( 0 )
|
||||||
|
|
||||||
fuint8 status;
|
uint8_t status;
|
||||||
fuint16 c; // carry set if (c & 0x100) != 0
|
uint16_t c; // carry set if (c & 0x100) != 0
|
||||||
fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
||||||
{
|
{
|
||||||
fuint8 temp = r.status;
|
uint8_t temp = r.status;
|
||||||
SET_STATUS( temp );
|
SET_STATUS( temp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +129,7 @@ loop:
|
||||||
check( (unsigned) x < 0x100 );
|
check( (unsigned) x < 0x100 );
|
||||||
check( (unsigned) y < 0x100 );
|
check( (unsigned) y < 0x100 );
|
||||||
|
|
||||||
fuint8 opcode = mem [pc];
|
uint8_t opcode = mem [pc];
|
||||||
pc++;
|
pc++;
|
||||||
uint8_t const* instr = mem + pc;
|
uint8_t const* instr = mem + pc;
|
||||||
|
|
||||||
|
@ -159,7 +153,7 @@ loop:
|
||||||
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
|
3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F
|
||||||
}; // 0x00 was 7
|
}; // 0x00 was 7
|
||||||
|
|
||||||
fuint16 data;
|
uint16_t data;
|
||||||
data = clock_table [opcode];
|
data = clock_table [opcode];
|
||||||
if ( (s_time += data) >= 0 )
|
if ( (s_time += data) >= 0 )
|
||||||
goto possibly_out_of_time;
|
goto possibly_out_of_time;
|
||||||
|
@ -191,13 +185,13 @@ possibly_out_of_time:
|
||||||
#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop;
|
#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop;
|
||||||
|
|
||||||
#define IND_Y( cross, out ) {\
|
#define IND_Y( cross, out ) {\
|
||||||
fuint16 temp = READ_LOW( data ) + y;\
|
uint16_t temp = READ_LOW( data ) + y;\
|
||||||
out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
||||||
cross( temp );\
|
cross( temp );\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IND_X( out ) {\
|
#define IND_X( out ) {\
|
||||||
fuint16 temp = data + x;\
|
uint16_t temp = data + x;\
|
||||||
out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\
|
out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +226,8 @@ imm##op:
|
||||||
// TODO: more efficient way to handle negative branch that wraps PC around
|
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||||
#define BRANCH( cond )\
|
#define BRANCH( cond )\
|
||||||
{\
|
{\
|
||||||
fint16 offset = (BOOST::int8_t) data;\
|
int16_t offset = (int8_t) data;\
|
||||||
fuint16 extra_clock = (++pc & 0xFF) + offset;\
|
uint16_t extra_clock = (++pc & 0xFF) + offset;\
|
||||||
if ( !(cond) ) goto dec_clock_loop;\
|
if ( !(cond) ) goto dec_clock_loop;\
|
||||||
pc += offset;\
|
pc += offset;\
|
||||||
s_time += extra_clock >> 8 & 1;\
|
s_time += extra_clock >> 8 & 1;\
|
||||||
|
@ -256,7 +250,7 @@ imm##op:
|
||||||
BRANCH( (uint8_t) nz );
|
BRANCH( (uint8_t) nz );
|
||||||
|
|
||||||
case 0x20: { // JSR
|
case 0x20: { // JSR
|
||||||
fuint16 temp = pc + 1;
|
uint16_t temp = pc + 1;
|
||||||
pc = GET_ADDR();
|
pc = GET_ADDR();
|
||||||
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
||||||
sp = (sp - 2) | 0x100;
|
sp = (sp - 2) | 0x100;
|
||||||
|
@ -322,7 +316,7 @@ imm##op:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
|
|
||||||
case 0x99: // STA abs,Y
|
case 0x99: // STA abs,Y
|
||||||
addr = y + GET_ADDR();
|
addr = y + GET_ADDR();
|
||||||
|
@ -378,7 +372,7 @@ imm##op:
|
||||||
|
|
||||||
// common read instructions
|
// common read instructions
|
||||||
{
|
{
|
||||||
fuint16 addr;
|
uint16_t addr;
|
||||||
|
|
||||||
case 0xA1: // LDA (ind,X)
|
case 0xA1: // LDA (ind,X)
|
||||||
IND_X( addr )
|
IND_X( addr )
|
||||||
|
@ -494,7 +488,7 @@ imm##op:
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
case 0x8C: // STY abs
|
case 0x8C: // STY abs
|
||||||
temp = y;
|
temp = y;
|
||||||
goto store_abs;
|
goto store_abs;
|
||||||
|
@ -604,8 +598,8 @@ imm##op:
|
||||||
ARITH_ADDR_MODES( 0x65 ) // ADC
|
ARITH_ADDR_MODES( 0x65 ) // ADC
|
||||||
adc_imm: {
|
adc_imm: {
|
||||||
check( !(status & st_d) );
|
check( !(status & st_d) );
|
||||||
fint16 carry = c >> 8 & 1;
|
int16_t carry = c >> 8 & 1;
|
||||||
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
|
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
|
||||||
status &= ~st_v;
|
status &= ~st_v;
|
||||||
status |= ov >> 2 & 0x40;
|
status |= ov >> 2 & 0x40;
|
||||||
c = nz = a + data + carry;
|
c = nz = a + data + carry;
|
||||||
|
@ -633,7 +627,7 @@ imm##op:
|
||||||
|
|
||||||
case 0x2A: { // ROL A
|
case 0x2A: { // ROL A
|
||||||
nz = a << 1;
|
nz = a << 1;
|
||||||
fint16 temp = c >> 8 & 1;
|
int16_t temp = c >> 8 & 1;
|
||||||
c = nz;
|
c = nz;
|
||||||
nz |= temp;
|
nz |= temp;
|
||||||
a = (uint8_t) nz;
|
a = (uint8_t) nz;
|
||||||
|
@ -725,7 +719,7 @@ imm##op:
|
||||||
case 0xD6: // DEC zp,x
|
case 0xD6: // DEC zp,x
|
||||||
data = uint8_t (data + x);
|
data = uint8_t (data + x);
|
||||||
case 0xC6: // DEC zp
|
case 0xC6: // DEC zp
|
||||||
nz = (unsigned) -1;
|
nz = (uint16_t) -1;
|
||||||
add_nz_zp:
|
add_nz_zp:
|
||||||
nz += READ_LOW( data );
|
nz += READ_LOW( data );
|
||||||
write_nz_zp:
|
write_nz_zp:
|
||||||
|
@ -750,7 +744,7 @@ imm##op:
|
||||||
case 0xCE: // DEC abs
|
case 0xCE: // DEC abs
|
||||||
data = GET_ADDR();
|
data = GET_ADDR();
|
||||||
dec_ptr:
|
dec_ptr:
|
||||||
nz = (unsigned) -1;
|
nz = (uint16_t) -1;
|
||||||
inc_common:
|
inc_common:
|
||||||
FLUSH_TIME();
|
FLUSH_TIME();
|
||||||
nz += READ( data );
|
nz += READ( data );
|
||||||
|
@ -791,7 +785,7 @@ imm##op:
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x40:{// RTI
|
case 0x40:{// RTI
|
||||||
fuint8 temp = READ_LOW( sp );
|
uint8_t temp = READ_LOW( sp );
|
||||||
pc = READ_LOW( 0x100 | (sp - 0xFF) );
|
pc = READ_LOW( 0x100 | (sp - 0xFF) );
|
||||||
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
|
pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100;
|
||||||
sp = (sp - 0xFD) | 0x100;
|
sp = (sp - 0xFD) | 0x100;
|
||||||
|
@ -811,9 +805,9 @@ imm##op:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x28:{// PLP
|
case 0x28:{// PLP
|
||||||
fuint8 temp = READ_LOW( sp );
|
uint8_t temp = READ_LOW( sp );
|
||||||
sp = (sp - 0xFF) | 0x100;
|
sp = (sp - 0xFF) | 0x100;
|
||||||
fuint8 changed = status ^ temp;
|
uint8_t changed = status ^ temp;
|
||||||
SET_STATUS( temp );
|
SET_STATUS( temp );
|
||||||
if ( !(changed & st_i) )
|
if ( !(changed & st_i) )
|
||||||
goto loop; // I flag didn't change
|
goto loop; // I flag didn't change
|
||||||
|
@ -823,7 +817,7 @@ imm##op:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x08: { // PHP
|
case 0x08: { // PHP
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
PUSH( temp | (st_b | st_r) );
|
PUSH( temp | (st_b | st_r) );
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -843,7 +837,7 @@ imm##op:
|
||||||
// Flags
|
// Flags
|
||||||
|
|
||||||
case 0x38: // SEC
|
case 0x38: // SEC
|
||||||
c = (unsigned) ~0;
|
c = (uint16_t) ~0;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0x18: // CLC
|
case 0x18: // CLC
|
||||||
|
@ -932,7 +926,6 @@ imm##op:
|
||||||
//case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
|
//case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert( (unsigned) opcode <= 0xFF );
|
|
||||||
illegal_encountered = true;
|
illegal_encountered = true;
|
||||||
pc--;
|
pc--;
|
||||||
goto stop;
|
goto stop;
|
||||||
|
@ -956,7 +949,7 @@ interrupt:
|
||||||
pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ );
|
pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ );
|
||||||
|
|
||||||
sp = (sp - 3) | 0x100;
|
sp = (sp - 3) | 0x100;
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
temp |= st_r;
|
temp |= st_r;
|
||||||
if ( result_ )
|
if ( result_ )
|
||||||
|
@ -998,7 +991,7 @@ stop:
|
||||||
r.y = y;
|
r.y = y;
|
||||||
|
|
||||||
{
|
{
|
||||||
fuint8 temp;
|
uint8_t temp;
|
||||||
CALC_STATUS( temp );
|
CALC_STATUS( temp );
|
||||||
r.status = temp;
|
r.status = temp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Atari 6502 CPU emulator
|
// Atari 6502 CPU emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SAP_CPU_H
|
#ifndef SAP_CPU_H
|
||||||
#define SAP_CPU_H
|
#define SAP_CPU_H
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@ enum { future_sap_time = INT_MAX / 2 + 1 };
|
||||||
|
|
||||||
class Sap_Cpu {
|
class Sap_Cpu {
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
// Clear all registers and keep pointer to 64K memory passed in
|
// Clear all registers and keep pointer to 64K memory passed in
|
||||||
void reset( void* mem_64k );
|
void reset( void* mem_64k );
|
||||||
|
|
||||||
|
@ -23,12 +21,12 @@ public:
|
||||||
|
|
||||||
// Registers are not updated until run() returns (except I flag in status)
|
// Registers are not updated until run() returns (except I flag in status)
|
||||||
struct registers_t {
|
struct registers_t {
|
||||||
BOOST::uint16_t pc;
|
uint16_t pc;
|
||||||
BOOST::uint8_t a;
|
uint8_t a;
|
||||||
BOOST::uint8_t x;
|
uint8_t x;
|
||||||
BOOST::uint8_t y;
|
uint8_t y;
|
||||||
BOOST::uint8_t status;
|
uint8_t status;
|
||||||
BOOST::uint8_t sp;
|
uint8_t sp;
|
||||||
};
|
};
|
||||||
registers_t r;
|
registers_t r;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Sap_Emu.h"
|
#include "Sap_Emu.h"
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ static blargg_err_t parse_info( byte const* in, long size, Sap_Emu::info_t* out
|
||||||
char const* tag = (char const*) in;
|
char const* tag = (char const*) in;
|
||||||
while ( in < line_end && *in > ' ' )
|
while ( in < line_end && *in > ' ' )
|
||||||
in++;
|
in++;
|
||||||
int tag_len = int((char const*) in - tag);
|
int tag_len = (char const*) in - tag;
|
||||||
|
|
||||||
while ( in < line_end && *in <= ' ' ) in++;
|
while ( in < line_end && *in <= ' ' ) in++;
|
||||||
|
|
||||||
|
@ -236,8 +236,7 @@ static Music_Emu* new_sap_emu () { return BLARGG_NEW Sap_Emu ; }
|
||||||
static Music_Emu* new_sap_file() { return BLARGG_NEW Sap_File; }
|
static Music_Emu* new_sap_file() { return BLARGG_NEW Sap_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_sap_type_ = { "Atari XL", 0, &new_sap_emu, &new_sap_file, "SAP", 1 };
|
static gme_type_t_ const gme_sap_type_ = { "Atari XL", 0, &new_sap_emu, &new_sap_file, "SAP", 1 };
|
||||||
gme_type_t const gme_sap_type = &gme_sap_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_sap_type = &gme_sap_type_;
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
||||||
|
@ -256,7 +255,7 @@ blargg_err_t Sap_Emu::load_mem_( byte const* in, long size )
|
||||||
|
|
||||||
set_warning( info.warning );
|
set_warning( info.warning );
|
||||||
set_track_count( info.track_count );
|
set_track_count( info.track_count );
|
||||||
set_voice_count( Sap_Apu::osc_count << (int)info.stereo );
|
set_voice_count( Sap_Apu::osc_count << info.stereo );
|
||||||
apu_impl.volume( gain() );
|
apu_impl.volume( gain() );
|
||||||
|
|
||||||
return setup_buffer( 1773447 );
|
return setup_buffer( 1773447 );
|
||||||
|
@ -315,8 +314,8 @@ inline void Sap_Emu::call_init( int track )
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
r.a = 0x70;
|
r.a = 0x70;
|
||||||
r.x = (BOOST::uint8_t)(info.music_addr&0xFF);
|
r.x = info.music_addr&0xFF;
|
||||||
r.y = (BOOST::uint8_t)(info.music_addr >> 8);
|
r.y = info.music_addr >> 8;
|
||||||
run_routine( info.play_addr + 3 );
|
run_routine( info.play_addr + 3 );
|
||||||
r.a = 0;
|
r.a = 0;
|
||||||
r.x = track;
|
r.x = track;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Atari XL/XE SAP music file emulator
|
// Atari XL/XE SAP music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SAP_EMU_H
|
#ifndef SAP_EMU_H
|
||||||
#define SAP_EMU_H
|
#define SAP_EMU_H
|
||||||
|
|
||||||
|
@ -54,8 +54,7 @@ private:
|
||||||
// large items
|
// large items
|
||||||
struct {
|
struct {
|
||||||
byte padding1 [0x100];
|
byte padding1 [0x100];
|
||||||
byte ram [0x10000];
|
byte ram [0x10000 + 0x100];
|
||||||
byte padding2 [0x100];
|
|
||||||
} mem;
|
} mem;
|
||||||
Sap_Apu_Impl apu_impl;
|
Sap_Apu_Impl apu_impl;
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ void Sms_Noise::run( blip_time_t time, blip_time_t end_time )
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int changed = shifter + 1;
|
int changed = shifter + 1;
|
||||||
shifter = (feedback & (unsigned)-(signed)(shifter & 1)) ^ (shifter >> 1);
|
shifter = (feedback & -(shifter & 1)) ^ (shifter >> 1);
|
||||||
if ( changed & 2 ) // true if bits 0 and 1 differ
|
if ( changed & 2 ) // true if bits 0 and 1 differ
|
||||||
{
|
{
|
||||||
delta = -delta;
|
delta = -delta;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPC emulation support: init, sample buffering, reset, SPC loading
|
// SPC emulation support: init, sample buffering, reset, SPC loading
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Snes_Spc.h"
|
#include "Snes_Spc.h"
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void Snes_Spc::ram_loaded()
|
||||||
|
|
||||||
// Put STOP instruction around memory to catch PC underflow/overflow
|
// Put STOP instruction around memory to catch PC underflow/overflow
|
||||||
memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
|
memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
|
||||||
memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 );
|
memset( m.ram.ram + 0x10000, cpu_pad_fill, sizeof m.ram.padding1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registers were just loaded. Applies these new values.
|
// Registers were just loaded. Applies these new values.
|
||||||
|
@ -303,7 +303,7 @@ void Snes_Spc::set_output( sample_t* out, int size )
|
||||||
assert( out <= out_end );
|
assert( out <= out_end );
|
||||||
}
|
}
|
||||||
|
|
||||||
dsp.set_output( out, int(out_end - out) );
|
dsp.set_output( out, out_end - out );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
// SNES SPC-700 APU emulator
|
// SNES SPC-700 APU emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SNES_SPC_H
|
#ifndef SNES_SPC_H
|
||||||
#define SNES_SPC_H
|
#define SNES_SPC_H
|
||||||
|
|
||||||
#include "Spc_Dsp.h"
|
#include "Spc_Dsp.h"
|
||||||
#include "blargg_endian.h"
|
#include "blargg_endian.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
struct Snes_Spc {
|
struct Snes_Spc {
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
// Must be called once before using
|
// Must be called once before using
|
||||||
blargg_err_t init();
|
blargg_err_t init();
|
||||||
|
|
||||||
|
@ -108,12 +108,12 @@ public:
|
||||||
// TODO: document
|
// TODO: document
|
||||||
struct regs_t
|
struct regs_t
|
||||||
{
|
{
|
||||||
int pc;
|
uint16_t pc;
|
||||||
int a;
|
uint8_t a;
|
||||||
int x;
|
uint8_t x;
|
||||||
int y;
|
uint8_t y;
|
||||||
int psw;
|
uint8_t psw;
|
||||||
int sp;
|
uint8_t sp;
|
||||||
};
|
};
|
||||||
regs_t& smp_regs() { return m.cpu_regs; }
|
regs_t& smp_regs() { return m.cpu_regs; }
|
||||||
|
|
||||||
|
@ -123,8 +123,6 @@ public:
|
||||||
public:
|
public:
|
||||||
BLARGG_DISABLE_NOTHROW
|
BLARGG_DISABLE_NOTHROW
|
||||||
|
|
||||||
typedef BOOST::uint16_t uint16_t;
|
|
||||||
|
|
||||||
// Time relative to m_spc_time. Speeds up code a bit by eliminating need to
|
// Time relative to m_spc_time. Speeds up code a bit by eliminating need to
|
||||||
// constantly add m_spc_time to time from CPU. CPU uses time that ends at
|
// constantly add m_spc_time to time from CPU. CPU uses time that ends at
|
||||||
// 0 to eliminate reloading end time every instruction. It pays off.
|
// 0 to eliminate reloading end time every instruction. It pays off.
|
||||||
|
@ -184,13 +182,11 @@ private:
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
// padding to neutralize address overflow
|
// padding to neutralize address overflow -- but this is
|
||||||
union {
|
// still undefined behavior! TODO: remove and instead properly
|
||||||
|
// guard usage of emulated memory
|
||||||
uint8_t padding1 [0x100];
|
uint8_t padding1 [0x100];
|
||||||
uint16_t align; // makes compiler align data for 16-bit access
|
alignas(uint16_t) uint8_t ram [0x10000 + 0x100];
|
||||||
} padding1 [1];
|
|
||||||
uint8_t ram [0x10000];
|
|
||||||
uint8_t padding2 [0x100];
|
|
||||||
} ram;
|
} ram;
|
||||||
};
|
};
|
||||||
state_t m;
|
state_t m;
|
||||||
|
@ -226,13 +222,13 @@ private:
|
||||||
Timer* run_timer ( Timer* t, rel_time_t );
|
Timer* run_timer ( Timer* t, rel_time_t );
|
||||||
int dsp_read ( rel_time_t );
|
int dsp_read ( rel_time_t );
|
||||||
void dsp_write ( int data, rel_time_t );
|
void dsp_write ( int data, rel_time_t );
|
||||||
void cpu_write_smp_reg_( int data, rel_time_t, int addr );
|
void cpu_write_smp_reg_( int data, rel_time_t, uint16_t addr );
|
||||||
void cpu_write_smp_reg ( int data, rel_time_t, int addr );
|
void cpu_write_smp_reg ( int data, rel_time_t, uint16_t addr );
|
||||||
void cpu_write_high ( int data, int i, rel_time_t );
|
void cpu_write_high ( int data, uint8_t i );
|
||||||
void cpu_write ( int data, int addr, rel_time_t );
|
void cpu_write ( int data, uint16_t addr, rel_time_t );
|
||||||
int cpu_read_smp_reg ( int i, rel_time_t );
|
int cpu_read_smp_reg ( int i, rel_time_t );
|
||||||
int cpu_read ( int addr, rel_time_t );
|
int cpu_read ( uint16_t addr, rel_time_t );
|
||||||
unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t );
|
unsigned CPU_mem_bit ( uint16_t pc, rel_time_t );
|
||||||
|
|
||||||
bool check_echo_access ( int addr );
|
bool check_echo_access ( int addr );
|
||||||
uint8_t* run_until_( time_t end_time );
|
uint8_t* run_until_( time_t end_time );
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Core SPC emulation: CPU, timers, SMP registers, memory
|
// Core SPC emulation: CPU, timers, SMP registers, memory
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Snes_Spc.h"
|
#include "Snes_Spc.h"
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ static unsigned char const glitch_probs [3] [256] =
|
||||||
// If write isn't preceded by read, data has this added to it
|
// If write isn't preceded by read, data has this added to it
|
||||||
int const no_read_before_write = 0x2000;
|
int const no_read_before_write = 0x2000;
|
||||||
|
|
||||||
void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
|
void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, uint16_t addr )
|
||||||
{
|
{
|
||||||
switch ( addr )
|
switch ( addr )
|
||||||
{
|
{
|
||||||
|
@ -385,7 +385,7 @@ void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Snes_Spc::cpu_write_smp_reg( int data, rel_time_t time, int addr )
|
void Snes_Spc::cpu_write_smp_reg( int data, rel_time_t time, uint16_t addr )
|
||||||
{
|
{
|
||||||
if ( addr == r_dspdata ) // 99%
|
if ( addr == r_dspdata ) // 99%
|
||||||
dsp_write( data, time );
|
dsp_write( data, time );
|
||||||
|
@ -393,33 +393,23 @@ void Snes_Spc::cpu_write_smp_reg( int data, rel_time_t time, int addr )
|
||||||
cpu_write_smp_reg_( data, time, addr );
|
cpu_write_smp_reg_( data, time, addr );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Snes_Spc::cpu_write_high( int data, int i, rel_time_t time )
|
void Snes_Spc::cpu_write_high( int data, uint8_t i )
|
||||||
{
|
|
||||||
if ( i < rom_size )
|
|
||||||
{
|
{
|
||||||
|
assert ( i < rom_size );
|
||||||
m.hi_ram [i] = (uint8_t) data;
|
m.hi_ram [i] = (uint8_t) data;
|
||||||
if ( m.rom_enabled )
|
if ( m.rom_enabled )
|
||||||
RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
|
RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
assert( RAM [i + rom_addr] == (uint8_t) data );
|
|
||||||
RAM [i + rom_addr] = cpu_pad_fill; // restore overwritten padding
|
|
||||||
cpu_write( data, i + rom_addr - 0x10000, time );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int const bits_in_int = CHAR_BIT * sizeof (int);
|
void Snes_Spc::cpu_write( int data, uint16_t addr, rel_time_t time )
|
||||||
|
|
||||||
void Snes_Spc::cpu_write( int data, int addr, rel_time_t time )
|
|
||||||
{
|
{
|
||||||
MEM_ACCESS( time, addr )
|
MEM_ACCESS( time, addr )
|
||||||
|
|
||||||
// RAM
|
// RAM
|
||||||
RAM [addr] = (uint8_t) data;
|
RAM [addr] = (uint8_t) data;
|
||||||
int reg = addr - 0xF0;
|
if ( addr >= 0xF0 ) // 64%
|
||||||
if ( reg >= 0 ) // 64%
|
|
||||||
{
|
{
|
||||||
|
const uint16_t reg = addr - 0xF0;
|
||||||
// $F0-$FF
|
// $F0-$FF
|
||||||
if ( reg < reg_count ) // 87%
|
if ( reg < reg_count ) // 87%
|
||||||
{
|
{
|
||||||
|
@ -437,12 +427,8 @@ void Snes_Spc::cpu_write( int data, int addr, rel_time_t time )
|
||||||
cpu_write_smp_reg( data, time, reg );
|
cpu_write_smp_reg( data, time, reg );
|
||||||
}
|
}
|
||||||
// High mem/address wrap-around
|
// High mem/address wrap-around
|
||||||
else
|
else if ( addr >= rom_addr ) // 1% in IPL ROM area or address wrapped around
|
||||||
{
|
cpu_write_high( data, addr - rom_addr );
|
||||||
reg -= rom_addr - 0xF0;
|
|
||||||
if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around
|
|
||||||
cpu_write_high( data, reg, time );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,7 +449,7 @@ inline int Snes_Spc::cpu_read_smp_reg( int reg, rel_time_t time )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Snes_Spc::cpu_read( int addr, rel_time_t time )
|
int Snes_Spc::cpu_read( uint16_t addr, rel_time_t time )
|
||||||
{
|
{
|
||||||
MEM_ACCESS( time, addr )
|
MEM_ACCESS( time, addr )
|
||||||
|
|
||||||
|
@ -507,7 +493,7 @@ int Snes_Spc::cpu_read( int addr, rel_time_t time )
|
||||||
|
|
||||||
// Prefix and suffix for CPU emulator function
|
// Prefix and suffix for CPU emulator function
|
||||||
#define SPC_CPU_RUN_FUNC \
|
#define SPC_CPU_RUN_FUNC \
|
||||||
BOOST::uint8_t* Snes_Spc::run_until_( time_t end_time )\
|
uint8_t* Snes_Spc::run_until_( time_t end_time )\
|
||||||
{\
|
{\
|
||||||
rel_time_t rel_time = m.spc_time - end_time;\
|
rel_time_t rel_time = m.spc_time - end_time;\
|
||||||
assert( rel_time <= 0 );\
|
assert( rel_time <= 0 );\
|
||||||
|
@ -527,7 +513,7 @@ BOOST::uint8_t* Snes_Spc::run_until_( time_t end_time )\
|
||||||
return ®S [r_cpuio0];\
|
return ®S [r_cpuio0];\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define cpu_lag_max (12 - 1) // DIV YA,X takes 12 clocks
|
int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks
|
||||||
|
|
||||||
void Snes_Spc::end_frame( time_t end_time )
|
void Snes_Spc::end_frame( time_t end_time )
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
|
/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
|
||||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||||
|
@ -66,62 +66,37 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )
|
#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )
|
||||||
#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )
|
#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )
|
||||||
|
|
||||||
#define READ_PROG16( addr ) GET_LE16( ram + (addr) )
|
#define READ_PROG16( addr ) (RAM [(addr) & 0xffff] | (RAM [((addr) + 1) & 0xffff] << 8))
|
||||||
|
|
||||||
#define SET_PC( n ) (pc = ram + (n))
|
#define SET_PC( n ) (pc = n)
|
||||||
#define GET_PC() (int(pc - ram))
|
#define GET_PC() (pc)
|
||||||
#define READ_PC( pc ) (*(pc))
|
#define READ_PC( pc ) (ram [pc])
|
||||||
#define READ_PC16( pc ) GET_LE16( pc )
|
#define READ_PC16( pc ) READ_PROG16( pc )
|
||||||
|
|
||||||
// TODO: remove non-wrapping versions?
|
#define SET_SP( v ) (sp = v)
|
||||||
#define SPC_NO_SP_WRAPAROUND 0
|
#define GET_SP() ((uint8_t) (sp))
|
||||||
|
|
||||||
#define SET_SP( v ) (sp = ram + 0x101 + ((uint8_t) v))
|
|
||||||
#define GET_SP() (uint8_t (sp - 0x101 - ram))
|
|
||||||
|
|
||||||
#if SPC_NO_SP_WRAPAROUND
|
|
||||||
#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))
|
|
||||||
#define PUSH( v ) (void) (*--sp = (uint8_t) (v))
|
|
||||||
#define POP( out ) (void) ((out) = *sp++)
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define PUSH16( data )\
|
#define PUSH16( data )\
|
||||||
{\
|
{\
|
||||||
int addr = int((sp -= 2) - ram);\
|
PUSH( (data & 0xff00) >> 8 );\
|
||||||
if ( addr > 0x100 )\
|
PUSH( data & 0xff );\
|
||||||
{\
|
|
||||||
SET_LE16( sp, data );\
|
|
||||||
}\
|
|
||||||
else\
|
|
||||||
{\
|
|
||||||
ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
|
|
||||||
sp [1] = (uint8_t) (data >> 8);\
|
|
||||||
sp += 0x100;\
|
|
||||||
}\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PUSH( data )\
|
#define PUSH( data )\
|
||||||
{\
|
{\
|
||||||
*--sp = (uint8_t) (data);\
|
ram [0x100 + sp] = (uint8_t) (data);\
|
||||||
if ( sp - ram == 0x100 )\
|
--sp;\
|
||||||
sp += 0x100;\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define POP( out )\
|
#define POP( out )\
|
||||||
{\
|
{\
|
||||||
out = *sp++;\
|
++sp;\
|
||||||
if ( sp - ram == 0x201 )\
|
out = ram [0x100 + sp];\
|
||||||
{\
|
|
||||||
out = sp [-0x101];\
|
|
||||||
sp -= 0x100;\
|
|
||||||
}\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
|
#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
|
||||||
|
|
||||||
unsigned Snes_Spc::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time )
|
unsigned Snes_Spc::CPU_mem_bit( uint16_t pc, rel_time_t rel_time )
|
||||||
{
|
{
|
||||||
unsigned addr = READ_PC16( pc );
|
unsigned addr = READ_PC16( pc );
|
||||||
unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
|
unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
|
||||||
|
@ -163,11 +138,11 @@ int const nz_neg_mask = 0x880; // either bit set indicates N flag set
|
||||||
SPC_CPU_RUN_FUNC
|
SPC_CPU_RUN_FUNC
|
||||||
{
|
{
|
||||||
uint8_t* const ram = RAM;
|
uint8_t* const ram = RAM;
|
||||||
int a = m.cpu_regs.a;
|
uint8_t a = m.cpu_regs.a;
|
||||||
int x = m.cpu_regs.x;
|
uint8_t x = m.cpu_regs.x;
|
||||||
int y = m.cpu_regs.y;
|
uint8_t y = m.cpu_regs.y;
|
||||||
uint8_t const* pc;
|
uint16_t pc;
|
||||||
uint8_t* sp;
|
uint8_t sp;
|
||||||
int psw;
|
int psw;
|
||||||
int c;
|
int c;
|
||||||
int nz;
|
int nz;
|
||||||
|
@ -183,7 +158,7 @@ SPC_CPU_RUN_FUNC
|
||||||
// Main loop
|
// Main loop
|
||||||
|
|
||||||
cbranch_taken_loop:
|
cbranch_taken_loop:
|
||||||
pc += *(BOOST::int8_t const*) pc;
|
pc += (int8_t) ram [pc];
|
||||||
inc_pc_loop:
|
inc_pc_loop:
|
||||||
pc++;
|
pc++;
|
||||||
loop:
|
loop:
|
||||||
|
@ -195,7 +170,7 @@ loop:
|
||||||
check( (unsigned) x < 0x100 );
|
check( (unsigned) x < 0x100 );
|
||||||
check( (unsigned) y < 0x100 );
|
check( (unsigned) y < 0x100 );
|
||||||
|
|
||||||
opcode = *pc;
|
opcode = ram [pc];
|
||||||
if ( (rel_time += m.cycle_table [opcode]) > 0 )
|
if ( (rel_time += m.cycle_table [opcode]) > 0 )
|
||||||
goto out_of_time;
|
goto out_of_time;
|
||||||
|
|
||||||
|
@ -218,7 +193,8 @@ loop:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
|
// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
|
||||||
data = *++pc;
|
pc++;
|
||||||
|
data = ram [pc];
|
||||||
switch ( opcode )
|
switch ( opcode )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -227,10 +203,10 @@ loop:
|
||||||
#define BRANCH( cond )\
|
#define BRANCH( cond )\
|
||||||
{\
|
{\
|
||||||
pc++;\
|
pc++;\
|
||||||
pc += (BOOST::int8_t) data;\
|
pc += (int8_t) data;\
|
||||||
if ( cond )\
|
if ( cond )\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
pc -= (BOOST::int8_t) data;\
|
pc -= (int8_t) data;\
|
||||||
rel_time -= 2;\
|
rel_time -= 2;\
|
||||||
goto loop;\
|
goto loop;\
|
||||||
}
|
}
|
||||||
|
@ -249,23 +225,12 @@ loop:
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x6F:// RET
|
case 0x6F:// RET
|
||||||
#if SPC_NO_SP_WRAPAROUND
|
|
||||||
{
|
{
|
||||||
SET_PC( GET_LE16( sp ) );
|
uint8_t l, h;
|
||||||
sp += 2;
|
POP( l );
|
||||||
|
POP( h );
|
||||||
|
SET_PC( l | (h << 8) );
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
{
|
|
||||||
int addr = int(sp - ram);
|
|
||||||
SET_PC( GET_LE16( sp ) );
|
|
||||||
sp += 2;
|
|
||||||
if ( addr < 0x1FF )
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] );
|
|
||||||
sp -= 0x100;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xE4: // MOV a,dp
|
case 0xE4: // MOV a,dp
|
||||||
|
@ -294,8 +259,7 @@ loop:
|
||||||
REGS [i] = (uint8_t) data;
|
REGS [i] = (uint8_t) data;
|
||||||
|
|
||||||
// Registers other than $F2 and $F4-$F7
|
// Registers other than $F2 and $F4-$F7
|
||||||
//if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 )
|
if ( i != 2 && (i < 4 || i > 7)) // 12%
|
||||||
if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12%
|
|
||||||
cpu_write_smp_reg( data, rel_time, i );
|
cpu_write_smp_reg( data, rel_time, i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,7 +468,7 @@ loop:
|
||||||
case op + 0x01: /* dp,dp */\
|
case op + 0x01: /* dp,dp */\
|
||||||
data = READ_DP( -3, data );\
|
data = READ_DP( -3, data );\
|
||||||
case op + 0x10:{/*dp,imm*/\
|
case op + 0x10:{/*dp,imm*/\
|
||||||
uint8_t const* addr2 = pc + 1;\
|
uint16_t addr2 = pc + 1;\
|
||||||
pc += 2;\
|
pc += 2;\
|
||||||
addr = READ_PC( addr2 ) + dp;\
|
addr = READ_PC( addr2 ) + dp;\
|
||||||
}\
|
}\
|
||||||
|
@ -878,7 +842,7 @@ loop:
|
||||||
// 12. BRANCHING COMMANDS
|
// 12. BRANCHING COMMANDS
|
||||||
|
|
||||||
case 0x2F: // BRA rel
|
case 0x2F: // BRA rel
|
||||||
pc += (BOOST::int8_t) data;
|
pc += (int8_t) data;
|
||||||
goto inc_pc_loop;
|
goto inc_pc_loop;
|
||||||
|
|
||||||
case 0x30: // BMI
|
case 0x30: // BMI
|
||||||
|
@ -1002,10 +966,12 @@ loop:
|
||||||
|
|
||||||
{
|
{
|
||||||
int temp;
|
int temp;
|
||||||
|
uint8_t l, h;
|
||||||
case 0x7F: // RET1
|
case 0x7F: // RET1
|
||||||
temp = *sp;
|
POP (temp);
|
||||||
SET_PC( GET_LE16( sp + 1 ) );
|
POP (l);
|
||||||
SET_SP(GET_SP() + 3);
|
POP (h);
|
||||||
|
SET_PC( l | (h << 8) );
|
||||||
goto set_psw;
|
goto set_psw;
|
||||||
case 0x8E: // POP PSW
|
case 0x8E: // POP PSW
|
||||||
POP( temp );
|
POP( temp );
|
||||||
|
@ -1180,11 +1146,8 @@ loop:
|
||||||
|
|
||||||
case 0xFF:{// STOP
|
case 0xFF:{// STOP
|
||||||
// handle PC wrap-around
|
// handle PC wrap-around
|
||||||
unsigned addr = GET_PC() - 1;
|
if ( pc == 0x0000 )
|
||||||
if ( addr >= 0x10000 )
|
|
||||||
{
|
{
|
||||||
addr &= 0xFFFF;
|
|
||||||
SET_PC( addr );
|
|
||||||
debug_printf( "SPC: PC wrapped around\n" );
|
debug_printf( "SPC: PC wrapped around\n" );
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
@ -1201,12 +1164,10 @@ loop:
|
||||||
assert( 0 ); // catch any unhandled instructions
|
assert( 0 ); // catch any unhandled instructions
|
||||||
}
|
}
|
||||||
out_of_time:
|
out_of_time:
|
||||||
rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode
|
rel_time -= m.cycle_table [ ram [pc] ]; // undo partial execution of opcode
|
||||||
stop:
|
stop:
|
||||||
|
|
||||||
// Uncache registers
|
// Uncache registers
|
||||||
if ( GET_PC() >= 0x10000 )
|
|
||||||
debug_printf( "SPC: PC wrapped around\n" );
|
|
||||||
m.cpu_regs.pc = (uint16_t) GET_PC();
|
m.cpu_regs.pc = (uint16_t) GET_PC();
|
||||||
m.cpu_regs.sp = ( uint8_t) GET_SP();
|
m.cpu_regs.sp = ( uint8_t) GET_SP();
|
||||||
m.cpu_regs.a = ( uint8_t) a;
|
m.cpu_regs.a = ( uint8_t) a;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Spc_Dsp.h"
|
#include "Spc_Dsp.h"
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||||
|
|
||||||
|
|
||||||
// TODO: add to blargg_endian.h
|
// TODO: add to blargg_endian.h
|
||||||
#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr ))
|
#define GET_LE16SA( addr ) ((int16_t) GET_LE16( addr ))
|
||||||
#define GET_LE16A( addr ) GET_LE16( addr )
|
#define GET_LE16A( addr ) GET_LE16( addr )
|
||||||
#define SET_LE16A( addr, data ) SET_LE16( addr, data )
|
#define SET_LE16A( addr, data ) SET_LE16( addr, data )
|
||||||
|
|
||||||
static BOOST::uint8_t const initial_regs [Spc_Dsp::register_count] =
|
static uint8_t const initial_regs [Spc_Dsp::register_count] =
|
||||||
{
|
{
|
||||||
0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
|
0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80,
|
||||||
0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
|
0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF,
|
||||||
|
@ -155,7 +155,7 @@ inline void Spc_Dsp::init_counter()
|
||||||
// counters start out with this synchronization
|
// counters start out with this synchronization
|
||||||
m.counters [0] = 1;
|
m.counters [0] = 1;
|
||||||
m.counters [1] = 0;
|
m.counters [1] = 0;
|
||||||
m.counters [2] = -0x20;
|
m.counters [2] = -0x20u;
|
||||||
m.counters [3] = 0x0B;
|
m.counters [3] = 0x0B;
|
||||||
|
|
||||||
int n = 2;
|
int n = 2;
|
||||||
|
@ -498,8 +498,9 @@ void Spc_Dsp::run( int clock_count )
|
||||||
// Decode four samples
|
// Decode four samples
|
||||||
for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
|
for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
|
||||||
{
|
{
|
||||||
// Extract upper nybble and scale appropriately
|
// Extract upper nybble and scale appropriately. Every cast is
|
||||||
int s = ((int16_t) nybbles >> right_shift) << left_shift;
|
// necessary to maintain correctness and avoid undef behavior
|
||||||
|
int s = int16_t(uint16_t((int16_t) nybbles >> right_shift) << left_shift);
|
||||||
|
|
||||||
// Apply IIR filter (8 is the most commonly used)
|
// Apply IIR filter (8 is the most commonly used)
|
||||||
int const filter = brr_header & 0x0C;
|
int const filter = brr_header & 0x0C;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one)
|
// Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one)
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SPC_DSP_H
|
#ifndef SPC_DSP_H
|
||||||
#define SPC_DSP_H
|
#define SPC_DSP_H
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
struct Spc_Dsp {
|
struct Spc_Dsp {
|
||||||
public:
|
public:
|
||||||
typedef BOOST::uint8_t uint8_t;
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
|
||||||
// Initializes DSP and has it use the 64K RAM provided
|
// Initializes DSP and has it use the 64K RAM provided
|
||||||
|
@ -89,9 +87,6 @@ public:
|
||||||
public:
|
public:
|
||||||
BLARGG_DISABLE_NOTHROW
|
BLARGG_DISABLE_NOTHROW
|
||||||
|
|
||||||
typedef BOOST::int8_t int8_t;
|
|
||||||
typedef BOOST::int16_t int16_t;
|
|
||||||
|
|
||||||
enum { echo_hist_size = 8 };
|
enum { echo_hist_size = 8 };
|
||||||
|
|
||||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||||
|
@ -154,7 +149,7 @@ private:
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
inline int Spc_Dsp::sample_count() const { return int(m.out - m.out_begin); }
|
inline int Spc_Dsp::sample_count() const { return m.out - m.out_begin; }
|
||||||
|
|
||||||
inline int Spc_Dsp::read( int addr ) const
|
inline int Spc_Dsp::read( int addr ) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Spc_Emu.h"
|
#include "Spc_Emu.h"
|
||||||
|
|
||||||
|
@ -228,14 +228,14 @@ struct Spc_File : Gme_Info_
|
||||||
{
|
{
|
||||||
RETURN_ERR( xid6.resize( xid6_size ) );
|
RETURN_ERR( xid6.resize( xid6_size ) );
|
||||||
RETURN_ERR( in.skip( xid6_offset - Spc_Emu::header_size ) );
|
RETURN_ERR( in.skip( xid6_offset - Spc_Emu::header_size ) );
|
||||||
RETURN_ERR( in.read( xid6.begin(), (long)xid6.size() ) );
|
RETURN_ERR( in.read( xid6.begin(), xid6.size() ) );
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
blargg_err_t track_info_( track_info_t* out, int ) const
|
blargg_err_t track_info_( track_info_t* out, int ) const
|
||||||
{
|
{
|
||||||
get_spc_info( header, xid6.begin(), (long)xid6.size(), out );
|
get_spc_info( header, xid6.begin(), xid6.size(), out );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -244,7 +244,7 @@ static Music_Emu* new_spc_emu () { return BLARGG_NEW Spc_Emu ; }
|
||||||
static Music_Emu* new_spc_file() { return BLARGG_NEW Spc_File; }
|
static Music_Emu* new_spc_file() { return BLARGG_NEW Spc_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_spc_type_ = { "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 };
|
static gme_type_t_ const gme_spc_type_ = { "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 };
|
||||||
gme_type_t const gme_spc_type = &gme_spc_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_spc_type = &gme_spc_type_;
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
@ -299,6 +299,11 @@ blargg_err_t Spc_Emu::start_track_( int track )
|
||||||
RETURN_ERR( apu.load_spc( file_data, file_size ) );
|
RETURN_ERR( apu.load_spc( file_data, file_size ) );
|
||||||
filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) );
|
filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) );
|
||||||
apu.clear_echo();
|
apu.clear_echo();
|
||||||
|
track_info_t spc_info;
|
||||||
|
RETURN_ERR( track_info_( &spc_info, track ) );
|
||||||
|
// Set a default track length, need a non-zero fadeout
|
||||||
|
if ( spc_info.length > 0 )
|
||||||
|
set_fade ( spc_info.length, 50 );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Super Nintendo SPC music file emulator
|
// Super Nintendo SPC music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SPC_EMU_H
|
#ifndef SPC_EMU_H
|
||||||
#define SPC_EMU_H
|
#define SPC_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Spc_Filter.h"
|
#include "Spc_Filter.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Simple low-pass and high-pass filter to better match sound output of a SNES
|
// Simple low-pass and high-pass filter to better match sound output of a SNES
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef SPC_FILTER_H
|
#ifndef SPC_FILTER_H
|
||||||
#define SPC_FILTER_H
|
#define SPC_FILTER_H
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Vgm_Emu.h"
|
#include "Vgm_Emu.h"
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ static byte const* skip_gd3_str( byte const* in, byte const* end )
|
||||||
static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
|
static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
|
||||||
{
|
{
|
||||||
byte const* mid = skip_gd3_str( in, end );
|
byte const* mid = skip_gd3_str( in, end );
|
||||||
int len = int(mid - in) / 2 - 1;
|
int len = (mid - in) / 2 - 1;
|
||||||
if ( len > 0 )
|
if ( len > 0 )
|
||||||
{
|
{
|
||||||
len = min( len, (int) Gme_File::max_field_ );
|
len = min( len, (int) Gme_File::max_field_ );
|
||||||
|
@ -108,7 +108,7 @@ byte const* Vgm_Emu::gd3_data( int* size ) const
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
byte const* gd3 = data + header_size + gd3_offset;
|
byte const* gd3 = data + header_size + gd3_offset;
|
||||||
long gd3_size = check_gd3_header( gd3, long(data_end - gd3) );
|
long gd3_size = check_gd3_header( gd3, data_end - gd3 );
|
||||||
if ( !gd3_size )
|
if ( !gd3_size )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ struct Vgm_File : Gme_Info_
|
||||||
if ( gd3_size )
|
if ( gd3_size )
|
||||||
{
|
{
|
||||||
RETURN_ERR( gd3.resize( gd3_size ) );
|
RETURN_ERR( gd3.resize( gd3_size ) );
|
||||||
RETURN_ERR( in.read( gd3.begin(), (long)gd3.size() ) );
|
RETURN_ERR( in.read( gd3.begin(), gd3.size() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -203,10 +203,10 @@ static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; }
|
||||||
static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; }
|
static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; }
|
||||||
|
|
||||||
static gme_type_t_ const gme_vgm_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 1 };
|
static gme_type_t_ const gme_vgm_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 1 };
|
||||||
gme_type_t const gme_vgm_type = &gme_vgm_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_vgm_type = &gme_vgm_type_;
|
||||||
|
|
||||||
static gme_type_t_ const gme_vgz_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 1 };
|
static gme_type_t_ const gme_vgz_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 1 };
|
||||||
gme_type_t const gme_vgz_type = &gme_vgz_type_;
|
BLARGG_EXPORT extern gme_type_t const gme_vgz_type = &gme_vgz_type_;
|
||||||
|
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
@ -233,6 +233,25 @@ blargg_err_t Vgm_Emu::set_sample_rate_( long sample_rate )
|
||||||
return Classic_Emu::set_sample_rate_( sample_rate );
|
return Classic_Emu::set_sample_rate_( sample_rate );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blargg_err_t Vgm_Emu::set_multi_channel ( bool is_enabled )
|
||||||
|
{
|
||||||
|
// we acutally should check here whether this is classic emu or not
|
||||||
|
// however set_multi_channel() is called before setup_fm() resulting in uninited is_classic_emu()
|
||||||
|
// hard code it to unsupported
|
||||||
|
#if 0
|
||||||
|
if ( is_classic_emu() )
|
||||||
|
{
|
||||||
|
RETURN_ERR( Music_Emu::set_multi_channel_( is_enabled ) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
(void) is_enabled;
|
||||||
|
return "multichannel rendering not supported for YM2*** FM sound chip emulators";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Vgm_Emu::update_eq( blip_eq_t const& eq )
|
void Vgm_Emu::update_eq( blip_eq_t const& eq )
|
||||||
{
|
{
|
||||||
psg.treble_eq( eq );
|
psg.treble_eq( eq );
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator
|
// Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef VGM_EMU_H
|
#ifndef VGM_EMU_H
|
||||||
#define VGM_EMU_H
|
#define VGM_EMU_H
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ public:
|
||||||
// TODO: move into Music_Emu and rename to something like supports_custom_buffer()
|
// TODO: move into Music_Emu and rename to something like supports_custom_buffer()
|
||||||
bool is_classic_emu() const { return !uses_fm; }
|
bool is_classic_emu() const { return !uses_fm; }
|
||||||
|
|
||||||
|
blargg_err_t set_multi_channel ( bool is_enabled ) override;
|
||||||
|
|
||||||
// Disable running FM chips at higher than normal rate. Will result in slightly
|
// Disable running FM chips at higher than normal rate. Will result in slightly
|
||||||
// more aliasing of high notes.
|
// more aliasing of high notes.
|
||||||
void disable_oversampling( bool disable = true ) { disable_oversampling_ = disable; }
|
void disable_oversampling( bool disable = true ) { disable_oversampling_ = disable; }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Vgm_Emu.h"
|
#include "Vgm_Emu.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Low-level parts of Vgm_Emu
|
// Low-level parts of Vgm_Emu
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef VGM_EMU_IMPL_H
|
#ifndef VGM_EMU_IMPL_H
|
||||||
#define VGM_EMU_IMPL_H
|
#define VGM_EMU_IMPL_H
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
// Use in place of Ym2413_Emu.cpp and ym2413.c to disable support for this chip
|
// Use in place of Ym2413_Emu.cpp and ym2413.c to disable support for this chip
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Ym2413_Emu.h"
|
#include "Ym2413_Emu.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// YM2413 FM sound chip emulator interface
|
// YM2413 FM sound chip emulator interface
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef YM2413_EMU_H
|
#ifndef YM2413_EMU_H
|
||||||
#define YM2413_EMU_H
|
#define YM2413_EMU_H
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,19 @@
|
||||||
// YM2612 FM sound chip emulator interface
|
// YM2612 FM sound chip emulator interface
|
||||||
|
|
||||||
// Game_Music_Emu 0.6.0
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
#ifndef YM2612_EMU_H
|
|
||||||
#define YM2612_EMU_H
|
|
||||||
|
|
||||||
struct Ym2612_Impl;
|
|
||||||
|
|
||||||
class Ym2612_Emu {
|
|
||||||
Ym2612_Impl* impl;
|
|
||||||
public:
|
|
||||||
Ym2612_Emu() { impl = 0; }
|
|
||||||
~Ym2612_Emu();
|
|
||||||
|
|
||||||
// Set output sample rate and chip clock rates, in Hz. Returns non-zero
|
|
||||||
// if error.
|
|
||||||
const char* set_rate( double sample_rate, double clock_rate );
|
|
||||||
|
|
||||||
// Reset to power-up state
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
// Mute voice n if bit n (1 << n) of mask is set
|
|
||||||
enum { channel_count = 6 };
|
|
||||||
void mute_voices( int mask );
|
|
||||||
|
|
||||||
// Write addr to register 0 then data to register 1
|
|
||||||
void write0( int addr, int data );
|
|
||||||
|
|
||||||
// Write addr to register 2 then data to register 3
|
|
||||||
void write1( int addr, int data );
|
|
||||||
|
|
||||||
// Run and add pair_count samples into current output buffer contents
|
|
||||||
typedef short sample_t;
|
|
||||||
enum { out_chan_count = 2 }; // stereo
|
|
||||||
void run( int pair_count, sample_t* out );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
#ifdef VGM_YM2612_GENS // LGPL v2.1+ license
|
||||||
|
#include "Ym2612_GENS.h"
|
||||||
|
typedef Ym2612_GENS_Emu Ym2612_Emu;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef VGM_YM2612_NUKED // LGPL v2.1+ license
|
||||||
|
#include "Ym2612_Nuked.h"
|
||||||
|
typedef Ym2612_Nuked_Emu Ym2612_Emu;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VGM_YM2612_MAME // GPL v2+ license
|
||||||
|
#include "Ym2612_MAME.h"
|
||||||
|
typedef Ym2612_MAME_Emu Ym2612_Emu;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
// Based on Gens 2.10 ym2612.c
|
// Based on Gens 2.10 ym2612.c
|
||||||
|
|
||||||
#include "Ym2612_Emu.h"
|
#include "Ym2612_GENS.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
/* Copyright (C) 2002 Stephane Dallongeville (gens AT consolemul.com) */
|
/* Copyright (C) 2002 Stéphane Dallongeville (gens AT consolemul.com) */
|
||||||
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
|
/* Copyright (C) 2004-2006 Shay Green. This module is free software; you
|
||||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
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
|
General Public License as published by the Free Software Foundation; either
|
||||||
|
@ -44,9 +44,9 @@ struct slot_t
|
||||||
int MUL; // parametre "multiple de frequence"
|
int MUL; // parametre "multiple de frequence"
|
||||||
int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
|
int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
|
||||||
int TLL; // Total Level ajusted
|
int TLL; // Total Level ajusted
|
||||||
int SLL; // Sustin Level (ajusted) = volume o・l'enveloppe termine sa premiere phase de regression
|
int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa premiere phase de regression
|
||||||
int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
|
int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
|
||||||
int KSR; // Key Scale Rate = cette valeur est calculee par rapport ・la frequence actuelle, elle va influer
|
int KSR; // Key Scale Rate = cette valeur est calculee par rapport à la frequence actuelle, elle va influer
|
||||||
// sur les differents parametres de l'enveloppe comme l'attaque, le decay ... comme dans la realite !
|
// sur les differents parametres de l'enveloppe comme l'attaque, le decay ... comme dans la realite !
|
||||||
int SEG; // Type enveloppe SSG
|
int SEG; // Type enveloppe SSG
|
||||||
int env_xor;
|
int env_xor;
|
||||||
|
@ -58,24 +58,24 @@ struct slot_t
|
||||||
const int *RR; // Release Rate (table pointeur) = Taux pour le rel'chement (RR[KSR])
|
const int *RR; // Release Rate (table pointeur) = Taux pour le rel'chement (RR[KSR])
|
||||||
int Fcnt; // Frequency Count = compteur-frequence pour determiner l'amplitude actuelle (SIN[Finc >> 16])
|
int Fcnt; // Frequency Count = compteur-frequence pour determiner l'amplitude actuelle (SIN[Finc >> 16])
|
||||||
int Finc; // frequency step = pas d'incrementation du compteur-frequence
|
int Finc; // frequency step = pas d'incrementation du compteur-frequence
|
||||||
// plus le pas est grand, plus la frequence est a・u (ou haute)
|
// plus le pas est grand, plus la frequence est aïgu (ou haute)
|
||||||
int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase
|
int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase
|
||||||
// de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
|
// de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
|
||||||
// en fonction de la valeur de cette variable, on va appeler une fonction permettant
|
// en fonction de la valeur de cette variable, on va appeler une fonction permettant
|
||||||
// de mettre ・jour l'enveloppe courante.
|
// de mettre à jour l'enveloppe courante.
|
||||||
int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir o・l'on se trouve dans l'enveloppe
|
int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe
|
||||||
int Einc; // Envelope step courant
|
int Einc; // Envelope step courant
|
||||||
int Ecmp; // Envelope counter limite pour la prochaine phase
|
int Ecmp; // Envelope counter limite pour la prochaine phase
|
||||||
int EincA; // Envelope step for Attack = pas d'incrementation du compteur durant la phase d'attaque
|
int EincA; // Envelope step for Attack = pas d'incrementation du compteur durant la phase d'attaque
|
||||||
// cette valeur est egal ・AR[KSR]
|
// cette valeur est egal à AR[KSR]
|
||||||
int EincD; // Envelope step for Decay = pas d'incrementation du compteur durant la phase de regression
|
int EincD; // Envelope step for Decay = pas d'incrementation du compteur durant la phase de regression
|
||||||
// cette valeur est egal ・DR[KSR]
|
// cette valeur est egal à DR[KSR]
|
||||||
int EincS; // Envelope step for Sustain = pas d'incrementation du compteur durant la phase de maintenue
|
int EincS; // Envelope step for Sustain = pas d'incrementation du compteur durant la phase de maintenue
|
||||||
// cette valeur est egal ・SR[KSR]
|
// cette valeur est egal à SR[KSR]
|
||||||
int EincR; // Envelope step for Release = pas d'incrementation du compteur durant la phase de rel'chement
|
int EincR; // Envelope step for Release = pas d'incrementation du compteur durant la phase de rel'chement
|
||||||
// cette valeur est egal ・RR[KSR]
|
// cette valeur est egal à RR[KSR]
|
||||||
int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot ・l'entree
|
int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entree
|
||||||
// d'un autre ou carrement ・la sortie de la voie
|
// d'un autre ou carrement à la sortie de la voie
|
||||||
int INd; // input data of the slot = donnees en entree du slot
|
int INd; // input data of the slot = donnees en entree du slot
|
||||||
int ChgEnM; // Change envelop mask.
|
int ChgEnM; // Change envelop mask.
|
||||||
int AMS; // AMS depth level of this SLOT = degre de modulation de l'amplitude par le LFO
|
int AMS; // AMS depth level of this SLOT = degre de modulation de l'amplitude par le LFO
|
||||||
|
@ -102,15 +102,15 @@ struct state_t
|
||||||
{
|
{
|
||||||
int TimerBase; // TimerBase calculation
|
int TimerBase; // TimerBase calculation
|
||||||
int Status; // YM2612 Status (timer overflow)
|
int Status; // YM2612 Status (timer overflow)
|
||||||
int TimerA; // timerA limit = valeur jusqu'・laquelle le timer A doit compter
|
int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter
|
||||||
int TimerAL;
|
int TimerAL;
|
||||||
int TimerAcnt; // timerA counter = valeur courante du Timer A
|
int TimerAcnt; // timerA counter = valeur courante du Timer A
|
||||||
int TimerB; // timerB limit = valeur jusqu'・laquelle le timer B doit compter
|
int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter
|
||||||
int TimerBL;
|
int TimerBL;
|
||||||
int TimerBcnt; // timerB counter = valeur courante du Timer B
|
int TimerBcnt; // timerB counter = valeur courante du Timer B
|
||||||
int Mode; // Mode actuel des voie 3 et 6 (normal / special)
|
int Mode; // Mode actuel des voie 3 et 6 (normal / special)
|
||||||
int DAC; // DAC enabled flag
|
int DAC; // DAC enabled flag
|
||||||
channel_t CHANNEL[Ym2612_Emu::channel_count]; // Les 6 voies du YM2612
|
channel_t CHANNEL[Ym2612_GENS_Emu::channel_count]; // Les 6 voies du YM2612
|
||||||
int REG[2][0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif
|
int REG[2][0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif
|
||||||
// cela nous rend le debuggage plus facile
|
// cela nous rend le debuggage plus facile
|
||||||
};
|
};
|
||||||
|
@ -255,9 +255,9 @@ static const unsigned char LFO_FMS_TAB [8] =
|
||||||
|
|
||||||
inline void YM2612_Special_Update() { }
|
inline void YM2612_Special_Update() { }
|
||||||
|
|
||||||
struct Ym2612_Impl
|
struct Ym2612_GENS_Impl
|
||||||
{
|
{
|
||||||
enum { channel_count = Ym2612_Emu::channel_count };
|
enum { channel_count = Ym2612_GENS_Emu::channel_count };
|
||||||
|
|
||||||
state_t YM2612;
|
state_t YM2612;
|
||||||
int mute_mask;
|
int mute_mask;
|
||||||
|
@ -274,10 +274,10 @@ struct Ym2612_Impl
|
||||||
void write0( int addr, int data );
|
void write0( int addr, int data );
|
||||||
void write1( int addr, int data );
|
void write1( int addr, int data );
|
||||||
void run_timer( int );
|
void run_timer( int );
|
||||||
void run( int pair_count, Ym2612_Emu::sample_t* );
|
void run( int pair_count, Ym2612_GENS_Emu::sample_t* );
|
||||||
};
|
};
|
||||||
|
|
||||||
void Ym2612_Impl::KEY_ON( channel_t& ch, int nsl)
|
void Ym2612_GENS_Impl::KEY_ON( channel_t& ch, int nsl)
|
||||||
{
|
{
|
||||||
slot_t *SL = &(ch.SLOT [nsl]); // on recupere le bon pointeur de slot
|
slot_t *SL = &(ch.SLOT [nsl]); // on recupere le bon pointeur de slot
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ void Ym2612_Impl::KEY_ON( channel_t& ch, int nsl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ym2612_Impl::KEY_OFF(channel_t& ch, int nsl)
|
void Ym2612_GENS_Impl::KEY_OFF(channel_t& ch, int nsl)
|
||||||
{
|
{
|
||||||
slot_t *SL = &(ch.SLOT [nsl]); // on recupere le bon pointeur de slot
|
slot_t *SL = &(ch.SLOT [nsl]); // on recupere le bon pointeur de slot
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ void Ym2612_Impl::KEY_OFF(channel_t& ch, int nsl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Ym2612_Impl::SLOT_SET( int Adr, int data )
|
int Ym2612_GENS_Impl::SLOT_SET( int Adr, int data )
|
||||||
{
|
{
|
||||||
int nch = Adr & 3;
|
int nch = Adr & 3;
|
||||||
if ( nch == 3 )
|
if ( nch == 3 )
|
||||||
|
@ -420,7 +420,7 @@ int Ym2612_Impl::SLOT_SET( int Adr, int data )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Ym2612_Impl::CHANNEL_SET( int Adr, int data )
|
int Ym2612_GENS_Impl::CHANNEL_SET( int Adr, int data )
|
||||||
{
|
{
|
||||||
int num = Adr & 3;
|
int num = Adr & 3;
|
||||||
if ( num == 3 )
|
if ( num == 3 )
|
||||||
|
@ -522,7 +522,7 @@ int Ym2612_Impl::CHANNEL_SET( int Adr, int data )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Ym2612_Impl::YM_SET(int Adr, int data)
|
int Ym2612_GENS_Impl::YM_SET(int Adr, int data)
|
||||||
{
|
{
|
||||||
switch ( Adr )
|
switch ( Adr )
|
||||||
{
|
{
|
||||||
|
@ -628,7 +628,7 @@ int Ym2612_Impl::YM_SET(int Adr, int data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
void Ym2612_GENS_Impl::set_rate( double sample_rate, double clock_rate )
|
||||||
{
|
{
|
||||||
assert( sample_rate );
|
assert( sample_rate );
|
||||||
assert( clock_rate > sample_rate );
|
assert( clock_rate > sample_rate );
|
||||||
|
@ -824,11 +824,11 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Ym2612_Emu::set_rate( double sample_rate, double clock_rate )
|
const char* Ym2612_GENS_Emu::set_rate( double sample_rate, double clock_rate )
|
||||||
{
|
{
|
||||||
if ( !impl )
|
if ( !impl )
|
||||||
{
|
{
|
||||||
impl = (Ym2612_Impl*) malloc( sizeof *impl );
|
impl = (Ym2612_GENS_Impl*) malloc( sizeof *impl );
|
||||||
if ( !impl )
|
if ( !impl )
|
||||||
return "Out of memory";
|
return "Out of memory";
|
||||||
impl->mute_mask = 0;
|
impl->mute_mask = 0;
|
||||||
|
@ -840,12 +840,12 @@ const char* Ym2612_Emu::set_rate( double sample_rate, double clock_rate )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ym2612_Emu::~Ym2612_Emu()
|
Ym2612_GENS_Emu::~Ym2612_GENS_Emu()
|
||||||
{
|
{
|
||||||
free( impl );
|
free( impl );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Ym2612_Impl::write0( int opn_addr, int data )
|
inline void Ym2612_GENS_Impl::write0( int opn_addr, int data )
|
||||||
{
|
{
|
||||||
assert( (unsigned) data <= 0xFF );
|
assert( (unsigned) data <= 0xFF );
|
||||||
|
|
||||||
|
@ -865,7 +865,7 @@ inline void Ym2612_Impl::write0( int opn_addr, int data )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Ym2612_Impl::write1( int opn_addr, int data )
|
inline void Ym2612_GENS_Impl::write1( int opn_addr, int data )
|
||||||
{
|
{
|
||||||
assert( (unsigned) data <= 0xFF );
|
assert( (unsigned) data <= 0xFF );
|
||||||
|
|
||||||
|
@ -880,12 +880,12 @@ inline void Ym2612_Impl::write1( int opn_addr, int data )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Emu::reset()
|
void Ym2612_GENS_Emu::reset()
|
||||||
{
|
{
|
||||||
impl->reset();
|
impl->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Impl::reset()
|
void Ym2612_GENS_Impl::reset()
|
||||||
{
|
{
|
||||||
g.LFOcnt = 0;
|
g.LFOcnt = 0;
|
||||||
YM2612.TimerA = 0;
|
YM2612.TimerA = 0;
|
||||||
|
@ -949,17 +949,17 @@ void Ym2612_Impl::reset()
|
||||||
write0( 0x2A, 0x80 );
|
write0( 0x2A, 0x80 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Emu::write0( int addr, int data )
|
void Ym2612_GENS_Emu::write0( int addr, int data )
|
||||||
{
|
{
|
||||||
impl->write0( addr, data );
|
impl->write0( addr, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Emu::write1( int addr, int data )
|
void Ym2612_GENS_Emu::write1( int addr, int data )
|
||||||
{
|
{
|
||||||
impl->write1( addr, data );
|
impl->write1( addr, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Emu::mute_voices( int mask ) { impl->mute_mask = mask; }
|
void Ym2612_GENS_Emu::mute_voices( int mask ) { impl->mute_mask = mask; }
|
||||||
|
|
||||||
static void update_envelope_( slot_t* sl )
|
static void update_envelope_( slot_t* sl )
|
||||||
{
|
{
|
||||||
|
@ -1033,14 +1033,14 @@ inline void update_envelope( slot_t& sl )
|
||||||
|
|
||||||
template<int algo>
|
template<int algo>
|
||||||
struct ym2612_update_chan {
|
struct ym2612_update_chan {
|
||||||
static void func( tables_t&, channel_t&, Ym2612_Emu::sample_t*, int );
|
static void func( tables_t&, channel_t&, Ym2612_GENS_Emu::sample_t*, int );
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*ym2612_update_chan_t)( tables_t&, channel_t&, Ym2612_Emu::sample_t*, int );
|
typedef void (*ym2612_update_chan_t)( tables_t&, channel_t&, Ym2612_GENS_Emu::sample_t*, int );
|
||||||
|
|
||||||
template<int algo>
|
template<int algo>
|
||||||
void ym2612_update_chan<algo>::func( tables_t& g, channel_t& ch,
|
void ym2612_update_chan<algo>::func( tables_t& g, channel_t& ch,
|
||||||
Ym2612_Emu::sample_t* buf, int length )
|
Ym2612_GENS_Emu::sample_t* buf, int length )
|
||||||
{
|
{
|
||||||
int not_end = ch.SLOT [S3].Ecnt - ENV_END;
|
int not_end = ch.SLOT [S3].Ecnt - ENV_END;
|
||||||
|
|
||||||
|
@ -1201,7 +1201,7 @@ static const ym2612_update_chan_t UPDATE_CHAN [8] = {
|
||||||
&ym2612_update_chan<7>::func
|
&ym2612_update_chan<7>::func
|
||||||
};
|
};
|
||||||
|
|
||||||
void Ym2612_Impl::run_timer( int length )
|
void Ym2612_GENS_Impl::run_timer( int length )
|
||||||
{
|
{
|
||||||
int const step = 6;
|
int const step = 6;
|
||||||
int remain = length;
|
int remain = length;
|
||||||
|
@ -1247,7 +1247,7 @@ void Ym2612_Impl::run_timer( int length )
|
||||||
while ( remain > 0 );
|
while ( remain > 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Impl::run( int pair_count, Ym2612_Emu::sample_t* out )
|
void Ym2612_GENS_Impl::run( int pair_count, Ym2612_GENS_Emu::sample_t* out )
|
||||||
{
|
{
|
||||||
if ( pair_count <= 0 )
|
if ( pair_count <= 0 )
|
||||||
return;
|
return;
|
||||||
|
@ -1255,7 +1255,7 @@ void Ym2612_Impl::run( int pair_count, Ym2612_Emu::sample_t* out )
|
||||||
if ( YM2612.Mode & 3 )
|
if ( YM2612.Mode & 3 )
|
||||||
run_timer( pair_count );
|
run_timer( pair_count );
|
||||||
|
|
||||||
// Mise ・jour des pas des compteurs-frequences s'ils ont ete modifies
|
// Mise à jour des pas des compteurs-frequences s'ils ont ete modifies
|
||||||
|
|
||||||
for ( int chi = 0; chi < channel_count; chi++ )
|
for ( int chi = 0; chi < channel_count; chi++ )
|
||||||
{
|
{
|
||||||
|
@ -1277,7 +1277,7 @@ void Ym2612_Impl::run( int pair_count, Ym2612_Emu::sample_t* out )
|
||||||
int ksr = ch.KC [i2] >> sl.KSR_S; // keycode attenuation
|
int ksr = ch.KC [i2] >> sl.KSR_S; // keycode attenuation
|
||||||
sl.Finc = (finc + sl.DT [ch.KC [i2]]) * sl.MUL;
|
sl.Finc = (finc + sl.DT [ch.KC [i2]]) * sl.MUL;
|
||||||
if (sl.KSR != ksr) // si le KSR a change alors
|
if (sl.KSR != ksr) // si le KSR a change alors
|
||||||
{ // les differents taux pour l'enveloppe sont mis ・jour
|
{ // les differents taux pour l'enveloppe sont mis à jour
|
||||||
sl.KSR = ksr;
|
sl.KSR = ksr;
|
||||||
|
|
||||||
sl.EincA = sl.AR [ksr];
|
sl.EincA = sl.AR [ksr];
|
||||||
|
@ -1316,4 +1316,4 @@ void Ym2612_Impl::run( int pair_count, Ym2612_Emu::sample_t* out )
|
||||||
g.LFOcnt += g.LFOinc * pair_count;
|
g.LFOcnt += g.LFOinc * pair_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ym2612_Emu::run( int pair_count, sample_t* out ) { impl->run( pair_count, out ); }
|
void Ym2612_GENS_Emu::run( int pair_count, sample_t* out ) { impl->run( pair_count, out ); }
|
38
game-music-emu/gme/Ym2612_GENS.h
Normal file
38
game-music-emu/gme/Ym2612_GENS.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// YM2612 FM sound chip emulator interface
|
||||||
|
|
||||||
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
#ifndef YM2612_EMU_H
|
||||||
|
#define YM2612_EMU_H
|
||||||
|
|
||||||
|
struct Ym2612_GENS_Impl;
|
||||||
|
|
||||||
|
class Ym2612_GENS_Emu {
|
||||||
|
Ym2612_GENS_Impl* impl;
|
||||||
|
public:
|
||||||
|
Ym2612_GENS_Emu() { impl = 0; }
|
||||||
|
~Ym2612_GENS_Emu();
|
||||||
|
|
||||||
|
// Set output sample rate and chip clock rates, in Hz. Returns non-zero
|
||||||
|
// if error.
|
||||||
|
const char* set_rate( double sample_rate, double clock_rate );
|
||||||
|
|
||||||
|
// Reset to power-up state
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Mute voice n if bit n (1 << n) of mask is set
|
||||||
|
enum { channel_count = 6 };
|
||||||
|
void mute_voices( int mask );
|
||||||
|
|
||||||
|
// Write addr to register 0 then data to register 1
|
||||||
|
void write0( int addr, int data );
|
||||||
|
|
||||||
|
// Write addr to register 2 then data to register 3
|
||||||
|
void write1( int addr, int data );
|
||||||
|
|
||||||
|
// Run and add pair_count samples into current output buffer contents
|
||||||
|
typedef short sample_t;
|
||||||
|
enum { out_chan_count = 2 }; // stereo
|
||||||
|
void run( int pair_count, sample_t* out );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
3108
game-music-emu/gme/Ym2612_MAME.cpp
Normal file
3108
game-music-emu/gme/Ym2612_MAME.cpp
Normal file
File diff suppressed because it is too large
Load diff
38
game-music-emu/gme/Ym2612_MAME.h
Normal file
38
game-music-emu/gme/Ym2612_MAME.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// YM2612 FM sound chip emulator interface
|
||||||
|
|
||||||
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
#ifndef YM2612_EMU_H
|
||||||
|
#define YM2612_EMU_H
|
||||||
|
|
||||||
|
typedef void Ym2612_MAME_Impl;
|
||||||
|
|
||||||
|
class Ym2612_MAME_Emu {
|
||||||
|
Ym2612_MAME_Impl* impl;
|
||||||
|
public:
|
||||||
|
Ym2612_MAME_Emu();
|
||||||
|
~Ym2612_MAME_Emu();
|
||||||
|
|
||||||
|
// Set output sample rate and chip clock rates, in Hz. Returns non-zero
|
||||||
|
// if error.
|
||||||
|
const char* set_rate( double sample_rate, double clock_rate );
|
||||||
|
|
||||||
|
// Reset to power-up state
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Mute voice n if bit n (1 << n) of mask is set
|
||||||
|
enum { channel_count = 6 };
|
||||||
|
void mute_voices( int mask );
|
||||||
|
|
||||||
|
// Write addr to register 0 then data to register 1
|
||||||
|
void write0( int addr, int data );
|
||||||
|
|
||||||
|
// Write addr to register 2 then data to register 3
|
||||||
|
void write1( int addr, int data );
|
||||||
|
|
||||||
|
// Run and add pair_count samples into current output buffer contents
|
||||||
|
typedef short sample_t;
|
||||||
|
enum { out_chan_count = 2 }; // stereo
|
||||||
|
void run( int pair_count, sample_t* out );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1872
game-music-emu/gme/Ym2612_Nuked.cpp
Normal file
1872
game-music-emu/gme/Ym2612_Nuked.cpp
Normal file
File diff suppressed because it is too large
Load diff
41
game-music-emu/gme/Ym2612_Nuked.h
Normal file
41
game-music-emu/gme/Ym2612_Nuked.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// YM2612 FM sound chip emulator interface
|
||||||
|
|
||||||
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
#ifndef YM2612_EMU_H
|
||||||
|
#define YM2612_EMU_H
|
||||||
|
|
||||||
|
typedef void Ym2612_Nuked_Impl;
|
||||||
|
|
||||||
|
class Ym2612_Nuked_Emu {
|
||||||
|
Ym2612_Nuked_Impl* impl;
|
||||||
|
double prev_sample_rate;
|
||||||
|
double prev_clock_rate;
|
||||||
|
public:
|
||||||
|
Ym2612_Nuked_Emu();
|
||||||
|
~Ym2612_Nuked_Emu();
|
||||||
|
|
||||||
|
// Set output sample rate and chip clock rates, in Hz. Returns non-zero
|
||||||
|
// if error.
|
||||||
|
const char* set_rate( double sample_rate, double clock_rate );
|
||||||
|
|
||||||
|
// Reset to power-up state
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// Mute voice n if bit n (1 << n) of mask is set
|
||||||
|
enum { channel_count = 6 };
|
||||||
|
void mute_voices( int mask );
|
||||||
|
|
||||||
|
// Write addr to register 0 then data to register 1
|
||||||
|
void write0( int addr, int data );
|
||||||
|
|
||||||
|
// Write addr to register 2 then data to register 3
|
||||||
|
void write1( int addr, int data );
|
||||||
|
|
||||||
|
// Run and add pair_count samples into current output buffer contents
|
||||||
|
typedef short sample_t;
|
||||||
|
enum { out_chan_count = 2 }; // stereo
|
||||||
|
void run( int pair_count, sample_t* out );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -80,6 +80,9 @@ public:
|
||||||
#define BLARGG_4CHAR( a, b, c, d ) \
|
#define BLARGG_4CHAR( a, b, c, d ) \
|
||||||
((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
|
((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
|
||||||
|
|
||||||
|
#define BLARGG_2CHAR( a, b ) \
|
||||||
|
((a&0xFF)*0x100L + (b&0xFF))
|
||||||
|
|
||||||
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
||||||
#ifndef BOOST_STATIC_ASSERT
|
#ifndef BOOST_STATIC_ASSERT
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -132,51 +135,12 @@ public:
|
||||||
typedef unsigned blargg_ulong;
|
typedef unsigned blargg_ulong;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BOOST::int8_t etc.
|
// int8_t etc.
|
||||||
|
|
||||||
// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
|
// TODO: Add CMake check for this, although I'd likely just point affected
|
||||||
#if defined (HAVE_STDINT_H)
|
// persons to a real compiler...
|
||||||
|
#if 1 || defined (HAVE_STDINT_H)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#define BOOST
|
|
||||||
|
|
||||||
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
|
|
||||||
#elif defined (HAVE_INTTYPES_H)
|
|
||||||
#include <inttypes.h>
|
|
||||||
#define BOOST
|
|
||||||
|
|
||||||
#else
|
|
||||||
struct BOOST
|
|
||||||
{
|
|
||||||
#if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
#else
|
|
||||||
// No suitable 8-bit type available
|
|
||||||
typedef struct see_blargg_common_h int8_t;
|
|
||||||
typedef struct see_blargg_common_h uint8_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USHRT_MAX == 0xFFFF
|
|
||||||
typedef short int16_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
#else
|
|
||||||
// No suitable 16-bit type available
|
|
||||||
typedef struct see_blargg_common_h int16_t;
|
|
||||||
typedef struct see_blargg_common_h uint16_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ULONG_MAX == 0xFFFFFFFF
|
|
||||||
typedef long int32_t;
|
|
||||||
typedef unsigned long uint32_t;
|
|
||||||
#elif UINT_MAX == 0xFFFFFFFF
|
|
||||||
typedef int int32_t;
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
#else
|
|
||||||
// No suitable 32-bit type available
|
|
||||||
typedef struct see_blargg_common_h int32_t;
|
|
||||||
typedef struct see_blargg_common_h uint32_t;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __GNUC__ >= 3
|
#if __GNUC__ >= 3
|
||||||
|
|
|
@ -123,15 +123,15 @@ inline void set_be32( void* p, blargg_ulong n )
|
||||||
#if BLARGG_NONPORTABLE
|
#if BLARGG_NONPORTABLE
|
||||||
// Optimized implementation if byte order is known
|
// Optimized implementation if byte order is known
|
||||||
#if BLARGG_LITTLE_ENDIAN
|
#if BLARGG_LITTLE_ENDIAN
|
||||||
#define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
|
#define GET_LE16( addr ) (*(uint16_t*) (addr))
|
||||||
#define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
|
#define GET_LE32( addr ) (*(uint32_t*) (addr))
|
||||||
#define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
#define SET_LE16( addr, data ) (void) (*(uint16_t*) (addr) = (data))
|
||||||
#define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
#define SET_LE32( addr, data ) (void) (*(uint32_t*) (addr) = (data))
|
||||||
#elif BLARGG_BIG_ENDIAN
|
#elif BLARGG_BIG_ENDIAN
|
||||||
#define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
|
#define GET_BE16( addr ) (*(uint16_t*) (addr))
|
||||||
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
|
#define GET_BE32( addr ) (*(uint32_t*) (addr))
|
||||||
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
#define SET_BE16( addr, data ) (void) (*(uint16_t*) (addr) = (data))
|
||||||
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
#define SET_BE32( addr, data ) (void) (*(uint32_t*) (addr) = (data))
|
||||||
|
|
||||||
#if BLARGG_CPU_POWERPC
|
#if BLARGG_CPU_POWERPC
|
||||||
// PowerPC has special byte-reversed instructions
|
// PowerPC has special byte-reversed instructions
|
||||||
|
@ -172,13 +172,13 @@ inline void set_be32( void* p, blargg_ulong n )
|
||||||
|
|
||||||
// auto-selecting versions
|
// auto-selecting versions
|
||||||
|
|
||||||
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
inline void set_le( uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
||||||
inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
|
inline void set_le( uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
|
||||||
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
inline void set_be( uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
||||||
inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
|
inline void set_be( uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
|
||||||
inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
|
inline unsigned get_le( uint16_t* p ) { return GET_LE16( p ); }
|
||||||
inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
|
inline blargg_ulong get_le( uint32_t* p ) { return GET_LE32( p ); }
|
||||||
inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
|
inline unsigned get_be( uint16_t* p ) { return GET_BE16( p ); }
|
||||||
inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
|
inline blargg_ulong get_be( uint32_t* p ) { return GET_BE32( p ); }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,19 @@ all other #include lines. */
|
||||||
#undef require
|
#undef require
|
||||||
#define require( expr ) assert( expr )
|
#define require( expr ) assert( expr )
|
||||||
|
|
||||||
|
// Use to provide hints to compiler for optimized code layout in situations where we
|
||||||
|
// can almost always expect a conditional to go one way or the other. Should only be
|
||||||
|
// used in situations where an unexpected branch is truly exceptional though!
|
||||||
|
#undef likely
|
||||||
|
#undef unlikely
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define likely( x ) __builtin_expect(x, 1)
|
||||||
|
#define unlikely( x ) __builtin_expect(x, 0)
|
||||||
|
#else
|
||||||
|
#define likely( x ) (x)
|
||||||
|
#define unlikely( x ) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Like printf() except output goes to debug log file. Might be defined to do
|
// Like printf() except output goes to debug log file. Might be defined to do
|
||||||
// nothing (not even evaluate its arguments).
|
// nothing (not even evaluate its arguments).
|
||||||
// void debug_printf( const char* format, ... );
|
// void debug_printf( const char* format, ... );
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||||
|
|
||||||
#include "Music_Emu.h"
|
#include "Music_Emu.h"
|
||||||
|
|
||||||
|
@ -83,6 +83,8 @@ BLARGG_EXPORT const char* gme_identify_header( void const* header )
|
||||||
case BLARGG_4CHAR('S','N','E','S'): return "SPC";
|
case BLARGG_4CHAR('S','N','E','S'): return "SPC";
|
||||||
case BLARGG_4CHAR('V','g','m',' '): return "VGM";
|
case BLARGG_4CHAR('V','g','m',' '): return "VGM";
|
||||||
}
|
}
|
||||||
|
if (get_be16(header) == BLARGG_2CHAR(0x1F, 0x8B))
|
||||||
|
return "VGZ";
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +113,14 @@ BLARGG_EXPORT gme_type_t gme_identify_extension( const char* extension_ )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLARGG_EXPORT const char *gme_type_extension( gme_type_t music_type )
|
||||||
|
{
|
||||||
|
const gme_type_t_ *const music_typeinfo = static_cast<const gme_type_t_ *>( music_type );
|
||||||
|
if ( music_type )
|
||||||
|
return music_typeinfo->extension_;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
BLARGG_EXPORT gme_err_t gme_identify_file( const char* path, gme_type_t* type_out )
|
BLARGG_EXPORT gme_err_t gme_identify_file( const char* path, gme_type_t* type_out )
|
||||||
{
|
{
|
||||||
*type_out = gme_identify_extension( path );
|
*type_out = gme_identify_extension( path );
|
||||||
|
@ -187,7 +197,8 @@ BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sa
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
|
// Used to implement gme_new_emu and gme_new_emu_multi_channel
|
||||||
|
Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel )
|
||||||
{
|
{
|
||||||
if ( type )
|
if ( type )
|
||||||
{
|
{
|
||||||
|
@ -198,9 +209,18 @@ BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
|
||||||
if ( me )
|
if ( me )
|
||||||
{
|
{
|
||||||
#if !GME_DISABLE_STEREO_DEPTH
|
#if !GME_DISABLE_STEREO_DEPTH
|
||||||
|
me->set_multi_channel( multi_channel );
|
||||||
|
|
||||||
if ( type->flags_ & 1 )
|
if ( type->flags_ & 1 )
|
||||||
{
|
{
|
||||||
me->effects_buffer = BLARGG_NEW Effects_Buffer;
|
if ( me->multi_channel() )
|
||||||
|
{
|
||||||
|
me->effects_buffer = BLARGG_NEW Effects_Buffer(8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me->effects_buffer = BLARGG_NEW Effects_Buffer(1);
|
||||||
|
}
|
||||||
if ( me->effects_buffer )
|
if ( me->effects_buffer )
|
||||||
me->set_buffer( me->effects_buffer );
|
me->set_buffer( me->effects_buffer );
|
||||||
}
|
}
|
||||||
|
@ -220,6 +240,17 @@ BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
|
||||||
|
{
|
||||||
|
return gme_internal_new_emu_( type, rate, false /* no multichannel */);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLARGG_EXPORT Music_Emu* gme_new_emu_multi_channel( gme_type_t type, int rate )
|
||||||
|
{
|
||||||
|
// multi-channel emulator (if possible, not all emu types support multi-channel)
|
||||||
|
return gme_internal_new_emu_( type, rate, true /* multichannel */);
|
||||||
|
}
|
||||||
|
|
||||||
BLARGG_EXPORT gme_err_t gme_load_file( Music_Emu* me, const char* path ) { return me->load_file( path ); }
|
BLARGG_EXPORT gme_err_t gme_load_file( Music_Emu* me, const char* path ) { return me->load_file( path ); }
|
||||||
|
|
||||||
BLARGG_EXPORT gme_err_t gme_load_data( Music_Emu* me, void const* data, long size )
|
BLARGG_EXPORT gme_err_t gme_load_data( Music_Emu* me, void const* data, long size )
|
||||||
|
@ -345,9 +376,10 @@ BLARGG_EXPORT void gme_ignore_silence ( Music_Emu* me, int disable )
|
||||||
BLARGG_EXPORT void gme_set_tempo ( Music_Emu* me, double t ) { me->set_tempo( t ); }
|
BLARGG_EXPORT void gme_set_tempo ( Music_Emu* me, double t ) { me->set_tempo( t ); }
|
||||||
BLARGG_EXPORT void gme_mute_voice ( Music_Emu* me, int index, int mute ) { me->mute_voice( index, mute != 0 ); }
|
BLARGG_EXPORT void gme_mute_voice ( Music_Emu* me, int index, int mute ) { me->mute_voice( index, mute != 0 ); }
|
||||||
BLARGG_EXPORT void gme_mute_voices ( Music_Emu* me, int mask ) { me->mute_voices( mask ); }
|
BLARGG_EXPORT void gme_mute_voices ( Music_Emu* me, int mask ) { me->mute_voices( mask ); }
|
||||||
BLARGG_EXPORT void gme_enable_accuracy( Music_Emu* me, int enabled ) { me->enable_accuracy( !!enabled ); }
|
BLARGG_EXPORT void gme_enable_accuracy( Music_Emu* me, int enabled ) { me->enable_accuracy( enabled ); }
|
||||||
BLARGG_EXPORT void gme_clear_playlist ( Music_Emu* me ) { me->clear_playlist(); }
|
BLARGG_EXPORT void gme_clear_playlist ( Music_Emu* me ) { me->clear_playlist(); }
|
||||||
BLARGG_EXPORT int gme_type_multitrack( gme_type_t t ) { return t->track_count != 1; }
|
BLARGG_EXPORT int gme_type_multitrack( gme_type_t t ) { return t->track_count != 1; }
|
||||||
|
BLARGG_EXPORT int gme_multi_channel ( Music_Emu const* me ) { return me->multi_channel(); }
|
||||||
|
|
||||||
BLARGG_EXPORT void gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq )
|
BLARGG_EXPORT void gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq )
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* Game music emulator library C interface (also usable from C++) */
|
/* Game music emulator library C interface (also usable from C++) */
|
||||||
|
|
||||||
/* Game_Music_Emu 0.6.1 */
|
/* Game_Music_Emu 0.6.2 */
|
||||||
#ifndef GME_H
|
#ifndef GME_H
|
||||||
#define GME_H
|
#define GME_H
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GME_VERSION 0x000601 /* 1 byte major, 1 byte minor, 1 byte patch-level */
|
#define GME_VERSION 0x000602 /* 1 byte major, 1 byte minor, 1 byte patch-level */
|
||||||
|
|
||||||
/* Error string returned by library functions, or NULL if no error (success) */
|
/* Error string returned by library functions, or NULL if no error (success) */
|
||||||
typedef const char* gme_err_t;
|
typedef const char* gme_err_t;
|
||||||
|
@ -187,13 +187,18 @@ const char* gme_type_system( gme_type_t );
|
||||||
/* True if this music file type supports multiple tracks */
|
/* True if this music file type supports multiple tracks */
|
||||||
int gme_type_multitrack( gme_type_t );
|
int gme_type_multitrack( gme_type_t );
|
||||||
|
|
||||||
|
/* whether the pcm output retrieved by gme_play() will have all 8 voices rendered to their
|
||||||
|
* individual stereo channel or (if false) these voices get mixed into one single stereo channel
|
||||||
|
* @since 0.6.2 */
|
||||||
|
int gme_multi_channel( Music_Emu const* );
|
||||||
|
|
||||||
/******** Advanced file loading ********/
|
/******** Advanced file loading ********/
|
||||||
|
|
||||||
/* Error returned if file type is not supported */
|
/* Error returned if file type is not supported */
|
||||||
extern const char* const gme_wrong_file_type;
|
extern const char* const gme_wrong_file_type;
|
||||||
|
|
||||||
/* Same as gme_open_file(), but uses file data already in memory. Makes copy of data. */
|
/* Same as gme_open_file(), but uses file data already in memory. Makes copy of data.
|
||||||
|
* The resulting Music_Emu object will be set to single channel mode. */
|
||||||
gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate );
|
gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate );
|
||||||
|
|
||||||
/* Determine likely game music type based on first four bytes of file. Returns
|
/* Determine likely game music type based on first four bytes of file. Returns
|
||||||
|
@ -204,6 +209,14 @@ const char* gme_identify_header( void const* header );
|
||||||
/* Get corresponding music type for file path or extension passed in. */
|
/* Get corresponding music type for file path or extension passed in. */
|
||||||
gme_type_t gme_identify_extension( const char path_or_extension [] );
|
gme_type_t gme_identify_extension( const char path_or_extension [] );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get typical file extension for a given music type. This is not a replacement
|
||||||
|
* for a file content identification library (but see gme_identify_header).
|
||||||
|
*
|
||||||
|
* @since 0.6.2
|
||||||
|
*/
|
||||||
|
const char* gme_type_extension( gme_type_t music_type );
|
||||||
|
|
||||||
/* Determine file type based on file's extension or header (if extension isn't recognized).
|
/* Determine file type based on file's extension or header (if extension isn't recognized).
|
||||||
Sets *type_out to type, or 0 if unrecognized or error. */
|
Sets *type_out to type, or 0 if unrecognized or error. */
|
||||||
gme_err_t gme_identify_file( const char path [], gme_type_t* type_out );
|
gme_err_t gme_identify_file( const char path [], gme_type_t* type_out );
|
||||||
|
@ -212,6 +225,13 @@ gme_err_t gme_identify_file( const char path [], gme_type_t* type_out );
|
||||||
track information, pass gme_info_only for sample_rate. */
|
track information, pass gme_info_only for sample_rate. */
|
||||||
Music_Emu* gme_new_emu( gme_type_t, int sample_rate );
|
Music_Emu* gme_new_emu( gme_type_t, int sample_rate );
|
||||||
|
|
||||||
|
/* Create new multichannel emulator and set sample rate. Returns NULL if out of memory.
|
||||||
|
* If you only need track information, pass gme_info_only for sample_rate.
|
||||||
|
* (see gme_multi_channel for more information on multichannel support)
|
||||||
|
* @since 0.6.2
|
||||||
|
*/
|
||||||
|
Music_Emu* gme_new_emu_multi_channel( gme_type_t, int sample_rate );
|
||||||
|
|
||||||
/* Load music file into emulator */
|
/* Load music file into emulator */
|
||||||
gme_err_t gme_load_file( Music_Emu*, const char path [] );
|
gme_err_t gme_load_file( Music_Emu*, const char path [] );
|
||||||
|
|
||||||
|
|
10
game-music-emu/gme/gme_types.h
Executable file → Normal file
10
game-music-emu/gme/gme_types.h
Executable file → Normal file
|
@ -1,13 +1,11 @@
|
||||||
#ifndef GME_TYPES_H
|
#ifndef GME_TYPES_H
|
||||||
#define GME_TYPES_H
|
#define GME_TYPES_H
|
||||||
|
|
||||||
/* CMake will either define the following to 1, or #undef it,
|
/*
|
||||||
* depending on the options passed to CMake. This is used to
|
* This is a default gme_types.h for use when *not* using
|
||||||
* conditionally compile in the various emulator types.
|
* CMake. If CMake is in use gme_types.h.in will be
|
||||||
*
|
* processed instead.
|
||||||
* See gme_type_list() in gme.cpp
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define USE_GME_AY
|
#define USE_GME_AY
|
||||||
#define USE_GME_GBS
|
#define USE_GME_GBS
|
||||||
#define USE_GME_GYM
|
#define USE_GME_GYM
|
||||||
|
|
16
game-music-emu/gme/libgme.pc.in
Normal file
16
game-music-emu/gme/libgme.pc.in
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# entries grouped with CMake are expanded by CMake
|
||||||
|
# ${foo} entries are left alone by CMake and much
|
||||||
|
# later are used by pkg-config.
|
||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
exec_prefix=${prefix}
|
||||||
|
lib_suffix=@LIB_SUFFIX@
|
||||||
|
libdir=${exec_prefix}/lib${lib_suffix}
|
||||||
|
includedir=${prefix}/include
|
||||||
|
|
||||||
|
Name: Game_Music_Emu
|
||||||
|
Description: A video game emulation library for music.
|
||||||
|
URL: https://bitbucket.org/mpyne/game-music-emu/wiki/Home
|
||||||
|
Version: @GME_VERSION@
|
||||||
|
Cflags: -I${includedir}
|
||||||
|
Libs: -L${libdir} -lgme
|
||||||
|
Libs.private: -lstdc++ @PKG_CONFIG_ZLIB@
|
|
@ -1,4 +1,4 @@
|
||||||
Game_Music_Emu 0.6.1: Game Music Emulators
|
Game_Music_Emu 0.6.2: Game Music Emulators
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
Game_Music_Emu is a collection of video game music file emulators that
|
Game_Music_Emu is a collection of video game music file emulators that
|
||||||
support the following formats and systems:
|
support the following formats and systems:
|
||||||
|
@ -34,10 +34,12 @@ several architectures, Mac OS, MorphOS, Xbox, PlayStation Portable,
|
||||||
GP2X, and Nintendo DS.
|
GP2X, and Nintendo DS.
|
||||||
|
|
||||||
Author : Shay Green <gblargg@gmail.com>
|
Author : Shay Green <gblargg@gmail.com>
|
||||||
Website: http://www.slack.net/~ant/
|
Website: https://bitbucket.org/mpyne/game-music-emu/wiki/Home
|
||||||
Forum : http://groups.google.com/group/blargg-sound-libs
|
|
||||||
License: GNU Lesser General Public License (LGPL)
|
License: GNU Lesser General Public License (LGPL)
|
||||||
|
|
||||||
|
Note: When you will use MAME YM2612 emulator, the license of library
|
||||||
|
will be GNU General Public License (GPL) v2.0+!
|
||||||
|
|
||||||
Current Maintainer: Michael Pyne <mpyne@purinchu.net>
|
Current Maintainer: Michael Pyne <mpyne@purinchu.net>
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
|
@ -191,8 +193,13 @@ gme/
|
||||||
Sms_Apu.cpp Common Sega emulator files
|
Sms_Apu.cpp Common Sega emulator files
|
||||||
Sms_Apu.h
|
Sms_Apu.h
|
||||||
Sms_Oscs.h
|
Sms_Oscs.h
|
||||||
Ym2612_Emu.cpp
|
|
||||||
Ym2612_Emu.h
|
Ym2612_Emu.h
|
||||||
|
Ym2612_GENS.cpp GENS 2.10 YM2612 emulator (LGPLv2.1+ license)
|
||||||
|
Ym2612_GENS.h
|
||||||
|
Ym2612_MAME.cpp MAME YM2612 emulator (GPLv2.0+ license)
|
||||||
|
Ym2612_MAME.h
|
||||||
|
Ym2612_Nuked.cpp Nuked OPN2 emulator (LGPLv2.1+ license)
|
||||||
|
Ym2612_Nuked.h
|
||||||
Dual_Resampler.cpp
|
Dual_Resampler.cpp
|
||||||
Dual_Resampler.h
|
Dual_Resampler.h
|
||||||
Fir_Resampler.cpp
|
Fir_Resampler.cpp
|
||||||
|
@ -227,6 +234,8 @@ Legal
|
||||||
-----
|
-----
|
||||||
Game_Music_Emu library copyright (C) 2003-2009 Shay Green.
|
Game_Music_Emu library copyright (C) 2003-2009 Shay Green.
|
||||||
Sega Genesis YM2612 emulator copyright (C) 2002 Stephane Dallongeville.
|
Sega Genesis YM2612 emulator copyright (C) 2002 Stephane Dallongeville.
|
||||||
|
MAME YM2612 emulator copyright (C) 2003 Jarek Burczynski, Tatsuyuki Satoh
|
||||||
|
Nuked OPN2 emulator copyright (C) 2017 Alexey Khokholov (Nuke.YKT)
|
||||||
|
|
||||||
--
|
--
|
||||||
Shay Green <gblargg@gmail.com>
|
Shay Green <gblargg@gmail.com>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue