mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 06:42:08 +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
|
||||
compiler: clang
|
||||
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"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-6.0
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- clang-6.0
|
||||
- libstdc++-5-dev
|
||||
- clang-7
|
||||
- libsdl2-dev
|
||||
- libgme-dev
|
||||
- libopenal-dev
|
||||
|
|
|
@ -53,7 +53,7 @@ function( assort_pk3_source_folder FOLDER_NAME PK3_DIR )
|
|||
assort_pk3_source_folder( ${FOLDER_NAME}\\${DIRNAME} ${PK3_SRC} )
|
||||
endif()
|
||||
# Assign IDE group for current top-level source files
|
||||
source_group(${FOLDER_NAME} FILES ${PK3_SRCS})
|
||||
source_group(${FOLDER_NAME} FILES ${PK3_SRCS})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
@ -78,7 +78,7 @@ function( add_pk3 PK3_NAME PK3_DIR )
|
|||
DEPENDS zipdir )
|
||||
endif()
|
||||
# Create a list of source files for this PK3, for use in the IDE
|
||||
# Phase 1: Create a list of all source files for this PK3 archive, except
|
||||
# Phase 1: Create a list of all source files for this PK3 archive, except
|
||||
# for a couple of strife image file names that confuse CMake.
|
||||
file(GLOB_RECURSE PK3_SRCS ${PK3_DIR}/*)
|
||||
# Exclude from the source list some gzdoom .png files with brackets in the
|
||||
|
@ -181,7 +181,7 @@ if( MSVC )
|
|||
# Function-level linking
|
||||
# Disable run-time type information
|
||||
set( ALL_C_FLAGS "/GF /Gy /GR-" )
|
||||
|
||||
|
||||
# Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall
|
||||
#set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") # This is already the default
|
||||
|
||||
|
@ -200,7 +200,7 @@ if( MSVC )
|
|||
# else()
|
||||
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
|
||||
# endif()
|
||||
|
||||
|
||||
# Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations.
|
||||
option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF )
|
||||
if( ZDOOM_GENERATE_ASM )
|
||||
|
@ -209,7 +209,7 @@ if( MSVC )
|
|||
set( REL_C_FLAGS "/MT /Oy /Oi /GS-" )
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# Debug allocations in debug builds
|
||||
set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC /MTd" )
|
||||
|
||||
|
@ -217,7 +217,7 @@ if( MSVC )
|
|||
if( MSVC_VERSION GREATER 1399 )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996" )
|
||||
endif()
|
||||
|
||||
|
||||
# The CMake configurations set /GR and /MD by default, which conflict with our settings.
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} )
|
||||
|
@ -234,7 +234,7 @@ else()
|
|||
set( REL_C_FLAGS "" )
|
||||
set( DEB_C_FLAGS "" )
|
||||
|
||||
|
||||
|
||||
if( APPLE )
|
||||
if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
|
||||
# With standard Apple tools -stdlib=libc++ needs to be specified in order to get
|
||||
|
@ -328,6 +328,9 @@ if( GME_FOUND AND NOT FORCE_INTERNAL_GME )
|
|||
message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" )
|
||||
else()
|
||||
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 )
|
||||
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/game-music-emu" )
|
||||
set( GME_LIBRARIES gme )
|
||||
|
@ -347,8 +350,8 @@ if( WIN32 )
|
|||
else()
|
||||
set( INSTALL_DOCS_PATH share/doc/${ZDOOM_EXE_NAME} CACHE STRING "Directory where the zdoom documentation will be placed during install." )
|
||||
endif()
|
||||
install(DIRECTORY docs/
|
||||
DESTINATION ${INSTALL_DOCS_PATH}
|
||||
install(DIRECTORY docs/
|
||||
DESTINATION ${INSTALL_DOCS_PATH}
|
||||
COMPONENT "Documentation")
|
||||
|
||||
add_subdirectory( lzma )
|
||||
|
|
|
@ -4,29 +4,32 @@ project(libgme)
|
|||
include (CheckCXXCompilerFlag)
|
||||
|
||||
# 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.
|
||||
# Of course, 2.4 might work, in which case you're welcome to drop
|
||||
# down the requirement, but I can't test that.
|
||||
cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR)
|
||||
|
||||
make_release_only()
|
||||
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
|
||||
|
||||
# I don't plan on debugging this, so make it a release build.
|
||||
if( NOT CMAKE_BUILD_TYPE MATCHES "Release" )
|
||||
set( CMAKE_BUILD_TYPE "RelWithDebInfo" )
|
||||
set( CMAKE_BUILD_TYPE "RelWithDebInfo" )
|
||||
endif()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
|
||||
if( NOT PROFILE )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" )
|
||||
endif()
|
||||
check_cxx_compiler_flag( -Wno-array-bounds HAVE_NO_ARRAY_BOUNDS )
|
||||
if( HAVE_NO_ARRAY_BOUNDS )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-array-bounds" )
|
||||
endif()
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
|
||||
if( NOT PROFILE )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" )
|
||||
endif()
|
||||
check_cxx_compiler_flag( -Wno-array-bounds HAVE_NO_ARRAY_BOUNDS )
|
||||
if( HAVE_NO_ARRAY_BOUNDS )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-array-bounds" )
|
||||
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
|
||||
|
@ -34,79 +37,102 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
|
|||
|
||||
# Default emulators to build (all of them! ;)
|
||||
# [ZDoom] No options, enable all of them by default.
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#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()
|
||||
|
||||
#if (USE_GME_NSFE AND NOT USE_GME_NSF)
|
||||
# MESSAGE(" -- NSFE support requires NSF, enabling NSF support. --")
|
||||
SET(USE_GME_NSF 1 BOOL "Enable NES NSF music emulation")
|
||||
#MESSAGE(" -- NSFE support requires NSF, enabling NSF support. --")
|
||||
SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation" FORCE)
|
||||
#endif()
|
||||
|
||||
# [ZDoom] Set always to OFF.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(ENABLE_UBSAN OFF)
|
||||
|
||||
# Check for GCC "visibility" support.
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
check_cxx_compiler_flag (-fvisibility=hidden __LIBGME_TEST_VISIBILITY)
|
||||
set (ENABLE_VISIBILITY OFF)
|
||||
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}")
|
||||
# Check for GCC/Clang "visibility" support.
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||
OR
|
||||
CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
|
||||
# gcc <4.1 had poor support for symbol visibility
|
||||
if ((${_gcc_version} VERSION_GREATER "4.1") OR (${_gcc_version} VERSION_EQUAL "4.1"))
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
|
||||
set (ENABLE_VISIBILITY ON)
|
||||
add_definitions (-DLIBGME_VISIBILITY)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -W -Wextra")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
# GCC >= 4.2 also correctly supports making inline members have hidden
|
||||
# visibility by default.
|
||||
if ((${_gcc_version} VERSION_GREATER "4.2") OR (${_gcc_version} VERSION_EQUAL "4.2"))
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
|
||||
endif()
|
||||
endif()
|
||||
endif() # test visibility
|
||||
# Assume we have visibility support on any compiler that supports C++11
|
||||
add_definitions (-DLIBGME_VISIBILITY)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
|
||||
|
||||
# Cache this result
|
||||
set( LIBGME_HAVE_GCC_VISIBILITY ${ENABLE_VISIBILITY} CACHE BOOL "GCC support for hidden visibility")
|
||||
# Try to protect against undefined behavior from signed integer overflow
|
||||
# This has caused miscompilation of code already and there are other
|
||||
# potential uses; see https://bitbucket.org/mpyne/game-music-emu/issues/18/
|
||||
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 ()
|
||||
|
||||
if(LIBGME_SWITCH_FALLTHROUGH)
|
||||
# Avoid warning spam about switch fallthroughs, which are numerous in
|
||||
# the codebase.
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wimplicit-fallthrough=0")
|
||||
endif()
|
||||
|
||||
# Shared library defined here
|
||||
|
|
|
@ -1,274 +1,5 @@
|
|||
Game_Music_Emu Change Log
|
||||
-------------------------
|
||||
|
||||
Game_Music_Emu 0.6.1
|
||||
--------------------
|
||||
|
||||
- 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
|
||||
Please see the git version history (e.g. git shortlog tags/0.6.0..tags/0.6.1)
|
||||
for the accurate change log.
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
Game_Music_Emu 0.6.1
|
||||
Game_Music_Emu 0.6.2
|
||||
--------------------
|
||||
Author : Shay Green <gblargg@gmail.com>
|
||||
Maintainer : Michael Pyne <mpyne@purinchu.net>
|
||||
Website : http://www.slack.net/~ant/libs/
|
||||
Forum : http://groups.google.com/group/blargg-sound-libs
|
||||
Website : 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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
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 )
|
||||
{
|
||||
delta = -delta;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
// 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 )
|
||||
{
|
||||
set_end_time( end_time );
|
||||
|
@ -148,8 +143,6 @@ bool Ay_Cpu::run( cpu_time_t end_time )
|
|||
this->state = &s;
|
||||
bool warning = false;
|
||||
|
||||
typedef BOOST::int8_t int8_t;
|
||||
|
||||
union {
|
||||
regs_t rg;
|
||||
pairs_t rp;
|
||||
|
@ -160,10 +153,10 @@ bool Ay_Cpu::run( cpu_time_t end_time )
|
|||
|
||||
cpu_time_t s_time = s.time;
|
||||
uint8_t* const mem = this->mem; // cache
|
||||
fuint16 pc = r.pc;
|
||||
fuint16 sp = r.sp;
|
||||
fuint16 ix = r.ix; // TODO: keep in memory for direct access?
|
||||
fuint16 iy = r.iy;
|
||||
uint16_t pc = r.pc;
|
||||
uint16_t sp = r.sp;
|
||||
uint16_t ix = r.ix; // TODO: keep in memory for direct access?
|
||||
uint16_t iy = r.iy;
|
||||
int flags = r.b.flags;
|
||||
|
||||
goto loop;
|
||||
|
@ -182,7 +175,7 @@ loop:
|
|||
check( (unsigned) ix < 0x10000 );
|
||||
check( (unsigned) iy < 0x10000 );
|
||||
|
||||
fuint8 opcode;
|
||||
uint8_t opcode;
|
||||
opcode = READ_PROG( pc );
|
||||
pc++;
|
||||
|
||||
|
@ -206,7 +199,7 @@ loop:
|
|||
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];
|
||||
if ( (s_time += data) >= 0 )
|
||||
goto possibly_out_of_time;
|
||||
|
@ -262,7 +255,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x3A:{// LD A,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
rg.a = READ( addr );
|
||||
goto loop;
|
||||
|
@ -277,7 +270,7 @@ possibly_out_of_time:
|
|||
|
||||
// JR
|
||||
#define JR( cond ) {\
|
||||
int disp = (BOOST::int8_t) data;\
|
||||
int disp = (int8_t) data;\
|
||||
pc++;\
|
||||
if ( !(cond) )\
|
||||
goto jr_not_taken;\
|
||||
|
@ -349,7 +342,7 @@ possibly_out_of_time:
|
|||
|
||||
case 0xCD:{// CALL addr
|
||||
call_taken:
|
||||
fuint16 addr = pc + 2;
|
||||
uint16_t addr = pc + 2;
|
||||
pc = GET_ADDR();
|
||||
sp = uint16_t (sp - 2);
|
||||
WRITE_WORD( sp, addr );
|
||||
|
@ -469,7 +462,7 @@ possibly_out_of_time:
|
|||
add_hl_data: {
|
||||
blargg_ulong sum = rp.hl + data;
|
||||
data ^= rp.hl;
|
||||
rp.hl = (uint16_t)sum;
|
||||
rp.hl = sum;
|
||||
flags = (flags & (S80 | Z40 | V04)) |
|
||||
(sum >> 16) |
|
||||
(sum >> 8 & (F20 | F08)) |
|
||||
|
@ -659,21 +652,21 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x2A:{// LD HL,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
rp.hl = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x32:{// LD (addr),A
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE( addr, rg.a );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x22:{// LD (addr),HL
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, rp.hl );
|
||||
goto loop;
|
||||
|
@ -696,7 +689,7 @@ possibly_out_of_time:
|
|||
// Rotate
|
||||
|
||||
case 0x07:{// RLCA
|
||||
fuint16 temp = rg.a;
|
||||
uint16_t temp = rg.a;
|
||||
temp = (temp << 1) | (temp >> 7);
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08 | C01));
|
||||
|
@ -705,7 +698,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x0F:{// RRCA
|
||||
fuint16 temp = rg.a;
|
||||
uint16_t temp = rg.a;
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & C01);
|
||||
temp = (temp << 7) | (temp >> 1);
|
||||
|
@ -719,12 +712,12 @@ possibly_out_of_time:
|
|||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(temp >> 8);
|
||||
rg.a = (uint8_t)temp;
|
||||
rg.a = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x1F:{// RRA
|
||||
fuint16 temp = (flags << 7) | (rg.a >> 1);
|
||||
uint16_t temp = (flags << 7) | (rg.a >> 1);
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(rg.a & C01);
|
||||
|
@ -734,7 +727,7 @@ possibly_out_of_time:
|
|||
|
||||
// Misc
|
||||
case 0x2F:{// CPL
|
||||
fuint16 temp = ~rg.a;
|
||||
uint16_t temp = ~rg.a;
|
||||
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(H10 | N02);
|
||||
|
@ -760,21 +753,21 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xE3:{// EX (SP),HL
|
||||
fuint16 temp = READ_WORD( sp );
|
||||
uint16_t temp = READ_WORD( sp );
|
||||
WRITE_WORD( sp, rp.hl );
|
||||
rp.hl = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0xEB:{// EX DE,HL
|
||||
fuint16 temp = rp.hl;
|
||||
uint16_t temp = rp.hl;
|
||||
rp.hl = rp.de;
|
||||
rp.de = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0xD9:{// EXX DE,HL
|
||||
fuint16 temp = r.alt.w.bc;
|
||||
uint16_t temp = r.alt.w.bc;
|
||||
r.alt.w.bc = rp.bc;
|
||||
rp.bc = temp;
|
||||
|
||||
|
@ -815,7 +808,7 @@ possibly_out_of_time:
|
|||
// Rotate left
|
||||
|
||||
#define RLC( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
result = uint8_t (result << 1) | (result >> 7);\
|
||||
flags = SZ28P( result ) | (result & C01);\
|
||||
write;\
|
||||
|
@ -834,7 +827,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define RL( read, write ) {\
|
||||
fuint16 result = (read << 1) | (flags & C01);\
|
||||
uint16_t result = (read << 1) | (flags & C01);\
|
||||
flags = SZ28PC( result );\
|
||||
write;\
|
||||
goto loop;\
|
||||
|
@ -852,7 +845,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SLA( read, add, write ) {\
|
||||
fuint16 result = (read << 1) | add;\
|
||||
uint16_t result = (read << 1) | add;\
|
||||
flags = SZ28PC( result );\
|
||||
write;\
|
||||
goto loop;\
|
||||
|
@ -883,7 +876,7 @@ possibly_out_of_time:
|
|||
// Rotate right
|
||||
|
||||
#define RRC( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result = uint8_t (result << 7) | (result >> 1);\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -903,8 +896,8 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define RR( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
fuint8 temp = result & C01;\
|
||||
uint8_t result = read;\
|
||||
uint8_t temp = result & C01;\
|
||||
result = uint8_t (flags << 7) | (result >> 1);\
|
||||
flags = SZ28P( result ) | temp;\
|
||||
write;\
|
||||
|
@ -923,7 +916,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SRA( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result = (result & 0x80) | (result >> 1);\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -943,7 +936,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SRL( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result >>= 1;\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -1048,7 +1041,7 @@ possibly_out_of_time:
|
|||
blargg_ulong sum = temp + (flags & C01);
|
||||
flags = ~data >> 2 & N02;
|
||||
if ( flags )
|
||||
sum = (blargg_ulong)-(blargg_long)sum;
|
||||
sum = -sum;
|
||||
sum += rp.hl;
|
||||
temp ^= rp.hl;
|
||||
temp ^= sum;
|
||||
|
@ -1056,7 +1049,7 @@ possibly_out_of_time:
|
|||
(temp >> 8 & H10) |
|
||||
(sum >> 8 & (S80 | F20 | F08)) |
|
||||
((temp - -0x8000) >> 14 & V04);
|
||||
rp.hl = (uint16_t)sum;
|
||||
rp.hl = sum;
|
||||
if ( (uint16_t) sum )
|
||||
goto loop;
|
||||
flags |= Z40;
|
||||
|
@ -1084,7 +1077,7 @@ possibly_out_of_time:
|
|||
case 0x43: // LD (ADDR),BC
|
||||
case 0x53: // LD (ADDR),DE
|
||||
temp = R16( data, 4, 0x43 );
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, temp );
|
||||
goto loop;
|
||||
|
@ -1092,21 +1085,21 @@ possibly_out_of_time:
|
|||
|
||||
case 0x4B: // LD BC,(ADDR)
|
||||
case 0x5B:{// LD DE,(ADDR)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x7B:{// LD SP,(ADDR)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
sp = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x67:{// RRD
|
||||
fuint8 temp = READ( rp.hl );
|
||||
uint8_t temp = READ( rp.hl );
|
||||
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
||||
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
||||
flags = (flags & C01) | SZ28P( temp );
|
||||
|
@ -1115,7 +1108,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x6F:{// RLD
|
||||
fuint8 temp = READ( rp.hl );
|
||||
uint8_t temp = READ( rp.hl );
|
||||
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
||||
temp = (rg.a & 0xF0) | (temp >> 4);
|
||||
flags = (flags & C01) | SZ28P( temp );
|
||||
|
@ -1139,7 +1132,7 @@ possibly_out_of_time:
|
|||
case 0xA1: // CPI
|
||||
case 0xB1: // CPIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1172,7 +1165,7 @@ possibly_out_of_time:
|
|||
case 0xA0: // LDI
|
||||
case 0xB0: // LDIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1204,7 +1197,7 @@ possibly_out_of_time:
|
|||
case 0xA3: // OUTI
|
||||
case 0xB3: // OTIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1230,7 +1223,7 @@ possibly_out_of_time:
|
|||
case 0xB2: // INIR
|
||||
inc = +1;
|
||||
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
|
||||
int temp = IN( rp.bc );
|
||||
|
@ -1295,7 +1288,7 @@ possibly_out_of_time:
|
|||
|
||||
//////////////////////////////////////// DD/FD prefix
|
||||
{
|
||||
fuint16 ixy;
|
||||
uint16_t ixy;
|
||||
case 0xDD:
|
||||
ixy = ix;
|
||||
goto ix_prefix;
|
||||
|
@ -1490,7 +1483,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x22:{// LD (ADDR),IXY
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, ixy );
|
||||
goto loop;
|
||||
|
@ -1502,7 +1495,7 @@ possibly_out_of_time:
|
|||
goto set_ixy;
|
||||
|
||||
case 0x2A:{// LD IXY,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
ixy = READ_WORD( addr );
|
||||
pc += 2;
|
||||
goto set_ixy;
|
||||
|
@ -1526,7 +1519,7 @@ possibly_out_of_time:
|
|||
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
||||
|
||||
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);
|
||||
flags = (flags & C01) | H10 |
|
||||
(masked & S80) |
|
||||
|
@ -1628,7 +1621,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xE3:{// EX (SP),IXY
|
||||
fuint16 temp = READ_WORD( sp );
|
||||
uint16_t temp = READ_WORD( sp );
|
||||
WRITE_WORD( sp, ixy );
|
||||
ixy = temp;
|
||||
goto set_ixy;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Z80 CPU emulator
|
||||
|
||||
// Game_Music_Emu 0.6.0
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
#ifndef 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 adjust_time( int delta ) { state->time += delta; }
|
||||
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
typedef BOOST::uint16_t uint16_t;
|
||||
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
struct regs_t { uint8_t b, c, d, e, h, l, flags, a; };
|
||||
#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"
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
long pos = long(ptr - (byte const*) file.header);
|
||||
long file_size = long(file.end - (byte const*) file.header);
|
||||
long pos = ptr - (byte const*) file.header;
|
||||
long file_size = file.end - (byte const*) file.header;
|
||||
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) )
|
||||
return 0;
|
||||
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 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
|
||||
|
||||
|
@ -207,7 +207,7 @@ blargg_err_t Ay_Emu::start_track_( int track )
|
|||
if ( len > blargg_ulong (file.end - in) )
|
||||
{
|
||||
set_warning( "Missing file data" );
|
||||
len = unsigned(file.end - in);
|
||||
len = file.end - in;
|
||||
}
|
||||
//debug_printf( "addr: $%04X, len: $%04X\n", addr, len );
|
||||
if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define AY_EMU_H
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ public:
|
|||
Blip_Buffer();
|
||||
~Blip_Buffer();
|
||||
|
||||
Blip_Buffer(Blip_Buffer &&) = default;
|
||||
|
||||
// Deprecated
|
||||
typedef blip_resampled_time_t resampled_time_t;
|
||||
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
|
||||
)
|
||||
|
||||
# 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
|
||||
if (USE_GME_AY OR USE_GME_KSS)
|
||||
set(libgme_SRCS ${libgme_SRCS}
|
||||
|
@ -23,9 +32,25 @@ endif()
|
|||
|
||||
# so is Ym2612_Emu
|
||||
if (USE_GME_VGM OR USE_GME_GYM)
|
||||
set(libgme_SRCS ${libgme_SRCS}
|
||||
Ym2612_Emu.cpp
|
||||
)
|
||||
if(GME_YM2612_EMU STREQUAL "Nuked")
|
||||
add_definitions(-DVGM_YM2612_NUKED)
|
||||
set(libgme_SRCS ${libgme_SRCS}
|
||||
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()
|
||||
|
||||
# But none are as popular as Sms_Apu
|
||||
|
@ -127,19 +152,11 @@ endif()
|
|||
# These headers are part of the generic gme interface.
|
||||
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
|
||||
# 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.
|
||||
|
||||
#[ZDoom] Not needed
|
||||
#add_definitions(-DBLARGG_BUILD_DLL)
|
||||
|
||||
# For the gme_types.h
|
||||
|
@ -148,13 +165,25 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|||
# Add library to be compiled.
|
||||
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
|
||||
# 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.
|
||||
# The way gme.h is designed, SOVERSION should very rarely be bumped, if ever.
|
||||
# Hopefully the API can stay compatible with old versions.
|
||||
# [ZDoom] Not needed.
|
||||
if( FALSE )
|
||||
set_target_properties(gme
|
||||
PROPERTIES VERSION ${GME_VERSION}
|
||||
SOVERSION 0)
|
||||
|
@ -163,8 +192,13 @@ install(TARGETS gme LIBRARY DESTINATION lib${LIB_SUFFIX}
|
|||
RUNTIME DESTINATION bin # 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 ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
||||
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"
|
||||
|
||||
|
@ -54,6 +54,12 @@ blargg_err_t Classic_Emu::set_sample_rate_( long rate )
|
|||
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 )
|
||||
{
|
||||
Music_Emu::mute_voices_( mask );
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define CLASSIC_EMU_H
|
||||
|
||||
|
@ -13,6 +13,7 @@ public:
|
|||
Classic_Emu();
|
||||
~Classic_Emu();
|
||||
void set_buffer( Multi_Buffer* );
|
||||
blargg_err_t set_multi_channel( bool is_enabled ) override;
|
||||
protected:
|
||||
// Services
|
||||
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/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include "Data_Reader.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
|
@ -22,24 +20,38 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
|
||||
#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";
|
||||
|
||||
#define RETURN_VALIDITY_CHECK( cond ) \
|
||||
do { if ( unlikely( !(cond) ) ) return "Corrupt file"; } while(0)
|
||||
|
||||
blargg_err_t Data_Reader::read( void* p, long s )
|
||||
{
|
||||
RETURN_VALIDITY_CHECK( s > 0 );
|
||||
|
||||
long result = read_avail( p, s );
|
||||
if ( result != s )
|
||||
{
|
||||
if ( result >= 0 && result < s )
|
||||
return eof_error;
|
||||
|
||||
|
||||
return "Read error";
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
blargg_err_t Data_Reader::skip( long count )
|
||||
{
|
||||
RETURN_VALIDITY_CHECK( count >= 0 );
|
||||
|
||||
char buf [512];
|
||||
while ( count )
|
||||
{
|
||||
|
@ -56,7 +68,8 @@ long File_Reader::remain() const { return size() - tell(); }
|
|||
|
||||
blargg_err_t File_Reader::skip( long n )
|
||||
{
|
||||
assert( n >= 0 );
|
||||
RETURN_VALIDITY_CHECK( n >= 0 );
|
||||
|
||||
if ( !n )
|
||||
return 0;
|
||||
return seek( tell() + n );
|
||||
|
@ -69,13 +82,14 @@ Subset_Reader::Subset_Reader( Data_Reader* dr, long size )
|
|||
in = dr;
|
||||
remain_ = dr->remain();
|
||||
if ( remain_ > size )
|
||||
remain_ = size;
|
||||
remain_ = max( 0l, size );
|
||||
}
|
||||
|
||||
long Subset_Reader::remain() const { return remain_; }
|
||||
|
||||
long Subset_Reader::read_avail( void* p, long s )
|
||||
{
|
||||
s = max( 0l, s );
|
||||
if ( s > remain_ )
|
||||
s = remain_;
|
||||
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 )
|
||||
{
|
||||
header = (char const*) h;
|
||||
header_end = header + size;
|
||||
header_end = header + max( 0l, size );
|
||||
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 first = long(header_end - header);
|
||||
count = max( 0l, count );
|
||||
long first = header_end - header;
|
||||
if ( first )
|
||||
{
|
||||
if ( first > count )
|
||||
if ( first > count || first < 0 )
|
||||
first = count;
|
||||
void const* old = header;
|
||||
header += first;
|
||||
memcpy( out, old, first );
|
||||
memcpy( out, old, (size_t) first );
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
long Remaining_Reader::read_avail( void* out, long count )
|
||||
{
|
||||
count = max( 0l, count );
|
||||
long first = read_first( out, count );
|
||||
long second = count - first;
|
||||
long second = max( 0l, count - first );
|
||||
if ( 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 )
|
||||
{
|
||||
count = max( 0l, count );
|
||||
long first = read_first( out, count );
|
||||
long second = count - first;
|
||||
long second = max( 0l, count - first );
|
||||
if ( !second )
|
||||
return 0;
|
||||
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( const void* p, long s ) :
|
||||
begin( (const char*) p ),
|
||||
size_( s )
|
||||
m_begin( (const char*) p ),
|
||||
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 r = remain();
|
||||
if ( s > r )
|
||||
if ( s > r || s < 0 )
|
||||
s = r;
|
||||
memcpy( p, begin + pos, s );
|
||||
pos += s;
|
||||
memcpy( p, m_begin + m_pos, static_cast<size_t>(s) );
|
||||
m_pos += 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 )
|
||||
{
|
||||
if ( n > size_ )
|
||||
RETURN_VALIDITY_CHECK( n >= 0 );
|
||||
if ( n > m_size )
|
||||
return eof_error;
|
||||
pos = n;
|
||||
m_pos = n;
|
||||
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_t c, long size, void* d ) :
|
||||
callback( c ),
|
||||
data( d )
|
||||
{
|
||||
remain_ = size;
|
||||
remain_ = max( 0l, size );
|
||||
}
|
||||
|
||||
long Callback_Reader::remain() const { return remain_; }
|
||||
|
@ -175,34 +286,82 @@ long Callback_Reader::read_avail( void* out, long count )
|
|||
{
|
||||
if ( count > remain_ )
|
||||
count = remain_;
|
||||
if ( Callback_Reader::read( out, count ) )
|
||||
if ( count < 0 || Callback_Reader::read( out, count ) )
|
||||
count = -1;
|
||||
return count;
|
||||
}
|
||||
|
||||
blargg_err_t Callback_Reader::read( void* out, long count )
|
||||
{
|
||||
RETURN_VALIDITY_CHECK( count >= 0 );
|
||||
if ( count > remain_ )
|
||||
return eof_error;
|
||||
return callback( data, out, count );
|
||||
return callback( data, out, (int) count );
|
||||
}
|
||||
|
||||
// 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(); }
|
||||
|
||||
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" );
|
||||
#endif
|
||||
|
||||
if ( !file_ )
|
||||
return "Couldn't open file";
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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();
|
||||
fseek( (FILE*) file_, 0, SEEK_END );
|
||||
long result = tell();
|
||||
|
@ -212,24 +371,64 @@ long Std_File_Reader::size() const
|
|||
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
if ( feof( (FILE*) file_ ) )
|
||||
if ( feof( file ) )
|
||||
return eof_error;
|
||||
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 )
|
||||
{
|
||||
if ( !fseek( (FILE*) file_, n, SEEK_SET ) )
|
||||
return 0;
|
||||
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||
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() )
|
||||
return eof_error;
|
||||
return "Error seeking in file";
|
||||
|
@ -239,79 +438,12 @@ void Std_File_Reader::close()
|
|||
{
|
||||
if ( file_ )
|
||||
{
|
||||
fclose( (FILE*) file_ );
|
||||
file_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H
|
||||
gzclose( reinterpret_cast<gzFile>( file_ ) );
|
||||
#else
|
||||
fclose( reinterpret_cast<FILE*>( file_ ) );
|
||||
#endif
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#include "blargg_common.h"
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
// Supports reading and finding out how many bytes are remaining
|
||||
class Data_Reader {
|
||||
public:
|
||||
|
@ -65,25 +69,39 @@ public:
|
|||
long tell() const;
|
||||
blargg_err_t seek( long );
|
||||
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
|
||||
class Mem_File_Reader : public File_Reader {
|
||||
public:
|
||||
Mem_File_Reader( const void*, long size );
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
~Mem_File_Reader( );
|
||||
#endif /* HAVE_ZLIB_H */
|
||||
|
||||
public:
|
||||
long size() const;
|
||||
long read_avail( void*, long );
|
||||
long tell() const;
|
||||
blargg_err_t seek( long );
|
||||
private:
|
||||
const char* const begin;
|
||||
const long size_;
|
||||
long pos;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
bool gz_decompress();
|
||||
#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
|
||||
class Subset_Reader : public Data_Reader {
|
||||
public:
|
||||
|
@ -128,26 +146,4 @@ private:
|
|||
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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -18,7 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
|
||||
#include "blargg_source.h"
|
||||
|
||||
//unsigned const resampler_extra = 256;
|
||||
unsigned const resampler_extra = 256;
|
||||
|
||||
Dual_Resampler::Dual_Resampler() :
|
||||
sample_buf_size(0),
|
||||
|
@ -68,10 +68,13 @@ void Dual_Resampler::play_frame_( Blip_Buffer& blip_buf, dsample_t* out )
|
|||
assert( blip_buf.samples_avail() == pair_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 );
|
||||
assert( count == (long) sample_buf_size );
|
||||
(void)count; // Silence warning in non-debug build
|
||||
#endif
|
||||
|
||||
mix_samples( blip_buf, out );
|
||||
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();
|
||||
blargg_long l = (blargg_long) in [0] * 2 + s;
|
||||
if ( (BOOST::int16_t) l != l )
|
||||
if ( (int16_t) l != l )
|
||||
l = 0x7FFF - (l >> 24);
|
||||
|
||||
sn.next( bass );
|
||||
blargg_long r = (blargg_long) in [1] * 2 + s;
|
||||
if ( (BOOST::int16_t) r != r )
|
||||
if ( (int16_t) r != r )
|
||||
r = 0x7FFF - (r >> 24);
|
||||
|
||||
in += 2;
|
||||
out [0] = (dsample_t)l;
|
||||
out [1] = (dsample_t)r;
|
||||
out [0] = l;
|
||||
out [1] = r;
|
||||
out += 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -63,29 +63,49 @@ void Effects_Buffer::set_depth( double d )
|
|||
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 );
|
||||
}
|
||||
|
||||
Effects_Buffer::~Effects_Buffer() { }
|
||||
Effects_Buffer::~Effects_Buffer()
|
||||
{}
|
||||
|
||||
blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec )
|
||||
{
|
||||
if ( !echo_buf.size() )
|
||||
RETURN_ERR( echo_buf.resize( echo_size ) );
|
||||
|
||||
if ( !reverb_buf.size() )
|
||||
RETURN_ERR( reverb_buf.resize( reverb_size ) );
|
||||
|
||||
try
|
||||
{
|
||||
for(int i=0; i<max_voices; i++)
|
||||
{
|
||||
if ( !echo_buf[i].size() )
|
||||
{
|
||||
echo_buf[i].resize( echo_size );
|
||||
}
|
||||
|
||||
if ( !reverb_buf[i].size() )
|
||||
{
|
||||
reverb_buf[i].resize( reverb_size );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(std::bad_alloc& ba)
|
||||
{
|
||||
return "Out of memory";
|
||||
}
|
||||
|
||||
for ( int i = 0; i < buf_count; i++ )
|
||||
RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
|
||||
|
||||
|
@ -111,12 +131,16 @@ void Effects_Buffer::clear()
|
|||
{
|
||||
stereo_remain = 0;
|
||||
effect_remain = 0;
|
||||
if ( echo_buf.size() )
|
||||
memset( &echo_buf [0], 0, echo_size * sizeof echo_buf [0] );
|
||||
|
||||
if ( reverb_buf.size() )
|
||||
memset( &reverb_buf [0], 0, reverb_size * sizeof reverb_buf [0] );
|
||||
|
||||
|
||||
for(int i=0; i<max_voices; i++)
|
||||
{
|
||||
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++ )
|
||||
bufs [i].clear();
|
||||
}
|
||||
|
@ -135,12 +159,17 @@ void Effects_Buffer::config( const config_t& cfg )
|
|||
channels_changed();
|
||||
|
||||
// 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] );
|
||||
memset( &reverb_buf [0], 0, reverb_size * sizeof reverb_buf [0] );
|
||||
for(int i=0; i<max_voices; i++)
|
||||
{
|
||||
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;
|
||||
|
||||
if ( config_.effects_enabled )
|
||||
|
@ -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),
|
||||
echo_size - 1 );
|
||||
|
||||
chan_types [0].center = &bufs [0];
|
||||
chan_types [0].left = &bufs [3];
|
||||
chan_types [0].right = &bufs [4];
|
||||
|
||||
chan_types [1].center = &bufs [1];
|
||||
chan_types [1].left = &bufs [3];
|
||||
chan_types [1].right = &bufs [4];
|
||||
|
||||
chan_types [2].center = &bufs [2];
|
||||
chan_types [2].left = &bufs [5];
|
||||
chan_types [2].right = &bufs [6];
|
||||
for(int i=0; i<max_voices; i++)
|
||||
{
|
||||
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 [i*chan_types_count+1].center = &bufs [i*max_buf_count+1];
|
||||
chan_types [i*chan_types_count+1].left = &bufs [i*max_buf_count+3];
|
||||
chan_types [i*chan_types_count+1].right = &bufs [i*max_buf_count+4];
|
||||
|
||||
chan_types [i*chan_types_count+2].center = &bufs [i*max_buf_count+2];
|
||||
chan_types [i*chan_types_count+2].left = &bufs [i*max_buf_count+5];
|
||||
chan_types [i*chan_types_count+2].right = &bufs [i*max_buf_count+6];
|
||||
}
|
||||
assert( 2 < chan_types_count );
|
||||
}
|
||||
else
|
||||
{
|
||||
// set up outputs
|
||||
for ( unsigned i = 0; i < chan_types_count; i++ )
|
||||
for(int i=0; i<max_voices; i++)
|
||||
{
|
||||
channel_t& c = chan_types [i];
|
||||
c.center = &bufs [0];
|
||||
c.left = &bufs [1];
|
||||
c.right = &bufs [2];
|
||||
// set up outputs
|
||||
for ( int j = 0; j < chan_types_count; j++ )
|
||||
{
|
||||
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];
|
||||
c.left = c.center;
|
||||
c.right = c.center;
|
||||
for ( int j = 0; j < chan_types_count; j++ )
|
||||
{
|
||||
channel_t& c = chan_types [i*chan_types_count+j];
|
||||
c.left = c.center;
|
||||
c.right = c.center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Effects_Buffer::channel_t Effects_Buffer::channel( int i, int type )
|
||||
{
|
||||
int out = 2;
|
||||
int out = chan_types_count-1;
|
||||
if ( !type )
|
||||
{
|
||||
out = i % 5;
|
||||
if ( out > 2 )
|
||||
out = 2;
|
||||
if ( out > chan_types_count-1 )
|
||||
out = chan_types_count-1;
|
||||
}
|
||||
else if ( !(type & noise_type) && (type & type_index_mask) % 3 != 0 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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);
|
||||
if ( (bufs_used & stereo_mask) && buf_count == max_buf_count )
|
||||
stereo_remain = bufs [0].samples_avail() + bufs [0].output_latency();
|
||||
|
||||
if ( effects_enabled || config_.effects_enabled )
|
||||
effect_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 )
|
||||
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;
|
||||
}
|
||||
|
@ -248,15 +291,17 @@ long Effects_Buffer::samples_avail() const
|
|||
|
||||
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();
|
||||
if ( remain > (total_samples >> 1) )
|
||||
remain = (total_samples >> 1);
|
||||
total_samples = remain;
|
||||
total_samples = remain = min( remain, total_samples/n_channels );
|
||||
|
||||
while ( remain )
|
||||
{
|
||||
int active_bufs = buf_count;
|
||||
int active_bufs = buf_count_per_voice;
|
||||
long count = remain;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
out += count * 2;
|
||||
out += count * n_channels;
|
||||
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 )
|
||||
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
|
||||
{
|
||||
if ( i < active_bufs )
|
||||
bufs [i].remove_samples( count );
|
||||
else
|
||||
bufs [i].remove_silence( count ); // keep time synchronized
|
||||
for ( int i = 0; i < buf_count_per_voice; i++) // foreach buffer of that voice
|
||||
{
|
||||
if ( i < active_bufs )
|
||||
bufs [v*buf_count_per_voice + i].remove_samples( count );
|
||||
else // 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 )
|
||||
{
|
||||
for(int i=0; i<max_voices; i++)
|
||||
{
|
||||
blip_sample_t* BLIP_RESTRICT out = out_;
|
||||
int const bass = BLIP_READER_BASS( bufs [0] );
|
||||
BLIP_READER_BEGIN( c, bufs [0] );
|
||||
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_BEGIN( c, bufs [i*max_buf_count+0] );
|
||||
|
||||
// unrolled loop
|
||||
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 );
|
||||
BLIP_READER_NEXT( c, bass );
|
||||
|
||||
if ( (BOOST::int16_t) cs0 != cs0 )
|
||||
if ( (int16_t) cs0 != cs0 )
|
||||
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);
|
||||
((BOOST::uint32_t*) out) [1] = ((BOOST::uint16_t) cs1) | (cs1 << 16);
|
||||
out += 4;
|
||||
((uint32_t*) out) [i*2+1] = ((uint16_t) cs1) | (uint16_t(cs1) << 16);
|
||||
out += max_voices*4;
|
||||
}
|
||||
|
||||
if ( count & 1 )
|
||||
{
|
||||
int s = BLIP_READER_READ( c );
|
||||
BLIP_READER_NEXT( c, bass );
|
||||
out [0] = s;
|
||||
out [1] = s;
|
||||
if ( (BOOST::int16_t) s != s )
|
||||
out [i*2+0] = s;
|
||||
out [i*2+1] = s;
|
||||
if ( (int16_t) s != s )
|
||||
{
|
||||
s = 0x7FFF - (s >> 24);
|
||||
out [0] = s;
|
||||
out [1] = s;
|
||||
out [i*2+0] = 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_;
|
||||
int const bass = BLIP_READER_BASS( bufs [0] );
|
||||
BLIP_READER_BEGIN( c, bufs [0] );
|
||||
BLIP_READER_BEGIN( l, bufs [1] );
|
||||
BLIP_READER_BEGIN( r, bufs [2] );
|
||||
|
||||
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_BEGIN( c, bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_BEGIN( l, bufs [i*max_buf_count+1] );
|
||||
BLIP_READER_BEGIN( r, bufs [i*max_buf_count+2] );
|
||||
|
||||
int count = frames;
|
||||
while ( count-- )
|
||||
{
|
||||
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( r, bass );
|
||||
|
||||
if ( (BOOST::int16_t) left != left )
|
||||
if ( (int16_t) left != left )
|
||||
left = 0x7FFF - (left >> 24);
|
||||
|
||||
out [0] = left;
|
||||
out [1] = right;
|
||||
if ( (int16_t) right != right )
|
||||
right = 0x7FFF - (right >> 24);
|
||||
|
||||
out [i*2+0] = left;
|
||||
out [i*2+1] = right;
|
||||
|
||||
out += 2;
|
||||
out += max_voices*2;
|
||||
|
||||
if ( (BOOST::int16_t) right != right )
|
||||
out [-1] = 0x7FFF - (right >> 24);
|
||||
}
|
||||
|
||||
BLIP_READER_END( r, bufs [2] );
|
||||
BLIP_READER_END( l, bufs [1] );
|
||||
BLIP_READER_END( c, bufs [0] );
|
||||
BLIP_READER_END( r, bufs [i*max_buf_count+2] );
|
||||
BLIP_READER_END( l, bufs [i*max_buf_count+1] );
|
||||
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_;
|
||||
int const bass = BLIP_READER_BASS( bufs [2] );
|
||||
BLIP_READER_BEGIN( center, bufs [2] );
|
||||
BLIP_READER_BEGIN( sq1, bufs [0] );
|
||||
BLIP_READER_BEGIN( sq2, bufs [1] );
|
||||
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+2] );
|
||||
BLIP_READER_BEGIN( center, bufs [i*max_buf_count+2] );
|
||||
BLIP_READER_BEGIN( sq1, bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_BEGIN( sq2, bufs [i*max_buf_count+1] );
|
||||
|
||||
blip_sample_t* const reverb_buf = this->reverb_buf.begin();
|
||||
blip_sample_t* const echo_buf = this->echo_buf.begin();
|
||||
int echo_pos = this->echo_pos;
|
||||
int reverb_pos = this->reverb_pos;
|
||||
blip_sample_t* const reverb_buf = &this->reverb_buf[i][0];
|
||||
blip_sample_t* const echo_buf = &this->echo_buf[i][0];
|
||||
int echo_pos = this->echo_pos[i];
|
||||
int reverb_pos = this->reverb_pos[i];
|
||||
|
||||
int count = frames;
|
||||
while ( count-- )
|
||||
{
|
||||
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_pos = (echo_pos + 1) & echo_mask;
|
||||
|
||||
if ( (BOOST::int16_t) left != left )
|
||||
if ( (int16_t) left != left )
|
||||
left = 0x7FFF - (left >> 24);
|
||||
|
||||
out [0] = left;
|
||||
out [1] = right;
|
||||
|
||||
out += 2;
|
||||
|
||||
if ( (BOOST::int16_t) right != right )
|
||||
out [-1] = 0x7FFF - (right >> 24);
|
||||
if ( (int16_t) right != right )
|
||||
right = 0x7FFF - (right >> 24);
|
||||
|
||||
out [i*2+0] = left;
|
||||
out [i*2+1] = right;
|
||||
out += max_voices*2;
|
||||
}
|
||||
this->reverb_pos = reverb_pos;
|
||||
this->echo_pos = echo_pos;
|
||||
this->reverb_pos[i] = reverb_pos;
|
||||
this->echo_pos[i] = echo_pos;
|
||||
|
||||
BLIP_READER_END( sq1, bufs [0] );
|
||||
BLIP_READER_END( sq2, bufs [1] );
|
||||
BLIP_READER_END( center, bufs [2] );
|
||||
BLIP_READER_END( sq1, bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_END( sq2, bufs [i*max_buf_count+1] );
|
||||
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_;
|
||||
int const bass = BLIP_READER_BASS( bufs [2] );
|
||||
BLIP_READER_BEGIN( center, bufs [2] );
|
||||
BLIP_READER_BEGIN( l1, bufs [3] );
|
||||
BLIP_READER_BEGIN( r1, bufs [4] );
|
||||
BLIP_READER_BEGIN( l2, bufs [5] );
|
||||
BLIP_READER_BEGIN( r2, bufs [6] );
|
||||
BLIP_READER_BEGIN( sq1, bufs [0] );
|
||||
BLIP_READER_BEGIN( sq2, bufs [1] );
|
||||
int const bass = BLIP_READER_BASS( bufs [i*max_buf_count+2] );
|
||||
BLIP_READER_BEGIN( center, bufs [i*max_buf_count+2] );
|
||||
BLIP_READER_BEGIN( l1, bufs [i*max_buf_count+3] );
|
||||
BLIP_READER_BEGIN( r1, bufs [i*max_buf_count+4] );
|
||||
BLIP_READER_BEGIN( l2, bufs [i*max_buf_count+5] );
|
||||
BLIP_READER_BEGIN( r2, bufs [i*max_buf_count+6] );
|
||||
BLIP_READER_BEGIN( sq1, bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_BEGIN( sq2, bufs [i*max_buf_count+1] );
|
||||
|
||||
blip_sample_t* const reverb_buf = this->reverb_buf.begin();
|
||||
blip_sample_t* const echo_buf = this->echo_buf.begin();
|
||||
int echo_pos = this->echo_pos;
|
||||
int reverb_pos = this->reverb_pos;
|
||||
blip_sample_t* const reverb_buf = &this->reverb_buf[i][0];
|
||||
blip_sample_t* const echo_buf = &this->echo_buf[i][0];
|
||||
int echo_pos = this->echo_pos[i];
|
||||
int reverb_pos = this->reverb_pos[i];
|
||||
|
||||
int count = frames;
|
||||
while ( count-- )
|
||||
{
|
||||
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_pos = (echo_pos + 1) & echo_mask;
|
||||
|
||||
if ( (BOOST::int16_t) left != left )
|
||||
if ( (int16_t) left != left )
|
||||
left = 0x7FFF - (left >> 24);
|
||||
|
||||
out [0] = left;
|
||||
out [1] = right;
|
||||
|
||||
out += 2;
|
||||
|
||||
if ( (BOOST::int16_t) right != right )
|
||||
out [-1] = 0x7FFF - (right >> 24);
|
||||
if ( (int16_t) right != right )
|
||||
right = 0x7FFF - (right >> 24);
|
||||
|
||||
out [i*2+0] = left;
|
||||
out [i*2+1] = right;
|
||||
|
||||
out += max_voices*2;
|
||||
}
|
||||
this->reverb_pos = reverb_pos;
|
||||
this->echo_pos = echo_pos;
|
||||
this->reverb_pos[i] = reverb_pos;
|
||||
this->echo_pos[i] = echo_pos;
|
||||
|
||||
BLIP_READER_END( l1, bufs [3] );
|
||||
BLIP_READER_END( r1, bufs [4] );
|
||||
BLIP_READER_END( l2, bufs [5] );
|
||||
BLIP_READER_END( r2, bufs [6] );
|
||||
BLIP_READER_END( sq1, bufs [0] );
|
||||
BLIP_READER_END( sq2, bufs [1] );
|
||||
BLIP_READER_END( center, bufs [2] );
|
||||
BLIP_READER_END( l1, bufs [i*max_buf_count+3] );
|
||||
BLIP_READER_END( r1, bufs [i*max_buf_count+4] );
|
||||
BLIP_READER_END( l2, bufs [i*max_buf_count+5] );
|
||||
BLIP_READER_END( r2, bufs [i*max_buf_count+6] );
|
||||
BLIP_READER_END( sq1, bufs [i*max_buf_count+0] );
|
||||
BLIP_READER_END( sq2, bufs [i*max_buf_count+1] );
|
||||
BLIP_READER_END( center, bufs [i*max_buf_count+2] );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
// 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
|
||||
#define EFFECTS_BUFFER_H
|
||||
|
||||
#include "Multi_Buffer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Effects_Buffer uses several buffers and outputs stereo sample pairs.
|
||||
class Effects_Buffer : public Multi_Buffer {
|
||||
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
|
||||
// less memory is used.
|
||||
Effects_Buffer( bool center_only = false );
|
||||
Effects_Buffer( int nVoices = 1, bool center_only = false );
|
||||
|
||||
// Channel Effect Center Pan
|
||||
// ---------------------------------
|
||||
|
@ -50,21 +54,21 @@ public:
|
|||
long samples_avail() const;
|
||||
private:
|
||||
typedef long fixed_t;
|
||||
|
||||
int max_voices;
|
||||
enum { max_buf_count = 7 };
|
||||
Blip_Buffer bufs [max_buf_count];
|
||||
std::vector<Blip_Buffer> bufs;
|
||||
enum { chan_types_count = 3 };
|
||||
channel_t chan_types [3];
|
||||
std::vector<channel_t> chan_types;
|
||||
config_t config_;
|
||||
long stereo_remain;
|
||||
long effect_remain;
|
||||
int buf_count;
|
||||
bool effects_enabled;
|
||||
|
||||
blargg_vector<blip_sample_t> reverb_buf;
|
||||
blargg_vector<blip_sample_t> echo_buf;
|
||||
int reverb_pos;
|
||||
int echo_pos;
|
||||
std::vector<std::vector<blip_sample_t> > reverb_buf;
|
||||
std::vector<std::vector<blip_sample_t> > echo_buf;
|
||||
std::vector<int> reverb_pos;
|
||||
std::vector<int> echo_pos;
|
||||
|
||||
struct {
|
||||
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"
|
||||
|
||||
|
@ -23,10 +23,6 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
#undef PI
|
||||
#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,
|
||||
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_ ) :
|
||||
width_( width ),
|
||||
write_offset( width * stereo - stereo ),
|
||||
|
@ -164,7 +156,7 @@ int Fir_Resampler_::input_needed( blargg_long output_count ) const
|
|||
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 )
|
||||
input_extra = 0;
|
||||
return input_extra;
|
||||
|
@ -194,8 +186,8 @@ int Fir_Resampler_::avail_( blargg_long input_count ) const
|
|||
|
||||
int Fir_Resampler_::skip_input( long count )
|
||||
{
|
||||
int remain = int(write_pos - buf.begin());
|
||||
int max_count = int(remain - width_ * stereo);
|
||||
int remain = write_pos - buf.begin();
|
||||
int max_count = remain - width_ * stereo;
|
||||
if ( count > max_count )
|
||||
count = max_count;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define FIR_RESAMPLER_H
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
|||
void clear();
|
||||
|
||||
// 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
|
||||
sample_t* buffer() { return write_pos; }
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
void write( long count );
|
||||
|
||||
// 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.
|
||||
int skip_input( long count );
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
int input_needed( blargg_long count ) const;
|
||||
|
||||
// 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:
|
||||
~Fir_Resampler_();
|
||||
|
@ -161,11 +161,11 @@ int Fir_Resampler<width>::read( sample_t* out_begin, blargg_long count )
|
|||
|
||||
imp_phase = res - remain;
|
||||
|
||||
int left = int(write_pos - in);
|
||||
int left = write_pos - in;
|
||||
write_pos = &buf [left];
|
||||
memmove( buf.begin(), in, left * sizeof *in );
|
||||
|
||||
return int(out - out_begin);
|
||||
return out - out_begin;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -123,7 +123,7 @@ void Gb_Apu::reset()
|
|||
0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
|
||||
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 )
|
||||
|
|
|
@ -68,7 +68,7 @@ private:
|
|||
Gb_Square square2;
|
||||
Gb_Wave wave;
|
||||
Gb_Noise noise;
|
||||
BOOST::uint8_t regs [register_count];
|
||||
uint8_t regs [register_count];
|
||||
Gb_Square::Synth square_synth; // used by squares
|
||||
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"
|
||||
|
||||
|
@ -89,12 +89,6 @@ unsigned const n_flag = 0x40;
|
|||
unsigned const h_flag = 0x20;
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
memcpy( &s, &this->state_, sizeof s );
|
||||
|
||||
typedef BOOST::uint16_t uint16_t;
|
||||
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
#define R8( n ) (r8_ [n])
|
||||
#elif BLARGG_LITTLE_ENDIAN
|
||||
|
@ -116,11 +108,11 @@ bool Gb_Cpu::run( blargg_long cycle_count )
|
|||
core_regs_t rg; // individual registers
|
||||
|
||||
struct {
|
||||
BOOST::uint16_t bc, de, hl, unused; // pairs
|
||||
uint16_t bc, de, hl, unused; // pairs
|
||||
} rp;
|
||||
|
||||
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 );
|
||||
|
||||
|
@ -168,7 +160,7 @@ loop:
|
|||
#define BRANCH( cond )\
|
||||
{\
|
||||
pc++;\
|
||||
int offset = (BOOST::int8_t) data;\
|
||||
int offset = (int8_t) data;\
|
||||
if ( !(cond) ) goto loop;\
|
||||
pc = uint16_t (pc + offset);\
|
||||
goto loop;\
|
||||
|
@ -688,7 +680,7 @@ loop:
|
|||
unsigned prev;
|
||||
|
||||
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++;
|
||||
flags = 0;
|
||||
temp += sp;
|
||||
|
@ -696,7 +688,7 @@ loop:
|
|||
goto add_16_hl;
|
||||
|
||||
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++;
|
||||
flags = 0;
|
||||
temp += sp;
|
||||
|
@ -717,7 +709,7 @@ loop:
|
|||
temp += prev;
|
||||
flags &= z_flag;
|
||||
add_16_hl:
|
||||
rp.hl = (uint16_t)temp;
|
||||
rp.hl = temp;
|
||||
add_16_comm:
|
||||
flags |= (temp >> 12) & c_flag;
|
||||
flags |= (((temp & 0x0FFF) - (prev & 0x0FFF)) >> 7) & h_flag;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Nintendo Game Boy CPU emulator
|
||||
// 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
|
||||
#define GB_CPU_H
|
||||
|
||||
|
@ -13,8 +13,6 @@ typedef unsigned gb_addr_t; // 16-bit CPU address
|
|||
class Gb_Cpu {
|
||||
enum { clocks_per_instr = 4 };
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Clear registers and map all pages to unmapped
|
||||
void reset( void* unmapped = 0 );
|
||||
|
||||
|
@ -39,7 +37,7 @@ public:
|
|||
|
||||
struct registers_t : core_regs_t {
|
||||
long pc; // more than 16 bits to allow overflow detection
|
||||
BOOST::uint16_t sp;
|
||||
uint16_t sp;
|
||||
};
|
||||
registers_t r;
|
||||
|
||||
|
@ -81,7 +79,7 @@ private:
|
|||
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
|
||||
#if !BLARGG_NONPORTABLE
|
||||
|
|
|
@ -15,7 +15,7 @@ struct Gb_Osc
|
|||
Blip_Buffer* outputs [4]; // NULL, right, left, center
|
||||
Blip_Buffer* output;
|
||||
int output_select;
|
||||
BOOST::uint8_t* regs; // osc's 5 registers
|
||||
uint8_t* regs; // osc's 5 registers
|
||||
|
||||
int delay;
|
||||
int last_amp;
|
||||
|
@ -68,7 +68,7 @@ struct Gb_Wave : Gb_Osc
|
|||
Synth const* synth;
|
||||
int wave_pos;
|
||||
enum { wave_size = 32 };
|
||||
BOOST::uint8_t wave [wave_size];
|
||||
uint8_t wave [wave_size];
|
||||
|
||||
void write_register( int, int );
|
||||
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"
|
||||
|
||||
|
@ -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 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
|
||||
|
||||
|
@ -175,7 +175,7 @@ void Gbs_Emu::update_timer()
|
|||
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
|
||||
0x00, 0x3F, 0x00, 0x00, 0xBF, // square 2
|
||||
0x7F, 0xFF, 0x9F, 0x00, 0xBF, // wave
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
RETURN_ERR( file_data.resize( in.remain() ) );
|
||||
RETURN_ERR( in.read( file_data.begin(), (long)file_data.size() ) );
|
||||
return load_mem_( file_data.begin(), (long)file_data.size() );
|
||||
RETURN_ERR( in.read( file_data.begin(), file_data.size() ) );
|
||||
return load_mem_( file_data.begin(), file_data.size() );
|
||||
}
|
||||
|
||||
// public load functions call this at beginning
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define GME_FILE_H
|
||||
|
||||
|
@ -105,7 +105,7 @@ public:
|
|||
Gme_File();
|
||||
virtual ~Gme_File();
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
typedef BOOST::uint8_t byte;
|
||||
typedef uint8_t byte;
|
||||
protected:
|
||||
// Services
|
||||
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 ); }
|
||||
|
||||
#ifndef GME_FILE_READER
|
||||
#ifdef HAVE_ZLIB_H
|
||||
#define GME_FILE_READER Gzip_File_Reader
|
||||
#else
|
||||
#define GME_FILE_READER Std_File_Reader
|
||||
#endif
|
||||
#define GME_FILE_READER Std_File_Reader
|
||||
#elif defined (GME_FILE_READER_INCLUDE)
|
||||
#include GME_FILE_READER_INCLUDE
|
||||
#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"
|
||||
|
||||
|
@ -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 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
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Sega Genesis/Mega Drive GYM music file emulator
|
||||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -106,10 +106,10 @@ void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time )
|
|||
unsigned noise_lfsr = this->noise_lfsr;
|
||||
do
|
||||
{
|
||||
int new_dac = 0x1F & (unsigned)-(int)(noise_lfsr >> 1 & 1);
|
||||
int new_dac = 0x1F & -(noise_lfsr >> 1 & 1);
|
||||
// Implemented using "Galios configuration"
|
||||
// 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));
|
||||
int delta = new_dac - dac;
|
||||
if ( delta )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -39,7 +39,7 @@ int const ram_addr = 0x2000;
|
|||
// status flags
|
||||
int const st_n = 0x80;
|
||||
int const st_v = 0x40;
|
||||
//unused: int const st_t = 0x20;
|
||||
int const st_t = 0x20;
|
||||
int const st_b = 0x10;
|
||||
int const st_d = 0x08;
|
||||
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 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 illegal_encountered = false;
|
||||
|
@ -100,14 +94,14 @@ bool Hes_Cpu::run( hes_time_t end_time )
|
|||
state_t s = this->state_;
|
||||
this->state = &s;
|
||||
// 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
|
||||
fuint16 pc = r.pc;
|
||||
fuint8 a = r.a;
|
||||
fuint8 x = r.x;
|
||||
fuint8 y = r.y;
|
||||
fuint16 sp;
|
||||
uint16_t pc = r.pc;
|
||||
uint8_t a = r.a;
|
||||
uint8_t x = r.x;
|
||||
uint8_t y = r.y;
|
||||
uint16_t sp;
|
||||
SET_SP( r.sp );
|
||||
|
||||
#define IS_NEG (nz & 0x8080)
|
||||
|
@ -126,11 +120,11 @@ bool Hes_Cpu::run( hes_time_t end_time )
|
|||
nz |= ~in & st_z;\
|
||||
} while ( 0 )
|
||||
|
||||
fuint8 status;
|
||||
fuint16 c; // carry set if (c & 0x100) != 0
|
||||
fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
||||
uint8_t status;
|
||||
uint16_t c; // carry set if (c & 0x100) != 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 );
|
||||
}
|
||||
|
||||
|
@ -159,7 +153,7 @@ loop:
|
|||
check( (unsigned) x < 0x100 );
|
||||
|
||||
uint8_t const* instr = s.code_map [pc >> page_shift];
|
||||
fuint8 opcode;
|
||||
uint8_t opcode;
|
||||
|
||||
// TODO: eliminate this special case
|
||||
#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
|
||||
}; // 0x00 was 8
|
||||
|
||||
fuint16 data;
|
||||
uint16_t data;
|
||||
data = clock_table [opcode];
|
||||
if ( (s_time += data) >= 0 )
|
||||
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
|
||||
#define BRANCH( cond )\
|
||||
{\
|
||||
fint16 offset = (BOOST::int8_t) data;\
|
||||
int16_t offset = (int8_t) data;\
|
||||
pc++;\
|
||||
if ( !(cond) ) goto branch_not_taken;\
|
||||
pc = BOOST::uint16_t (pc + offset);\
|
||||
pc = uint16_t (pc + offset);\
|
||||
goto loop;\
|
||||
}
|
||||
|
||||
|
@ -283,7 +277,7 @@ possibly_out_of_time:
|
|||
case 0xCF:
|
||||
case 0xDF:
|
||||
case 0xEF: {
|
||||
fuint16 t = 0x101 * READ_LOW( data );
|
||||
uint16_t t = 0x101 * READ_LOW( data );
|
||||
t ^= 0xFF;
|
||||
pc++;
|
||||
data = GET_MSB();
|
||||
|
@ -311,7 +305,7 @@ possibly_out_of_time:
|
|||
goto branch_taken;
|
||||
|
||||
case 0x20: { // JSR
|
||||
fuint16 temp = pc + 1;
|
||||
uint16_t temp = pc + 1;
|
||||
pc = GET_ADDR();
|
||||
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
||||
sp = (sp - 2) | 0x100;
|
||||
|
@ -332,7 +326,7 @@ possibly_out_of_time:
|
|||
|
||||
case 0xBD:{// LDA abs,X
|
||||
PAGE_CROSS_PENALTY( data + x );
|
||||
fuint16 addr = GET_ADDR() + x;
|
||||
uint16_t addr = GET_ADDR() + x;
|
||||
pc += 2;
|
||||
CPU_READ_FAST( this, addr, TIME, nz );
|
||||
a = nz;
|
||||
|
@ -340,7 +334,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x9D:{// STA abs,X
|
||||
fuint16 addr = GET_ADDR() + x;
|
||||
uint16_t addr = GET_ADDR() + x;
|
||||
pc += 2;
|
||||
CPU_WRITE_FAST( this, addr, a, TIME );
|
||||
goto loop;
|
||||
|
@ -354,7 +348,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xAE:{// LDX abs
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
CPU_READ_FAST( this, addr, TIME, nz );
|
||||
x = nz;
|
||||
|
@ -369,7 +363,7 @@ possibly_out_of_time:
|
|||
// Load/store
|
||||
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
case 0x91: // STA (ind),Y
|
||||
addr = 0x100 * READ_LOW( uint8_t (data + 1) );
|
||||
addr += READ_LOW( data ) + y;
|
||||
|
@ -395,7 +389,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
case 0xA1: // LDA (ind,X)
|
||||
data = uint8_t (data + x);
|
||||
case 0xB2: // LDA (ind)
|
||||
|
@ -425,7 +419,7 @@ possibly_out_of_time:
|
|||
|
||||
case 0xBE:{// LDX abs,y
|
||||
PAGE_CROSS_PENALTY( data + y );
|
||||
fuint16 addr = GET_ADDR() + y;
|
||||
uint16_t addr = GET_ADDR() + y;
|
||||
pc += 2;
|
||||
FLUSH_TIME();
|
||||
x = nz = READ( addr );
|
||||
|
@ -449,7 +443,7 @@ possibly_out_of_time:
|
|||
case 0x3C: // BIT abs,x
|
||||
data += x;
|
||||
case 0x2C:{// BIT abs
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
ADD_PAGE( addr );
|
||||
FLUSH_TIME();
|
||||
nz = READ( addr );
|
||||
|
@ -472,7 +466,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
|
||||
case 0xB3: // TST abs,x
|
||||
addr = GET_MSB() + x;
|
||||
|
@ -505,7 +499,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
case 0x0C: // TSB abs
|
||||
case 0x1C: // TRB abs
|
||||
addr = GET_ADDR();
|
||||
|
@ -610,7 +604,7 @@ possibly_out_of_time:
|
|||
data += x;
|
||||
PAGE_CROSS_PENALTY( data );
|
||||
case 0xAC:{// LDY abs
|
||||
fuint16 addr = data + 0x100 * GET_MSB();
|
||||
uint16_t addr = data + 0x100 * GET_MSB();
|
||||
pc += 2;
|
||||
FLUSH_TIME();
|
||||
y = nz = READ( addr );
|
||||
|
@ -619,7 +613,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
{
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
case 0x8C: // STY abs
|
||||
temp = y;
|
||||
goto store_abs;
|
||||
|
@ -627,7 +621,7 @@ possibly_out_of_time:
|
|||
case 0x8E: // STX abs
|
||||
temp = x;
|
||||
store_abs:
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
FLUSH_TIME();
|
||||
WRITE( addr, temp );
|
||||
|
@ -638,7 +632,7 @@ possibly_out_of_time:
|
|||
// Compare
|
||||
|
||||
case 0xEC:{// CPX abs
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc++;
|
||||
FLUSH_TIME();
|
||||
data = READ( addr );
|
||||
|
@ -657,7 +651,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xCC:{// CPY abs
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc++;
|
||||
FLUSH_TIME();
|
||||
data = READ( addr );
|
||||
|
@ -684,7 +678,7 @@ possibly_out_of_time:
|
|||
data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\
|
||||
goto ptr##op;\
|
||||
case op + 0x0C:{/* (ind),y */\
|
||||
fuint16 temp = READ_LOW( data ) + y;\
|
||||
uint16_t temp = READ_LOW( data ) + y;\
|
||||
PAGE_CROSS_PENALTY( temp );\
|
||||
data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\
|
||||
goto ptr##op;\
|
||||
|
@ -742,8 +736,8 @@ possibly_out_of_time:
|
|||
adc_imm: {
|
||||
if ( status & st_d )
|
||||
debug_printf( "Decimal mode not supported\n" );
|
||||
fint16 carry = c >> 8 & 1;
|
||||
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
|
||||
int16_t carry = c >> 8 & 1;
|
||||
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
|
||||
status &= ~st_v;
|
||||
status |= ov >> 2 & 0x40;
|
||||
c = nz = a + data + carry;
|
||||
|
@ -771,7 +765,7 @@ possibly_out_of_time:
|
|||
|
||||
case 0x2A: { // ROL A
|
||||
nz = a << 1;
|
||||
fint16 temp = c >> 8 & 1;
|
||||
int16_t temp = c >> 8 & 1;
|
||||
c = nz;
|
||||
nz |= temp;
|
||||
a = (uint8_t) nz;
|
||||
|
@ -877,7 +871,7 @@ possibly_out_of_time:
|
|||
case 0xD6: // DEC zp,x
|
||||
data = uint8_t (data + x);
|
||||
case 0xC6: // DEC zp
|
||||
nz = (unsigned) -1;
|
||||
nz = (uint16_t) -1;
|
||||
add_nz_zp:
|
||||
nz += READ_LOW( data );
|
||||
write_nz_zp:
|
||||
|
@ -902,7 +896,7 @@ possibly_out_of_time:
|
|||
case 0xCE: // DEC abs
|
||||
data = GET_ADDR();
|
||||
dec_ptr:
|
||||
nz = (unsigned) -1;
|
||||
nz = (uint16_t) -1;
|
||||
inc_common:
|
||||
FLUSH_TIME();
|
||||
nz += READ( data );
|
||||
|
@ -942,7 +936,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
#define SWAP_REGS( r1, r2 ) {\
|
||||
fuint8 t = r1;\
|
||||
uint8_t t = r1;\
|
||||
r1 = r2;\
|
||||
r2 = t;\
|
||||
goto loop;\
|
||||
|
@ -984,7 +978,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
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 - 0xFE) ) * 0x100;
|
||||
sp = (sp - 0xFD) | 0x100;
|
||||
|
@ -1018,8 +1012,8 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x28:{// PLP
|
||||
fuint8 temp = POP();
|
||||
fuint8 changed = status ^ temp;
|
||||
uint8_t temp = POP();
|
||||
uint8_t changed = status ^ temp;
|
||||
SET_STATUS( temp );
|
||||
if ( !(changed & st_i) )
|
||||
goto loop; // I flag didn't change
|
||||
|
@ -1030,7 +1024,7 @@ possibly_out_of_time:
|
|||
#undef POP
|
||||
|
||||
case 0x08: { // PHP
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
PUSH( temp | st_b );
|
||||
goto loop;
|
||||
|
@ -1039,7 +1033,7 @@ possibly_out_of_time:
|
|||
// Flags
|
||||
|
||||
case 0x38: // SEC
|
||||
c = (unsigned) ~0;
|
||||
c = (uint16_t) ~0;
|
||||
goto loop;
|
||||
|
||||
case 0x18: // CLC
|
||||
|
@ -1107,7 +1101,7 @@ possibly_out_of_time:
|
|||
// Special
|
||||
|
||||
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++;
|
||||
for ( int i = 0; i < 8; i++ )
|
||||
if ( bits & (1 << i) )
|
||||
|
@ -1131,7 +1125,7 @@ possibly_out_of_time:
|
|||
case 0x03: // ST0
|
||||
case 0x13: // ST1
|
||||
case 0x23:{// ST2
|
||||
fuint16 addr = opcode >> 4;
|
||||
uint16_t addr = opcode >> 4;
|
||||
if ( addr )
|
||||
addr++;
|
||||
pc++;
|
||||
|
@ -1153,7 +1147,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xF4: { // SET
|
||||
//fuint16 operand = GET_MSB();
|
||||
//uint16_t operand = GET_MSB();
|
||||
debug_printf( "SET not handled\n" );
|
||||
//switch ( data )
|
||||
//{
|
||||
|
@ -1165,10 +1159,10 @@ possibly_out_of_time:
|
|||
// Block transfer
|
||||
|
||||
{
|
||||
fuint16 in_alt;
|
||||
fint16 in_inc;
|
||||
fuint16 out_alt;
|
||||
fint16 out_inc;
|
||||
uint16_t in_alt;
|
||||
int16_t in_inc;
|
||||
uint16_t out_alt;
|
||||
int16_t out_inc;
|
||||
|
||||
case 0xE3: // TIA
|
||||
in_alt = 0;
|
||||
|
@ -1199,8 +1193,8 @@ possibly_out_of_time:
|
|||
in_alt = 0;
|
||||
out_alt = 0;
|
||||
bxfer:
|
||||
fuint16 in = GET_LE16( instr + 0 );
|
||||
fuint16 out = GET_LE16( instr + 2 );
|
||||
uint16_t in = GET_LE16( instr + 0 );
|
||||
uint16_t out = GET_LE16( instr + 2 );
|
||||
int count = GET_LE16( instr + 4 );
|
||||
if ( !count )
|
||||
count = 0x10000;
|
||||
|
@ -1212,7 +1206,7 @@ possibly_out_of_time:
|
|||
do
|
||||
{
|
||||
// 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 &= 0xFFFF;
|
||||
s.time += 6;
|
||||
|
@ -1232,7 +1226,6 @@ possibly_out_of_time:
|
|||
// Illegal
|
||||
|
||||
default:
|
||||
assert( (unsigned) opcode <= 0xFF );
|
||||
debug_printf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 );
|
||||
illegal_encountered = true;
|
||||
goto loop;
|
||||
|
@ -1253,7 +1246,7 @@ interrupt:
|
|||
pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ );
|
||||
|
||||
sp = (sp - 3) | 0x100;
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
if ( result_ == 6 )
|
||||
temp |= st_b;
|
||||
|
@ -1290,7 +1283,7 @@ out_of_time:
|
|||
r.y = y;
|
||||
|
||||
{
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
r.status = temp;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define HES_CPU_H
|
||||
|
||||
|
@ -12,8 +12,6 @@ enum { future_hes_time = INT_MAX / 2 + 1 };
|
|||
|
||||
class Hes_Cpu {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
void reset();
|
||||
|
||||
enum { page_size = 0x2000 };
|
||||
|
@ -27,7 +25,7 @@ public:
|
|||
|
||||
// not kept updated during a call to run()
|
||||
struct registers_t {
|
||||
BOOST::uint16_t pc;
|
||||
uint16_t pc;
|
||||
uint8_t a;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
|
@ -86,7 +84,7 @@ private:
|
|||
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
|
||||
#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"
|
||||
|
||||
|
@ -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 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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
// 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 )
|
||||
{
|
||||
set_end_time( end_time );
|
||||
|
@ -174,8 +169,6 @@ bool Kss_Cpu::run( cpu_time_t end_time )
|
|||
this->state = &s;
|
||||
bool warning = false;
|
||||
|
||||
typedef BOOST::int8_t int8_t;
|
||||
|
||||
union {
|
||||
regs_t rg;
|
||||
pairs_t rp;
|
||||
|
@ -185,10 +178,10 @@ bool Kss_Cpu::run( cpu_time_t end_time )
|
|||
rg = this->r.b;
|
||||
|
||||
cpu_time_t s_time = s.time;
|
||||
fuint16 pc = r.pc;
|
||||
fuint16 sp = r.sp;
|
||||
fuint16 ix = r.ix; // TODO: keep in memory for direct access?
|
||||
fuint16 iy = r.iy;
|
||||
uint16_t pc = r.pc;
|
||||
uint16_t sp = r.sp;
|
||||
uint16_t ix = r.ix; // TODO: keep in memory for direct access?
|
||||
uint16_t iy = r.iy;
|
||||
int flags = r.b.flags;
|
||||
|
||||
goto loop;
|
||||
|
@ -210,7 +203,7 @@ loop:
|
|||
uint8_t const* instr = s.read [pc >> page_shift];
|
||||
#define GET_ADDR() GET_LE16( instr )
|
||||
|
||||
fuint8 opcode;
|
||||
uint8_t opcode;
|
||||
|
||||
// TODO: eliminate this special case
|
||||
#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
|
||||
};
|
||||
|
||||
fuint16 data;
|
||||
uint16_t data;
|
||||
data = base_timing [opcode];
|
||||
if ( (s_time += data) >= 0 )
|
||||
goto possibly_out_of_time;
|
||||
|
@ -299,7 +292,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x3A:{// LD A,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
rg.a = READ( addr );
|
||||
goto loop;
|
||||
|
@ -315,7 +308,7 @@ possibly_out_of_time:
|
|||
// JR
|
||||
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||
#define JR( cond ) {\
|
||||
int offset = (BOOST::int8_t) data;\
|
||||
int offset = (int8_t) data;\
|
||||
pc++;\
|
||||
if ( !(cond) )\
|
||||
goto jr_not_taken;\
|
||||
|
@ -387,7 +380,7 @@ possibly_out_of_time:
|
|||
|
||||
case 0xCD:{// CALL addr
|
||||
call_taken:
|
||||
fuint16 addr = pc + 2;
|
||||
uint16_t addr = pc + 2;
|
||||
pc = GET_ADDR();
|
||||
sp = uint16_t (sp - 2);
|
||||
WRITE_WORD( sp, addr );
|
||||
|
@ -395,7 +388,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0xFF: // RST
|
||||
if ( pc > idle_addr )
|
||||
if ( pc >= idle_addr )
|
||||
goto hit_idle_addr;
|
||||
CASE7( C7, CF, D7, DF, E7, EF, F7 ):
|
||||
data = pc;
|
||||
|
@ -503,7 +496,7 @@ possibly_out_of_time:
|
|||
add_hl_data: {
|
||||
blargg_ulong sum = rp.hl + data;
|
||||
data ^= rp.hl;
|
||||
rp.hl = (uint16_t)sum;
|
||||
rp.hl = sum;
|
||||
flags = (flags & (S80 | Z40 | V04)) |
|
||||
(sum >> 16) |
|
||||
(sum >> 8 & (F20 | F08)) |
|
||||
|
@ -693,21 +686,21 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x2A:{// LD HL,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
rp.hl = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x32:{// LD (addr),A
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE( addr, rg.a );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x22:{// LD (addr),HL
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, rp.hl );
|
||||
goto loop;
|
||||
|
@ -730,7 +723,7 @@ possibly_out_of_time:
|
|||
// Rotate
|
||||
|
||||
case 0x07:{// RLCA
|
||||
fuint16 temp = rg.a;
|
||||
uint16_t temp = rg.a;
|
||||
temp = (temp << 1) | (temp >> 7);
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08 | C01));
|
||||
|
@ -739,7 +732,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x0F:{// RRCA
|
||||
fuint16 temp = rg.a;
|
||||
uint16_t temp = rg.a;
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & C01);
|
||||
temp = (temp << 7) | (temp >> 1);
|
||||
|
@ -753,12 +746,12 @@ possibly_out_of_time:
|
|||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(temp >> 8);
|
||||
rg.a = (uint8_t)temp;
|
||||
rg.a = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x1F:{// RRA
|
||||
fuint16 temp = (flags << 7) | (rg.a >> 1);
|
||||
uint16_t temp = (flags << 7) | (rg.a >> 1);
|
||||
flags = (flags & (S80 | Z40 | P04)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(rg.a & C01);
|
||||
|
@ -768,7 +761,7 @@ possibly_out_of_time:
|
|||
|
||||
// Misc
|
||||
case 0x2F:{// CPL
|
||||
fuint16 temp = ~rg.a;
|
||||
uint16_t temp = ~rg.a;
|
||||
flags = (flags & (S80 | Z40 | P04 | C01)) |
|
||||
(temp & (F20 | F08)) |
|
||||
(H10 | N02);
|
||||
|
@ -794,21 +787,21 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xE3:{// EX (SP),HL
|
||||
fuint16 temp = READ_WORD( sp );
|
||||
uint16_t temp = READ_WORD( sp );
|
||||
WRITE_WORD( sp, rp.hl );
|
||||
rp.hl = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0xEB:{// EX DE,HL
|
||||
fuint16 temp = rp.hl;
|
||||
uint16_t temp = rp.hl;
|
||||
rp.hl = rp.de;
|
||||
rp.de = temp;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0xD9:{// EXX DE,HL
|
||||
fuint16 temp = r.alt.w.bc;
|
||||
uint16_t temp = r.alt.w.bc;
|
||||
r.alt.w.bc = rp.bc;
|
||||
rp.bc = temp;
|
||||
|
||||
|
@ -849,7 +842,7 @@ possibly_out_of_time:
|
|||
// Rotate left
|
||||
|
||||
#define RLC( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
result = uint8_t (result << 1) | (result >> 7);\
|
||||
flags = SZ28P( result ) | (result & C01);\
|
||||
write;\
|
||||
|
@ -868,7 +861,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define RL( read, write ) {\
|
||||
fuint16 result = (read << 1) | (flags & C01);\
|
||||
uint16_t result = (read << 1) | (flags & C01);\
|
||||
flags = SZ28PC( result );\
|
||||
write;\
|
||||
goto loop;\
|
||||
|
@ -886,7 +879,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SLA( read, add, write ) {\
|
||||
fuint16 result = (read << 1) | add;\
|
||||
uint16_t result = (read << 1) | add;\
|
||||
flags = SZ28PC( result );\
|
||||
write;\
|
||||
goto loop;\
|
||||
|
@ -917,7 +910,7 @@ possibly_out_of_time:
|
|||
// Rotate right
|
||||
|
||||
#define RRC( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result = uint8_t (result << 7) | (result >> 1);\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -937,8 +930,8 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define RR( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
fuint8 temp = result & C01;\
|
||||
uint8_t result = read;\
|
||||
uint8_t temp = result & C01;\
|
||||
result = uint8_t (flags << 7) | (result >> 1);\
|
||||
flags = SZ28P( result ) | temp;\
|
||||
write;\
|
||||
|
@ -957,7 +950,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SRA( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result = (result & 0x80) | (result >> 1);\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -977,7 +970,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
#define SRL( read, write ) {\
|
||||
fuint8 result = read;\
|
||||
uint8_t result = read;\
|
||||
flags = result & C01;\
|
||||
result >>= 1;\
|
||||
flags |= SZ28P( result );\
|
||||
|
@ -1085,7 +1078,7 @@ possibly_out_of_time:
|
|||
blargg_ulong sum = temp + (flags & C01);
|
||||
flags = ~data >> 2 & N02;
|
||||
if ( flags )
|
||||
sum = (blargg_ulong)-(blargg_long)sum;
|
||||
sum = -sum;
|
||||
sum += rp.hl;
|
||||
temp ^= rp.hl;
|
||||
temp ^= sum;
|
||||
|
@ -1093,7 +1086,7 @@ possibly_out_of_time:
|
|||
(temp >> 8 & H10) |
|
||||
(sum >> 8 & (S80 | F20 | F08)) |
|
||||
((temp - -0x8000) >> 14 & V04);
|
||||
rp.hl = (uint16_t)sum;
|
||||
rp.hl = sum;
|
||||
if ( (uint16_t) sum )
|
||||
goto loop;
|
||||
flags |= Z40;
|
||||
|
@ -1121,7 +1114,7 @@ possibly_out_of_time:
|
|||
case 0x43: // LD (ADDR),BC
|
||||
case 0x53: // LD (ADDR),DE
|
||||
temp = R16( data, 4, 0x43 );
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, temp );
|
||||
goto loop;
|
||||
|
@ -1129,21 +1122,21 @@ possibly_out_of_time:
|
|||
|
||||
case 0x4B: // LD BC,(ADDR)
|
||||
case 0x5B:{// LD DE,(ADDR)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
R16( data, 4, 0x4B ) = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x7B:{// LD SP,(ADDR)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
sp = READ_WORD( addr );
|
||||
goto loop;
|
||||
}
|
||||
|
||||
case 0x67:{// RRD
|
||||
fuint8 temp = READ( rp.hl );
|
||||
uint8_t temp = READ( rp.hl );
|
||||
WRITE( rp.hl, (rg.a << 4) | (temp >> 4) );
|
||||
temp = (rg.a & 0xF0) | (temp & 0x0F);
|
||||
flags = (flags & C01) | SZ28P( temp );
|
||||
|
@ -1152,7 +1145,7 @@ possibly_out_of_time:
|
|||
}
|
||||
|
||||
case 0x6F:{// RLD
|
||||
fuint8 temp = READ( rp.hl );
|
||||
uint8_t temp = READ( rp.hl );
|
||||
WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) );
|
||||
temp = (rg.a & 0xF0) | (temp >> 4);
|
||||
flags = (flags & C01) | SZ28P( temp );
|
||||
|
@ -1176,7 +1169,7 @@ possibly_out_of_time:
|
|||
case 0xA1: // CPI
|
||||
case 0xB1: // CPIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1209,7 +1202,7 @@ possibly_out_of_time:
|
|||
case 0xA0: // LDI
|
||||
case 0xB0: // LDIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1241,7 +1234,7 @@ possibly_out_of_time:
|
|||
case 0xA3: // OUTI
|
||||
case 0xB3: // OTIR
|
||||
inc = +1;
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
int temp = READ( addr );
|
||||
|
||||
|
@ -1267,7 +1260,7 @@ possibly_out_of_time:
|
|||
case 0xB2: // INIR
|
||||
inc = +1;
|
||||
|
||||
fuint16 addr = rp.hl;
|
||||
uint16_t addr = rp.hl;
|
||||
rp.hl = addr + inc;
|
||||
|
||||
int temp = IN( rp.bc );
|
||||
|
@ -1332,7 +1325,7 @@ possibly_out_of_time:
|
|||
|
||||
//////////////////////////////////////// DD/FD prefix
|
||||
{
|
||||
fuint16 ixy;
|
||||
uint16_t ixy;
|
||||
case 0xDD:
|
||||
ixy = ix;
|
||||
goto ix_prefix;
|
||||
|
@ -1528,7 +1521,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0x22:{// LD (ADDR),IXY
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
pc += 2;
|
||||
WRITE_WORD( addr, ixy );
|
||||
goto loop;
|
||||
|
@ -1540,7 +1533,7 @@ possibly_out_of_time:
|
|||
goto set_ixy;
|
||||
|
||||
case 0x2A:{// LD IXY,(addr)
|
||||
fuint16 addr = GET_ADDR();
|
||||
uint16_t addr = GET_ADDR();
|
||||
ixy = READ_WORD( addr );
|
||||
pc += 2;
|
||||
goto set_ixy;
|
||||
|
@ -1564,7 +1557,7 @@ possibly_out_of_time:
|
|||
case 0x3E: goto srl_data_addr; // SRL (IXY)
|
||||
|
||||
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);
|
||||
flags = (flags & C01) | H10 |
|
||||
(masked & S80) |
|
||||
|
@ -1666,7 +1659,7 @@ possibly_out_of_time:
|
|||
goto loop;
|
||||
|
||||
case 0xE3:{// EX (SP),IXY
|
||||
fuint16 temp = READ_WORD( sp );
|
||||
uint16_t temp = READ_WORD( sp );
|
||||
WRITE_WORD( sp, ixy );
|
||||
ixy = temp;
|
||||
goto set_ixy;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Z80 CPU emulator
|
||||
|
||||
// Game_Music_Emu 0.6.0
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
#ifndef 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 {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Clear registers and map all pages to unmapped
|
||||
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 adjust_time( int delta ) { state->time += delta; }
|
||||
|
||||
typedef BOOST::uint16_t uint16_t;
|
||||
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
struct regs_t { uint8_t b, c, d, e, h, l, flags, a; };
|
||||
#else
|
||||
|
@ -104,12 +100,12 @@ public:
|
|||
#define KSS_CPU_PAGE_OFFSET( addr ) ((addr) & (page_size - 1))
|
||||
#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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -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 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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -43,7 +43,7 @@ void Scc_Apu::run_until( blip_time_t end_time )
|
|||
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 )
|
||||
wave -= wave_size; // last two oscs share wave
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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 "Music_Emu.h"
|
||||
|
@ -407,7 +407,7 @@ blargg_err_t M3u_Playlist::parse()
|
|||
blargg_err_t M3u_Playlist::load( Data_Reader& in )
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define M3U_PLAYLIST_H
|
||||
|
||||
|
@ -43,7 +43,7 @@ public:
|
|||
int repeat; // count
|
||||
};
|
||||
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();
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ void Stereo_Buffer::clock_rate( long rate )
|
|||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ void Stereo_Buffer::clear()
|
|||
void Stereo_Buffer::end_frame( blip_time_t clock_count )
|
||||
{
|
||||
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;
|
||||
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 );
|
||||
blargg_long l = c + BLIP_READER_READ( left );
|
||||
blargg_long r = c + BLIP_READER_READ( right );
|
||||
if ( (BOOST::int16_t) l != l )
|
||||
if ( (int16_t) l != l )
|
||||
l = 0x7FFF - (l >> 24);
|
||||
|
||||
BLIP_READER_NEXT( center, bass );
|
||||
if ( (BOOST::int16_t) r != r )
|
||||
if ( (int16_t) r != r )
|
||||
r = 0x7FFF - (r >> 24);
|
||||
|
||||
BLIP_READER_NEXT( left, bass );
|
||||
BLIP_READER_NEXT( right, bass );
|
||||
|
||||
out [0] = (blip_sample_t)l;
|
||||
out [1] = (blip_sample_t)r;
|
||||
out [0] = l;
|
||||
out [1] = r;
|
||||
out += 2;
|
||||
}
|
||||
|
||||
|
@ -191,18 +191,18 @@ void Stereo_Buffer::mix_stereo_no_center( blip_sample_t* out_, blargg_long count
|
|||
for ( ; count; --count )
|
||||
{
|
||||
blargg_long l = BLIP_READER_READ( left );
|
||||
if ( (BOOST::int16_t) l != l )
|
||||
if ( (int16_t) l != l )
|
||||
l = 0x7FFF - (l >> 24);
|
||||
|
||||
blargg_long r = BLIP_READER_READ( right );
|
||||
if ( (BOOST::int16_t) r != r )
|
||||
if ( (int16_t) r != r )
|
||||
r = 0x7FFF - (r >> 24);
|
||||
|
||||
BLIP_READER_NEXT( left, bass );
|
||||
BLIP_READER_NEXT( right, bass );
|
||||
|
||||
out [0] = (blip_sample_t)l;
|
||||
out [1] = (blip_sample_t)r;
|
||||
out [0] = l;
|
||||
out [1] = r;
|
||||
out += 2;
|
||||
}
|
||||
|
||||
|
@ -219,12 +219,12 @@ void Stereo_Buffer::mix_mono( blip_sample_t* out_, blargg_long count )
|
|||
for ( ; count; --count )
|
||||
{
|
||||
blargg_long s = BLIP_READER_READ( center );
|
||||
if ( (BOOST::int16_t) s != s )
|
||||
if ( (int16_t) s != s )
|
||||
s = 0x7FFF - (s >> 24);
|
||||
|
||||
BLIP_READER_NEXT( center, bass );
|
||||
out [0] = (blip_sample_t)s;
|
||||
out [1] = (blip_sample_t)s;
|
||||
out [0] = s;
|
||||
out [1] = s;
|
||||
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"
|
||||
|
||||
|
@ -18,7 +18,6 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
|
||||
#include "blargg_source.h"
|
||||
|
||||
int const stereo = 2; // number of channels for stereo
|
||||
int const silence_max = 6; // seconds
|
||||
int const silence_threshold = 0x10;
|
||||
long const fade_block_size = 512;
|
||||
|
@ -52,7 +51,7 @@ void Music_Emu::unload()
|
|||
Music_Emu::Music_Emu()
|
||||
{
|
||||
effects_buffer = 0;
|
||||
|
||||
multi_channel_ = false;
|
||||
sample_rate_ = 0;
|
||||
mute_mask_ = 0;
|
||||
tempo_ = 1.0;
|
||||
|
@ -96,6 +95,25 @@ void Music_Emu::set_equalizer( equalizer_t const& 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 )
|
||||
{
|
||||
require( (unsigned) index < (unsigned) voice_count() );
|
||||
|
@ -145,7 +163,7 @@ blargg_err_t Music_Emu::start_track( int track )
|
|||
if ( !ignore_silence_ )
|
||||
{
|
||||
// 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();
|
||||
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;
|
||||
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
|
||||
|
@ -185,7 +203,7 @@ long Music_Emu::tell_samples() 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;
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -345,7 +363,7 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
|
|||
else
|
||||
{
|
||||
require( current_track() >= 0 );
|
||||
require( out_count % stereo == 0 );
|
||||
require( out_count % out_channels() == 0 );
|
||||
|
||||
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
|
||||
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 with silence
|
||||
|
@ -365,7 +383,7 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
|
|||
memset( out, 0, pos * sizeof *out );
|
||||
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;
|
||||
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 );
|
||||
}
|
||||
out_time += out_count;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define MUSIC_EMU_H
|
||||
|
||||
|
@ -13,6 +13,11 @@ public:
|
|||
|
||||
// Set output sample rate. Must be called only once before loading file.
|
||||
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.
|
||||
blargg_err_t start_track( int );
|
||||
|
@ -35,6 +40,8 @@ public:
|
|||
|
||||
// Names of voices
|
||||
const char** voice_names() const;
|
||||
|
||||
bool multi_channel() const;
|
||||
|
||||
// Track status/control
|
||||
|
||||
|
@ -127,6 +134,7 @@ protected:
|
|||
double gain() const { return gain_; }
|
||||
double tempo() const { return tempo_; }
|
||||
void remute_voices();
|
||||
blargg_err_t set_multi_channel_( bool is_enabled );
|
||||
|
||||
virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
|
||||
virtual void set_equalizer_( equalizer_t const& ) { }
|
||||
|
@ -149,7 +157,11 @@ private:
|
|||
int mute_mask_;
|
||||
double tempo_;
|
||||
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_;
|
||||
blargg_long msec_to_samples( blargg_long msec ) const;
|
||||
|
||||
|
@ -179,7 +191,7 @@ private:
|
|||
void emu_play( long count, sample_t* out );
|
||||
|
||||
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 );
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -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 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 )
|
||||
{
|
||||
set_end_time( end_time );
|
||||
state_t s = this->state_;
|
||||
this->state = &s;
|
||||
// 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
|
||||
fuint16 pc = r.pc;
|
||||
fuint8 a = r.a;
|
||||
fuint8 x = r.x;
|
||||
fuint8 y = r.y;
|
||||
fuint16 sp;
|
||||
uint16_t pc = r.pc;
|
||||
uint8_t a = r.a;
|
||||
uint8_t x = r.x;
|
||||
uint8_t y = r.y;
|
||||
uint16_t sp;
|
||||
SET_SP( r.sp );
|
||||
|
||||
// status flags
|
||||
|
@ -152,11 +147,11 @@ bool Nes_Cpu::run( nes_time_t end_time )
|
|||
nz |= ~in & st_z;\
|
||||
} while ( 0 )
|
||||
|
||||
fuint8 status;
|
||||
fuint16 c; // carry set if (c & 0x100) != 0
|
||||
fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
||||
uint8_t status;
|
||||
uint16_t c; // carry set if (c & 0x100) != 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 );
|
||||
}
|
||||
|
||||
|
@ -173,7 +168,7 @@ loop:
|
|||
check( -32768 <= s_time && s_time < 32767 );
|
||||
|
||||
uint8_t const* instr = s.code_map [pc >> page_bits];
|
||||
fuint8 opcode;
|
||||
uint8_t opcode;
|
||||
|
||||
// TODO: eliminate this special case
|
||||
#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
|
||||
}; // 0x00 was 7 and 0xF2 was 2
|
||||
|
||||
fuint16 data;
|
||||
uint16_t data;
|
||||
|
||||
#if !BLARGG_CPU_X86
|
||||
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 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) );\
|
||||
cross( temp );\
|
||||
}
|
||||
|
||||
#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) );\
|
||||
}
|
||||
|
||||
|
@ -288,10 +283,10 @@ imm##op:
|
|||
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||
#define BRANCH( cond )\
|
||||
{\
|
||||
fint16 offset = (BOOST::int8_t) data;\
|
||||
fuint16 extra_clock = (++pc & 0xFF) + offset;\
|
||||
int16_t offset = (int8_t) data;\
|
||||
uint16_t extra_clock = (++pc & 0xFF) + offset;\
|
||||
if ( !(cond) ) goto dec_clock_loop;\
|
||||
pc = BOOST::uint16_t (pc + offset);\
|
||||
pc = uint16_t (pc + offset);\
|
||||
s_time += extra_clock >> 8 & 1;\
|
||||
goto loop;\
|
||||
}
|
||||
|
@ -312,7 +307,7 @@ imm##op:
|
|||
BRANCH( (uint8_t) nz );
|
||||
|
||||
case 0x20: { // JSR
|
||||
fuint16 temp = pc + 1;
|
||||
uint16_t temp = pc + 1;
|
||||
pc = GET_ADDR();
|
||||
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
||||
sp = (sp - 2) | 0x100;
|
||||
|
@ -378,7 +373,7 @@ imm##op:
|
|||
goto loop;
|
||||
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
|
||||
case 0x99: // STA abs,Y
|
||||
addr = y + GET_ADDR();
|
||||
|
@ -434,7 +429,7 @@ imm##op:
|
|||
|
||||
// common read instructions
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
|
||||
case 0xA1: // LDA (ind,X)
|
||||
IND_X( addr )
|
||||
|
@ -550,7 +545,7 @@ imm##op:
|
|||
}
|
||||
|
||||
{
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
case 0x8C: // STY abs
|
||||
temp = y;
|
||||
goto store_abs;
|
||||
|
@ -659,8 +654,8 @@ imm##op:
|
|||
|
||||
ARITH_ADDR_MODES( 0x65 ) // ADC
|
||||
adc_imm: {
|
||||
fint16 carry = c >> 8 & 1;
|
||||
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
|
||||
int16_t carry = c >> 8 & 1;
|
||||
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
|
||||
status &= ~st_v;
|
||||
status |= ov >> 2 & 0x40;
|
||||
c = nz = a + data + carry;
|
||||
|
@ -688,7 +683,7 @@ imm##op:
|
|||
|
||||
case 0x2A: { // ROL A
|
||||
nz = a << 1;
|
||||
fint16 temp = c >> 8 & 1;
|
||||
int16_t temp = c >> 8 & 1;
|
||||
c = nz;
|
||||
nz |= temp;
|
||||
a = (uint8_t) nz;
|
||||
|
@ -780,7 +775,7 @@ imm##op:
|
|||
case 0xD6: // DEC zp,x
|
||||
data = uint8_t (data + x);
|
||||
case 0xC6: // DEC zp
|
||||
nz = (unsigned) -1;
|
||||
nz = (uint16_t) -1;
|
||||
add_nz_zp:
|
||||
nz += READ_LOW( data );
|
||||
write_nz_zp:
|
||||
|
@ -805,7 +800,7 @@ imm##op:
|
|||
case 0xCE: // DEC abs
|
||||
data = GET_ADDR();
|
||||
dec_ptr:
|
||||
nz = (unsigned) -1;
|
||||
nz = (uint16_t) -1;
|
||||
inc_common:
|
||||
FLUSH_TIME();
|
||||
nz += READ( data );
|
||||
|
@ -846,7 +841,7 @@ imm##op:
|
|||
goto loop;
|
||||
|
||||
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 - 0xFE) ) * 0x100;
|
||||
sp = (sp - 0xFD) | 0x100;
|
||||
|
@ -863,9 +858,9 @@ imm##op:
|
|||
}
|
||||
|
||||
case 0x28:{// PLP
|
||||
fuint8 temp = READ_LOW( sp );
|
||||
uint8_t temp = READ_LOW( sp );
|
||||
sp = (sp - 0xFF) | 0x100;
|
||||
fuint8 changed = status ^ temp;
|
||||
uint8_t changed = status ^ temp;
|
||||
SET_STATUS( temp );
|
||||
if ( !(changed & st_i) )
|
||||
goto loop; // I flag didn't change
|
||||
|
@ -875,7 +870,7 @@ imm##op:
|
|||
}
|
||||
|
||||
case 0x08: { // PHP
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
PUSH( temp | (st_b | st_r) );
|
||||
goto loop;
|
||||
|
@ -897,7 +892,7 @@ imm##op:
|
|||
// Flags
|
||||
|
||||
case 0x38: // SEC
|
||||
c = (unsigned) ~0;
|
||||
c = (uint16_t) ~0;
|
||||
goto loop;
|
||||
|
||||
case 0x18: // CLC
|
||||
|
@ -983,12 +978,6 @@ imm##op:
|
|||
|
||||
case bad_opcode: // HLT
|
||||
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 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2:
|
||||
goto stop;
|
||||
|
@ -1003,8 +992,8 @@ imm##op:
|
|||
static unsigned char const illop_lens [8] = {
|
||||
0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0
|
||||
};
|
||||
fuint8 opcode = instr [-1];
|
||||
fint16 len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
|
||||
uint8_t opcode = instr [-1];
|
||||
int16_t len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3;
|
||||
if ( opcode == 0x9C )
|
||||
len = 2;
|
||||
pc += len;
|
||||
|
@ -1035,7 +1024,7 @@ interrupt:
|
|||
pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ );
|
||||
|
||||
sp = (sp - 3) | 0x100;
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
temp |= st_r;
|
||||
if ( result_ )
|
||||
|
@ -1071,7 +1060,7 @@ stop:
|
|||
r.y = y;
|
||||
|
||||
{
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
r.status = temp;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// NES 6502 CPU emulator
|
||||
|
||||
// Game_Music_Emu 0.6.0
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
#ifndef NES_CPU_H
|
||||
#define NES_CPU_H
|
||||
|
||||
|
@ -12,8 +12,6 @@ enum { future_nes_time = INT_MAX / 2 + 1 };
|
|||
|
||||
class Nes_Cpu {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Clear registers, map low memory and its three mirrors to address 0,
|
||||
// and mirror unmapped_page in remaining memory
|
||||
void reset( void const* unmapped_page = 0 );
|
||||
|
@ -32,12 +30,12 @@ public:
|
|||
|
||||
// NES 6502 registers. Not kept updated during a call to run().
|
||||
struct registers_t {
|
||||
BOOST::uint16_t pc;
|
||||
BOOST::uint8_t a;
|
||||
BOOST::uint8_t x;
|
||||
BOOST::uint8_t y;
|
||||
BOOST::uint8_t status;
|
||||
BOOST::uint8_t sp;
|
||||
uint16_t pc;
|
||||
uint8_t a;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t status;
|
||||
uint8_t sp;
|
||||
};
|
||||
registers_t r;
|
||||
|
||||
|
@ -84,7 +82,7 @@ private:
|
|||
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
|
||||
#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"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define NES_FME7_APU_H
|
||||
|
||||
|
@ -10,10 +10,10 @@
|
|||
struct fme7_apu_state_t
|
||||
{
|
||||
enum { reg_count = 14 };
|
||||
BOOST::uint8_t regs [reg_count];
|
||||
BOOST::uint8_t phases [3]; // 0 or 1
|
||||
BOOST::uint8_t latch;
|
||||
BOOST::uint16_t delays [3]; // a, b, c
|
||||
uint8_t regs [reg_count];
|
||||
uint8_t phases [3]; // 0 or 1
|
||||
uint8_t latch;
|
||||
uint16_t delays [3]; // a, b, c
|
||||
};
|
||||
|
||||
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;
|
||||
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) )
|
||||
continue;
|
||||
|
||||
|
|
|
@ -54,24 +54,24 @@ private:
|
|||
int addr_reg;
|
||||
|
||||
enum { reg_count = 0x80 };
|
||||
BOOST::uint8_t reg [reg_count];
|
||||
uint8_t reg [reg_count];
|
||||
Blip_Synth<blip_good_quality,15> synth;
|
||||
|
||||
BOOST::uint8_t& access();
|
||||
uint8_t& access();
|
||||
void run_until( blip_time_t );
|
||||
};
|
||||
/*
|
||||
struct namco_state_t
|
||||
{
|
||||
BOOST::uint8_t regs [0x80];
|
||||
BOOST::uint8_t addr;
|
||||
BOOST::uint8_t unused;
|
||||
BOOST::uint8_t positions [8];
|
||||
BOOST::uint32_t delays [8];
|
||||
uint8_t regs [0x80];
|
||||
uint8_t addr;
|
||||
uint8_t unused;
|
||||
uint8_t positions [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;
|
||||
if ( addr_reg & 0x80 )
|
||||
|
|
|
@ -40,7 +40,7 @@ private:
|
|||
|
||||
struct Vrc6_Osc
|
||||
{
|
||||
BOOST::uint8_t regs [3];
|
||||
uint8_t regs [3];
|
||||
Blip_Buffer* output;
|
||||
int delay;
|
||||
int last_amp;
|
||||
|
@ -66,11 +66,11 @@ private:
|
|||
|
||||
struct vrc6_apu_state_t
|
||||
{
|
||||
BOOST::uint8_t regs [3] [3];
|
||||
BOOST::uint8_t saw_amp;
|
||||
BOOST::uint16_t delays [3];
|
||||
BOOST::uint8_t phases [3];
|
||||
BOOST::uint8_t unused;
|
||||
uint8_t regs [3] [3];
|
||||
uint8_t saw_amp;
|
||||
uint16_t delays [3];
|
||||
uint8_t phases [3];
|
||||
uint8_t unused;
|
||||
};
|
||||
|
||||
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"
|
||||
|
||||
|
@ -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 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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define NSF_EMU_H
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
|
||||
#include "Nsfe_Emu.h"
|
||||
|
||||
|
@ -37,7 +35,7 @@ inline void Nsfe_Info::unload()
|
|||
void Nsfe_Info::disable_playlist( bool b )
|
||||
{
|
||||
playlist_disabled = b;
|
||||
info.track_count = (byte)playlist.size();
|
||||
info.track_count = playlist.size();
|
||||
if ( !info.track_count || playlist_disabled )
|
||||
info.track_count = actual_track_count_;
|
||||
}
|
||||
|
@ -136,6 +134,9 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
|
|||
RETURN_ERR( in.read( block_header, sizeof block_header ) );
|
||||
blargg_long size = get_le32( block_header [0] );
|
||||
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) );
|
||||
|
||||
|
@ -173,7 +174,7 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
|
|||
blargg_vector<char> chars;
|
||||
blargg_vector<const char*> strs;
|
||||
RETURN_ERR( read_strs( in, size, chars, strs ) );
|
||||
int n = (int)strs.size();
|
||||
int n = strs.size();
|
||||
|
||||
if ( n > 3 )
|
||||
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'):
|
||||
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;
|
||||
|
||||
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 );
|
||||
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 )
|
||||
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 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 )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -30,7 +30,7 @@ static void gen_poly( blargg_ulong mask, int count, byte* out )
|
|||
{
|
||||
// implemented using "Galios configuration"
|
||||
bits |= (n & 1) << b;
|
||||
n = (n >> 1) ^ (mask & (blargg_ulong)-(blargg_long)(n & 1));
|
||||
n = (n >> 1) ^ (mask & -(n & 1));
|
||||
}
|
||||
while ( b++ < 7 );
|
||||
*out++ = bits;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -68,27 +68,21 @@ void Sap_Cpu::reset( void* new_mem )
|
|||
#define GET_SP() ((sp - 1) & 0xFF)
|
||||
#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 illegal_encountered = false;
|
||||
set_end_time( end_time );
|
||||
state_t s = this->state_;
|
||||
this->state = &s;
|
||||
fint32 s_time = s.time;
|
||||
int32_t s_time = s.time;
|
||||
uint8_t* const mem = this->mem; // cache
|
||||
|
||||
// registers
|
||||
fuint16 pc = r.pc;
|
||||
fuint8 a = r.a;
|
||||
fuint8 x = r.x;
|
||||
fuint8 y = r.y;
|
||||
fuint16 sp;
|
||||
uint16_t pc = r.pc;
|
||||
uint8_t a = r.a;
|
||||
uint8_t x = r.x;
|
||||
uint8_t y = r.y;
|
||||
uint16_t sp;
|
||||
SET_SP( r.sp );
|
||||
|
||||
// status flags
|
||||
|
@ -108,11 +102,11 @@ bool Sap_Cpu::run( sap_time_t end_time )
|
|||
nz |= ~in & st_z;\
|
||||
} while ( 0 )
|
||||
|
||||
fuint8 status;
|
||||
fuint16 c; // carry set if (c & 0x100) != 0
|
||||
fuint16 nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0
|
||||
uint8_t status;
|
||||
uint16_t c; // carry set if (c & 0x100) != 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 );
|
||||
}
|
||||
|
||||
|
@ -135,7 +129,7 @@ loop:
|
|||
check( (unsigned) x < 0x100 );
|
||||
check( (unsigned) y < 0x100 );
|
||||
|
||||
fuint8 opcode = mem [pc];
|
||||
uint8_t opcode = mem [pc];
|
||||
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
|
||||
}; // 0x00 was 7
|
||||
|
||||
fuint16 data;
|
||||
uint16_t data;
|
||||
data = clock_table [opcode];
|
||||
if ( (s_time += data) >= 0 )
|
||||
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 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) );\
|
||||
cross( temp );\
|
||||
}
|
||||
|
||||
#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) );\
|
||||
}
|
||||
|
||||
|
@ -232,8 +226,8 @@ imm##op:
|
|||
// TODO: more efficient way to handle negative branch that wraps PC around
|
||||
#define BRANCH( cond )\
|
||||
{\
|
||||
fint16 offset = (BOOST::int8_t) data;\
|
||||
fuint16 extra_clock = (++pc & 0xFF) + offset;\
|
||||
int16_t offset = (int8_t) data;\
|
||||
uint16_t extra_clock = (++pc & 0xFF) + offset;\
|
||||
if ( !(cond) ) goto dec_clock_loop;\
|
||||
pc += offset;\
|
||||
s_time += extra_clock >> 8 & 1;\
|
||||
|
@ -256,7 +250,7 @@ imm##op:
|
|||
BRANCH( (uint8_t) nz );
|
||||
|
||||
case 0x20: { // JSR
|
||||
fuint16 temp = pc + 1;
|
||||
uint16_t temp = pc + 1;
|
||||
pc = GET_ADDR();
|
||||
WRITE_LOW( 0x100 | (sp - 1), temp >> 8 );
|
||||
sp = (sp - 2) | 0x100;
|
||||
|
@ -322,7 +316,7 @@ imm##op:
|
|||
goto loop;
|
||||
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
|
||||
case 0x99: // STA abs,Y
|
||||
addr = y + GET_ADDR();
|
||||
|
@ -378,7 +372,7 @@ imm##op:
|
|||
|
||||
// common read instructions
|
||||
{
|
||||
fuint16 addr;
|
||||
uint16_t addr;
|
||||
|
||||
case 0xA1: // LDA (ind,X)
|
||||
IND_X( addr )
|
||||
|
@ -494,7 +488,7 @@ imm##op:
|
|||
}
|
||||
|
||||
{
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
case 0x8C: // STY abs
|
||||
temp = y;
|
||||
goto store_abs;
|
||||
|
@ -604,8 +598,8 @@ imm##op:
|
|||
ARITH_ADDR_MODES( 0x65 ) // ADC
|
||||
adc_imm: {
|
||||
check( !(status & st_d) );
|
||||
fint16 carry = c >> 8 & 1;
|
||||
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
|
||||
int16_t carry = c >> 8 & 1;
|
||||
int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend
|
||||
status &= ~st_v;
|
||||
status |= ov >> 2 & 0x40;
|
||||
c = nz = a + data + carry;
|
||||
|
@ -633,7 +627,7 @@ imm##op:
|
|||
|
||||
case 0x2A: { // ROL A
|
||||
nz = a << 1;
|
||||
fint16 temp = c >> 8 & 1;
|
||||
int16_t temp = c >> 8 & 1;
|
||||
c = nz;
|
||||
nz |= temp;
|
||||
a = (uint8_t) nz;
|
||||
|
@ -725,7 +719,7 @@ imm##op:
|
|||
case 0xD6: // DEC zp,x
|
||||
data = uint8_t (data + x);
|
||||
case 0xC6: // DEC zp
|
||||
nz = (unsigned) -1;
|
||||
nz = (uint16_t) -1;
|
||||
add_nz_zp:
|
||||
nz += READ_LOW( data );
|
||||
write_nz_zp:
|
||||
|
@ -750,7 +744,7 @@ imm##op:
|
|||
case 0xCE: // DEC abs
|
||||
data = GET_ADDR();
|
||||
dec_ptr:
|
||||
nz = (unsigned) -1;
|
||||
nz = (uint16_t) -1;
|
||||
inc_common:
|
||||
FLUSH_TIME();
|
||||
nz += READ( data );
|
||||
|
@ -791,7 +785,7 @@ imm##op:
|
|||
goto loop;
|
||||
|
||||
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 - 0xFE) ) * 0x100;
|
||||
sp = (sp - 0xFD) | 0x100;
|
||||
|
@ -811,9 +805,9 @@ imm##op:
|
|||
}
|
||||
|
||||
case 0x28:{// PLP
|
||||
fuint8 temp = READ_LOW( sp );
|
||||
uint8_t temp = READ_LOW( sp );
|
||||
sp = (sp - 0xFF) | 0x100;
|
||||
fuint8 changed = status ^ temp;
|
||||
uint8_t changed = status ^ temp;
|
||||
SET_STATUS( temp );
|
||||
if ( !(changed & st_i) )
|
||||
goto loop; // I flag didn't change
|
||||
|
@ -823,7 +817,7 @@ imm##op:
|
|||
}
|
||||
|
||||
case 0x08: { // PHP
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
PUSH( temp | (st_b | st_r) );
|
||||
goto loop;
|
||||
|
@ -843,7 +837,7 @@ imm##op:
|
|||
// Flags
|
||||
|
||||
case 0x38: // SEC
|
||||
c = (unsigned) ~0;
|
||||
c = (uint16_t) ~0;
|
||||
goto loop;
|
||||
|
||||
case 0x18: // CLC
|
||||
|
@ -932,7 +926,6 @@ imm##op:
|
|||
//case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
|
||||
|
||||
default:
|
||||
assert( (unsigned) opcode <= 0xFF );
|
||||
illegal_encountered = true;
|
||||
pc--;
|
||||
goto stop;
|
||||
|
@ -956,7 +949,7 @@ interrupt:
|
|||
pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ );
|
||||
|
||||
sp = (sp - 3) | 0x100;
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
temp |= st_r;
|
||||
if ( result_ )
|
||||
|
@ -998,7 +991,7 @@ stop:
|
|||
r.y = y;
|
||||
|
||||
{
|
||||
fuint8 temp;
|
||||
uint8_t temp;
|
||||
CALC_STATUS( temp );
|
||||
r.status = temp;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Atari 6502 CPU emulator
|
||||
|
||||
// Game_Music_Emu 0.6.0
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
#ifndef SAP_CPU_H
|
||||
#define SAP_CPU_H
|
||||
|
||||
|
@ -12,8 +12,6 @@ enum { future_sap_time = INT_MAX / 2 + 1 };
|
|||
|
||||
class Sap_Cpu {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Clear all registers and keep pointer to 64K memory passed in
|
||||
void reset( void* mem_64k );
|
||||
|
||||
|
@ -23,12 +21,12 @@ public:
|
|||
|
||||
// Registers are not updated until run() returns (except I flag in status)
|
||||
struct registers_t {
|
||||
BOOST::uint16_t pc;
|
||||
BOOST::uint8_t a;
|
||||
BOOST::uint8_t x;
|
||||
BOOST::uint8_t y;
|
||||
BOOST::uint8_t status;
|
||||
BOOST::uint8_t sp;
|
||||
uint16_t pc;
|
||||
uint8_t a;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t status;
|
||||
uint8_t sp;
|
||||
};
|
||||
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"
|
||||
|
||||
|
@ -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;
|
||||
while ( in < line_end && *in > ' ' )
|
||||
in++;
|
||||
int tag_len = int((char const*) in - tag);
|
||||
int tag_len = (char const*) in - tag;
|
||||
|
||||
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 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
|
||||
|
||||
|
@ -256,7 +255,7 @@ blargg_err_t Sap_Emu::load_mem_( byte const* in, long size )
|
|||
|
||||
set_warning( info.warning );
|
||||
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() );
|
||||
|
||||
return setup_buffer( 1773447 );
|
||||
|
@ -315,8 +314,8 @@ inline void Sap_Emu::call_init( int track )
|
|||
|
||||
case 'C':
|
||||
r.a = 0x70;
|
||||
r.x = (BOOST::uint8_t)(info.music_addr&0xFF);
|
||||
r.y = (BOOST::uint8_t)(info.music_addr >> 8);
|
||||
r.x = info.music_addr&0xFF;
|
||||
r.y = info.music_addr >> 8;
|
||||
run_routine( info.play_addr + 3 );
|
||||
r.a = 0;
|
||||
r.x = track;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define SAP_EMU_H
|
||||
|
||||
|
@ -54,8 +54,7 @@ private:
|
|||
// large items
|
||||
struct {
|
||||
byte padding1 [0x100];
|
||||
byte ram [0x10000];
|
||||
byte padding2 [0x100];
|
||||
byte ram [0x10000 + 0x100];
|
||||
} mem;
|
||||
Sap_Apu_Impl apu_impl;
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ void Sms_Noise::run( blip_time_t time, blip_time_t end_time )
|
|||
do
|
||||
{
|
||||
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
|
||||
{
|
||||
delta = -delta;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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"
|
||||
|
||||
|
@ -143,8 +143,8 @@ void Snes_Spc::ram_loaded()
|
|||
load_regs( &RAM [0xF0] );
|
||||
|
||||
// Put STOP instruction around memory to catch PC underflow/overflow
|
||||
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.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
|
||||
memset( m.ram.ram + 0x10000, cpu_pad_fill, sizeof m.ram.padding1 );
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
dsp.set_output( out, int(out_end - out) );
|
||||
dsp.set_output( out, out_end - out );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
// 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
|
||||
#define SNES_SPC_H
|
||||
|
||||
#include "Spc_Dsp.h"
|
||||
#include "blargg_endian.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct Snes_Spc {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Must be called once before using
|
||||
blargg_err_t init();
|
||||
|
||||
|
@ -108,12 +108,12 @@ public:
|
|||
// TODO: document
|
||||
struct regs_t
|
||||
{
|
||||
int pc;
|
||||
int a;
|
||||
int x;
|
||||
int y;
|
||||
int psw;
|
||||
int sp;
|
||||
uint16_t pc;
|
||||
uint8_t a;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t psw;
|
||||
uint8_t sp;
|
||||
};
|
||||
regs_t& smp_regs() { return m.cpu_regs; }
|
||||
|
||||
|
@ -123,8 +123,6 @@ public:
|
|||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
typedef BOOST::uint16_t uint16_t;
|
||||
|
||||
// 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
|
||||
// 0 to eliminate reloading end time every instruction. It pays off.
|
||||
|
@ -184,13 +182,11 @@ private:
|
|||
|
||||
struct
|
||||
{
|
||||
// padding to neutralize address overflow
|
||||
union {
|
||||
uint8_t padding1 [0x100];
|
||||
uint16_t align; // makes compiler align data for 16-bit access
|
||||
} padding1 [1];
|
||||
uint8_t ram [0x10000];
|
||||
uint8_t padding2 [0x100];
|
||||
// padding to neutralize address overflow -- but this is
|
||||
// still undefined behavior! TODO: remove and instead properly
|
||||
// guard usage of emulated memory
|
||||
uint8_t padding1 [0x100];
|
||||
alignas(uint16_t) uint8_t ram [0x10000 + 0x100];
|
||||
} ram;
|
||||
};
|
||||
state_t m;
|
||||
|
@ -226,13 +222,13 @@ private:
|
|||
Timer* run_timer ( Timer* t, rel_time_t );
|
||||
int dsp_read ( 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, int addr );
|
||||
void cpu_write_high ( int data, int i, rel_time_t );
|
||||
void cpu_write ( int data, int addr, rel_time_t );
|
||||
void cpu_write_smp_reg_( int data, rel_time_t, uint16_t addr );
|
||||
void cpu_write_smp_reg ( int data, rel_time_t, uint16_t addr );
|
||||
void cpu_write_high ( int data, uint8_t i );
|
||||
void cpu_write ( int data, uint16_t addr, rel_time_t );
|
||||
int cpu_read_smp_reg ( int i, rel_time_t );
|
||||
int cpu_read ( int addr, rel_time_t );
|
||||
unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t );
|
||||
int cpu_read ( uint16_t addr, rel_time_t );
|
||||
unsigned CPU_mem_bit ( uint16_t pc, rel_time_t );
|
||||
|
||||
bool check_echo_access ( int addr );
|
||||
uint8_t* run_until_( time_t end_time );
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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"
|
||||
|
||||
|
@ -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
|
||||
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 )
|
||||
{
|
||||
|
@ -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%
|
||||
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 );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
m.hi_ram [i] = (uint8_t) data;
|
||||
if ( m.rom_enabled )
|
||||
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 );
|
||||
}
|
||||
assert ( i < rom_size );
|
||||
m.hi_ram [i] = (uint8_t) data;
|
||||
if ( m.rom_enabled )
|
||||
RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
|
||||
}
|
||||
|
||||
int const bits_in_int = CHAR_BIT * sizeof (int);
|
||||
|
||||
void Snes_Spc::cpu_write( int data, int addr, rel_time_t time )
|
||||
void Snes_Spc::cpu_write( int data, uint16_t addr, rel_time_t time )
|
||||
{
|
||||
MEM_ACCESS( time, addr )
|
||||
|
||||
// RAM
|
||||
RAM [addr] = (uint8_t) data;
|
||||
int reg = addr - 0xF0;
|
||||
if ( reg >= 0 ) // 64%
|
||||
if ( addr >= 0xF0 ) // 64%
|
||||
{
|
||||
const uint16_t reg = addr - 0xF0;
|
||||
// $F0-$FF
|
||||
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 );
|
||||
}
|
||||
// High mem/address wrap-around
|
||||
else
|
||||
{
|
||||
reg -= rom_addr - 0xF0;
|
||||
if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around
|
||||
cpu_write_high( data, reg, time );
|
||||
}
|
||||
else if ( addr >= rom_addr ) // 1% in IPL ROM area or address wrapped around
|
||||
cpu_write_high( data, addr - rom_addr );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,7 +449,7 @@ inline int Snes_Spc::cpu_read_smp_reg( int reg, rel_time_t time )
|
|||
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 )
|
||||
|
||||
|
@ -507,7 +493,7 @@ int Snes_Spc::cpu_read( int addr, rel_time_t time )
|
|||
|
||||
// Prefix and suffix for CPU emulator function
|
||||
#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;\
|
||||
assert( rel_time <= 0 );\
|
||||
|
@ -527,7 +513,7 @@ BOOST::uint8_t* Snes_Spc::run_until_( time_t end_time )\
|
|||
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 )
|
||||
{
|
||||
|
|
|
@ -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
|
||||
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 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 GET_PC() (int(pc - ram))
|
||||
#define READ_PC( pc ) (*(pc))
|
||||
#define READ_PC16( pc ) GET_LE16( pc )
|
||||
#define SET_PC( n ) (pc = n)
|
||||
#define GET_PC() (pc)
|
||||
#define READ_PC( pc ) (ram [pc])
|
||||
#define READ_PC16( pc ) READ_PROG16( pc )
|
||||
|
||||
// TODO: remove non-wrapping versions?
|
||||
#define SPC_NO_SP_WRAPAROUND 0
|
||||
#define SET_SP( v ) (sp = v)
|
||||
#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 )\
|
||||
{\
|
||||
int addr = int((sp -= 2) - ram);\
|
||||
if ( addr > 0x100 )\
|
||||
{\
|
||||
SET_LE16( sp, data );\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
|
||||
sp [1] = (uint8_t) (data >> 8);\
|
||||
sp += 0x100;\
|
||||
}\
|
||||
PUSH( (data & 0xff00) >> 8 );\
|
||||
PUSH( data & 0xff );\
|
||||
}
|
||||
|
||||
#define PUSH( data )\
|
||||
{\
|
||||
*--sp = (uint8_t) (data);\
|
||||
if ( sp - ram == 0x100 )\
|
||||
sp += 0x100;\
|
||||
ram [0x100 + sp] = (uint8_t) (data);\
|
||||
--sp;\
|
||||
}
|
||||
|
||||
#define POP( out )\
|
||||
{\
|
||||
out = *sp++;\
|
||||
if ( sp - ram == 0x201 )\
|
||||
{\
|
||||
out = sp [-0x101];\
|
||||
sp -= 0x100;\
|
||||
}\
|
||||
++sp;\
|
||||
out = ram [0x100 + sp];\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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 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
|
||||
{
|
||||
uint8_t* const ram = RAM;
|
||||
int a = m.cpu_regs.a;
|
||||
int x = m.cpu_regs.x;
|
||||
int y = m.cpu_regs.y;
|
||||
uint8_t const* pc;
|
||||
uint8_t* sp;
|
||||
uint8_t a = m.cpu_regs.a;
|
||||
uint8_t x = m.cpu_regs.x;
|
||||
uint8_t y = m.cpu_regs.y;
|
||||
uint16_t pc;
|
||||
uint8_t sp;
|
||||
int psw;
|
||||
int c;
|
||||
int nz;
|
||||
|
@ -183,7 +158,7 @@ SPC_CPU_RUN_FUNC
|
|||
// Main loop
|
||||
|
||||
cbranch_taken_loop:
|
||||
pc += *(BOOST::int8_t const*) pc;
|
||||
pc += (int8_t) ram [pc];
|
||||
inc_pc_loop:
|
||||
pc++;
|
||||
loop:
|
||||
|
@ -195,7 +170,7 @@ loop:
|
|||
check( (unsigned) x < 0x100 );
|
||||
check( (unsigned) y < 0x100 );
|
||||
|
||||
opcode = *pc;
|
||||
opcode = ram [pc];
|
||||
if ( (rel_time += m.cycle_table [opcode]) > 0 )
|
||||
goto out_of_time;
|
||||
|
||||
|
@ -218,7 +193,8 @@ loop:
|
|||
*/
|
||||
|
||||
// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
|
||||
data = *++pc;
|
||||
pc++;
|
||||
data = ram [pc];
|
||||
switch ( opcode )
|
||||
{
|
||||
|
||||
|
@ -227,10 +203,10 @@ loop:
|
|||
#define BRANCH( cond )\
|
||||
{\
|
||||
pc++;\
|
||||
pc += (BOOST::int8_t) data;\
|
||||
pc += (int8_t) data;\
|
||||
if ( cond )\
|
||||
goto loop;\
|
||||
pc -= (BOOST::int8_t) data;\
|
||||
pc -= (int8_t) data;\
|
||||
rel_time -= 2;\
|
||||
goto loop;\
|
||||
}
|
||||
|
@ -249,23 +225,12 @@ loop:
|
|||
}
|
||||
|
||||
case 0x6F:// RET
|
||||
#if SPC_NO_SP_WRAPAROUND
|
||||
{
|
||||
SET_PC( GET_LE16( sp ) );
|
||||
sp += 2;
|
||||
uint8_t l, h;
|
||||
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;
|
||||
|
||||
case 0xE4: // MOV a,dp
|
||||
|
@ -294,8 +259,7 @@ loop:
|
|||
REGS [i] = (uint8_t) data;
|
||||
|
||||
// Registers other than $F2 and $F4-$F7
|
||||
//if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 )
|
||||
if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12%
|
||||
if ( i != 2 && (i < 4 || i > 7)) // 12%
|
||||
cpu_write_smp_reg( data, rel_time, i );
|
||||
}
|
||||
}
|
||||
|
@ -504,7 +468,7 @@ loop:
|
|||
case op + 0x01: /* dp,dp */\
|
||||
data = READ_DP( -3, data );\
|
||||
case op + 0x10:{/*dp,imm*/\
|
||||
uint8_t const* addr2 = pc + 1;\
|
||||
uint16_t addr2 = pc + 1;\
|
||||
pc += 2;\
|
||||
addr = READ_PC( addr2 ) + dp;\
|
||||
}\
|
||||
|
@ -878,7 +842,7 @@ loop:
|
|||
// 12. BRANCHING COMMANDS
|
||||
|
||||
case 0x2F: // BRA rel
|
||||
pc += (BOOST::int8_t) data;
|
||||
pc += (int8_t) data;
|
||||
goto inc_pc_loop;
|
||||
|
||||
case 0x30: // BMI
|
||||
|
@ -1002,10 +966,12 @@ loop:
|
|||
|
||||
{
|
||||
int temp;
|
||||
uint8_t l, h;
|
||||
case 0x7F: // RET1
|
||||
temp = *sp;
|
||||
SET_PC( GET_LE16( sp + 1 ) );
|
||||
SET_SP(GET_SP() + 3);
|
||||
POP (temp);
|
||||
POP (l);
|
||||
POP (h);
|
||||
SET_PC( l | (h << 8) );
|
||||
goto set_psw;
|
||||
case 0x8E: // POP PSW
|
||||
POP( temp );
|
||||
|
@ -1180,11 +1146,8 @@ loop:
|
|||
|
||||
case 0xFF:{// STOP
|
||||
// handle PC wrap-around
|
||||
unsigned addr = GET_PC() - 1;
|
||||
if ( addr >= 0x10000 )
|
||||
if ( pc == 0x0000 )
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
SET_PC( addr );
|
||||
debug_printf( "SPC: PC wrapped around\n" );
|
||||
goto loop;
|
||||
}
|
||||
|
@ -1199,14 +1162,12 @@ loop:
|
|||
} // switch
|
||||
|
||||
assert( 0 ); // catch any unhandled instructions
|
||||
}
|
||||
}
|
||||
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:
|
||||
|
||||
// Uncache registers
|
||||
if ( GET_PC() >= 0x10000 )
|
||||
debug_printf( "SPC: PC wrapped around\n" );
|
||||
m.cpu_regs.pc = (uint16_t) GET_PC();
|
||||
m.cpu_regs.sp = ( uint8_t) GET_SP();
|
||||
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"
|
||||
|
||||
|
@ -28,11 +28,11 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
|
||||
|
||||
// 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 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,
|
||||
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
|
||||
m.counters [0] = 1;
|
||||
m.counters [1] = 0;
|
||||
m.counters [2] = -0x20;
|
||||
m.counters [2] = -0x20u;
|
||||
m.counters [3] = 0x0B;
|
||||
|
||||
int n = 2;
|
||||
|
@ -498,8 +498,9 @@ void Spc_Dsp::run( int clock_count )
|
|||
// Decode four samples
|
||||
for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 )
|
||||
{
|
||||
// Extract upper nybble and scale appropriately
|
||||
int s = ((int16_t) nybbles >> right_shift) << left_shift;
|
||||
// Extract upper nybble and scale appropriately. Every cast is
|
||||
// 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)
|
||||
int const filter = brr_header & 0x0C;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define SPC_DSP_H
|
||||
|
||||
|
@ -8,8 +8,6 @@
|
|||
|
||||
struct Spc_Dsp {
|
||||
public:
|
||||
typedef BOOST::uint8_t uint8_t;
|
||||
|
||||
// Setup
|
||||
|
||||
// Initializes DSP and has it use the 64K RAM provided
|
||||
|
@ -89,9 +87,6 @@ public:
|
|||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
typedef BOOST::int8_t int8_t;
|
||||
typedef BOOST::int16_t int16_t;
|
||||
|
||||
enum { echo_hist_size = 8 };
|
||||
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
|
@ -154,7 +149,7 @@ private:
|
|||
|
||||
#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
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -228,14 +228,14 @@ struct Spc_File : Gme_Info_
|
|||
{
|
||||
RETURN_ERR( xid6.resize( xid6_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
@ -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 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
|
||||
|
@ -299,6 +299,11 @@ blargg_err_t Spc_Emu::start_track_( int track )
|
|||
RETURN_ERR( apu.load_spc( file_data, file_size ) );
|
||||
filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) );
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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"
|
||||
|
||||
|
@ -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 )
|
||||
{
|
||||
byte const* mid = skip_gd3_str( in, end );
|
||||
int len = int(mid - in) / 2 - 1;
|
||||
int len = (mid - in) / 2 - 1;
|
||||
if ( len > 0 )
|
||||
{
|
||||
len = min( len, (int) Gme_File::max_field_ );
|
||||
|
@ -108,7 +108,7 @@ byte const* Vgm_Emu::gd3_data( int* size ) const
|
|||
return 0;
|
||||
|
||||
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 )
|
||||
return 0;
|
||||
|
||||
|
@ -184,7 +184,7 @@ struct Vgm_File : Gme_Info_
|
|||
if ( 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;
|
||||
|
@ -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 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 };
|
||||
gme_type_t const gme_vgz_type = &gme_vgz_type_;
|
||||
BLARGG_EXPORT extern gme_type_t const gme_vgz_type = &gme_vgz_type_;
|
||||
|
||||
|
||||
// Setup
|
||||
|
@ -233,6 +233,25 @@ blargg_err_t Vgm_Emu::set_sample_rate_( long 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 )
|
||||
{
|
||||
psg.treble_eq( eq );
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define VGM_EMU_H
|
||||
|
||||
|
@ -17,6 +17,8 @@ public:
|
|||
// TODO: move into Music_Emu and rename to something like supports_custom_buffer()
|
||||
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
|
||||
// more aliasing of high notes.
|
||||
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"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#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
|
||||
|
||||
// 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"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
#define YM2413_EMU_H
|
||||
|
||||
|
|
|
@ -1,38 +1,19 @@
|
|||
// YM2612 FM sound chip emulator interface
|
||||
|
||||
// Game_Music_Emu 0.6.0
|
||||
#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 );
|
||||
};
|
||||
// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/
|
||||
|
||||
#ifdef VGM_YM2612_GENS // LGPL v2.1+ license
|
||||
#include "Ym2612_GENS.h"
|
||||
typedef Ym2612_GENS_Emu Ym2612_Emu;
|
||||
#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
|
||||
|
||||
#include "Ym2612_Emu.h"
|
||||
#include "Ym2612_GENS.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -11,7 +11,7 @@
|
|||
#include <stdio.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
|
||||
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
|
||||
|
@ -44,9 +44,9 @@ struct slot_t
|
|||
int MUL; // parametre "multiple de frequence"
|
||||
int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
|
||||
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; // 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 !
|
||||
int SEG; // Type enveloppe SSG
|
||||
int env_xor;
|
||||
|
@ -58,24 +58,24 @@ struct slot_t
|
|||
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 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
|
||||
// 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
|
||||
// de mettre ・jour l'enveloppe courante.
|
||||
int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir o・l'on se trouve dans l'enveloppe
|
||||
// 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 Einc; // Envelope step courant
|
||||
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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// cette valeur est egal ・RR[KSR]
|
||||
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
|
||||
// cette valeur est egal à RR[KSR]
|
||||
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
|
||||
int INd; // input data of the slot = donnees en entree du slot
|
||||
int ChgEnM; // Change envelop mask.
|
||||
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 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 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 TimerBcnt; // timerB counter = valeur courante du Timer B
|
||||
int Mode; // Mode actuel des voie 3 et 6 (normal / special)
|
||||
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
|
||||
// cela nous rend le debuggage plus facile
|
||||
};
|
||||
|
@ -203,9 +203,9 @@ struct tables_t
|
|||
unsigned int SL_TAB [16]; // Substain level table
|
||||
unsigned int NULL_RATE [32]; // Table for NULL rate
|
||||
int LFO_INC_TAB [8]; // LFO step table
|
||||
|
||||
|
||||
short ENV_TAB [2 * ENV_LENGHT + 8]; // ENV CURVE TABLE (attack & decay)
|
||||
|
||||
|
||||
short LFO_ENV_TAB [LFO_LENGHT]; // LFO AMS TABLE (adjusted for 11.8 dB)
|
||||
short LFO_FREQ_TAB [LFO_LENGHT]; // LFO FMS TABLE
|
||||
int TL_TAB [TL_LENGHT * 2]; // TOTAL LEVEL TABLE (positif and minus)
|
||||
|
@ -233,7 +233,7 @@ static const unsigned char DT_DEF_TAB [4 * 32] =
|
|||
};
|
||||
|
||||
static const unsigned char FKEY_TAB [16] =
|
||||
{
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 1,
|
||||
2, 3, 3, 3,
|
||||
|
@ -255,38 +255,38 @@ static const unsigned char LFO_FMS_TAB [8] =
|
|||
|
||||
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;
|
||||
int mute_mask;
|
||||
tables_t g;
|
||||
|
||||
|
||||
void KEY_ON( channel_t&, int );
|
||||
void KEY_OFF( channel_t&, int );
|
||||
int SLOT_SET( int, int );
|
||||
int CHANNEL_SET( int, int );
|
||||
int YM_SET( int, int );
|
||||
|
||||
|
||||
void set_rate( double sample_rate, double clock_factor );
|
||||
void reset();
|
||||
void write0( int addr, int data );
|
||||
void write1( int addr, int data );
|
||||
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
|
||||
|
||||
|
||||
if (SL->Ecurp == RELEASE) // la touche est-elle rel'chee ?
|
||||
{
|
||||
SL->Fcnt = 0;
|
||||
|
||||
// Fix Ecco 2 splash sound
|
||||
|
||||
|
||||
SL->Ecnt = (g.DECAY_TO_ATTACK [g.ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK) & SL->ChgEnM;
|
||||
SL->ChgEnM = ~0;
|
||||
|
||||
|
@ -300,10 +300,10 @@ 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
|
||||
|
||||
|
||||
if (SL->Ecurp != RELEASE) // la touche est-elle appuyee ?
|
||||
{
|
||||
if (SL->Ecnt < ENV_DECAY) // attack phase ?
|
||||
|
@ -318,12 +318,12 @@ 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;
|
||||
if ( nch == 3 )
|
||||
return 1;
|
||||
|
||||
|
||||
channel_t& ch = YM2612.CHANNEL [nch + (Adr & 0x100 ? 3 : 0)];
|
||||
slot_t& sl = ch.SLOT [(Adr >> 2) & 3];
|
||||
|
||||
|
@ -397,7 +397,7 @@ int Ym2612_Impl::SLOT_SET( int Adr, int data )
|
|||
// SSG-EG envelope shapes :
|
||||
/*
|
||||
E At Al H
|
||||
|
||||
|
||||
1 0 0 0 \\\\
|
||||
1 0 0 1 \___
|
||||
1 0 1 0 \/\/
|
||||
|
@ -406,7 +406,7 @@ int Ym2612_Impl::SLOT_SET( int Adr, int data )
|
|||
1 1 0 1 /
|
||||
1 1 1 0 /\/\
|
||||
1 1 1 1 /___
|
||||
|
||||
|
||||
E = SSG-EG enable
|
||||
At = Start negate
|
||||
Al = Altern
|
||||
|
@ -420,14 +420,14 @@ 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;
|
||||
if ( num == 3 )
|
||||
return 1;
|
||||
|
||||
|
||||
channel_t& ch = YM2612.CHANNEL [num + (Adr & 0x100 ? 3 : 0)];
|
||||
|
||||
|
||||
switch ( Adr & 0xFC )
|
||||
{
|
||||
case 0xA0:
|
||||
|
@ -487,7 +487,7 @@ int Ym2612_Impl::CHANNEL_SET( int Adr, int data )
|
|||
YM2612_Special_Update();
|
||||
|
||||
ch.ALGO = data & 7;
|
||||
|
||||
|
||||
ch.SLOT [0].ChgEnM = 0;
|
||||
ch.SLOT [1].ChgEnM = 0;
|
||||
ch.SLOT [2].ChgEnM = 0;
|
||||
|
@ -502,13 +502,13 @@ int Ym2612_Impl::CHANNEL_SET( int Adr, int data )
|
|||
|
||||
case 0xB4: {
|
||||
YM2612_Special_Update();
|
||||
|
||||
|
||||
ch.LEFT = 0 - ((data >> 7) & 1);
|
||||
ch.RIGHT = 0 - ((data >> 6) & 1);
|
||||
|
||||
|
||||
ch.AMS = LFO_AMS_TAB [(data >> 4) & 3];
|
||||
ch.FMS = LFO_FMS_TAB [data & 7];
|
||||
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
slot_t& sl = ch.SLOT [i];
|
||||
|
@ -517,12 +517,12 @@ int Ym2612_Impl::CHANNEL_SET( int Adr, int data )
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Ym2612_Impl::YM_SET(int Adr, int data)
|
||||
int Ym2612_GENS_Impl::YM_SET(int Adr, int data)
|
||||
{
|
||||
switch ( Adr )
|
||||
{
|
||||
|
@ -617,27 +617,27 @@ int Ym2612_Impl::YM_SET(int Adr, int data)
|
|||
else KEY_OFF(ch, S3); // On rel'che la touche pour le slot 4
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 0x2B:
|
||||
if (YM2612.DAC ^ (data & 0x80)) YM2612_Special_Update();
|
||||
|
||||
YM2612.DAC = data & 0x80; // activation/desactivation du DAC
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
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( clock_rate > sample_rate );
|
||||
|
||||
|
||||
int i;
|
||||
|
||||
// 144 = 12 * (prescale * 2) = 12 * 6 * 2
|
||||
// prescale set to 6 by default
|
||||
|
||||
|
||||
double Frequence = clock_rate / sample_rate / 144.0;
|
||||
if ( fabs( Frequence - 1.0 ) < 0.0000001 )
|
||||
Frequence = 1.0;
|
||||
|
@ -662,9 +662,9 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
g.TL_TAB [TL_LENGHT + i] = -g.TL_TAB [i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tableau SIN :
|
||||
// g.SIN_TAB [x] [y] = sin(x) * y;
|
||||
// g.SIN_TAB [x] [y] = sin(x) * y;
|
||||
// x = phase and y = volume
|
||||
|
||||
g.SIN_TAB [0] = g.SIN_TAB [SIN_LENGHT / 2] = PG_CUT_OFF;
|
||||
|
@ -720,11 +720,11 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
}
|
||||
for ( i = 0; i < 8; i++ )
|
||||
g.ENV_TAB [i + ENV_LENGHT * 2] = 0;
|
||||
|
||||
|
||||
g.ENV_TAB [ENV_END >> ENV_LBITS] = ENV_LENGHT - 1; // for the stopped state
|
||||
|
||||
|
||||
// Tableau pour la conversion Attack -> Decay and Decay -> Attack
|
||||
|
||||
|
||||
int j = ENV_LENGHT - 1;
|
||||
for ( i = 0; i < ENV_LENGHT; i++ )
|
||||
{
|
||||
|
@ -735,7 +735,7 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
}
|
||||
|
||||
// Tableau pour le Substain Level
|
||||
|
||||
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
double x = i * 3; // 3 and not 6 (Mickey Mania first music for test)
|
||||
|
@ -770,7 +770,7 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
g.AR_TAB [i] = 0;
|
||||
g.DR_TAB [i] = 0;
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < 60; i++)
|
||||
{
|
||||
double x = Frequence;
|
||||
|
@ -790,10 +790,10 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
|
||||
g.NULL_RATE [i - 64] = 0;
|
||||
}
|
||||
|
||||
|
||||
for ( i = 96; i < 128; i++ )
|
||||
g.AR_TAB [i] = 0;
|
||||
|
||||
|
||||
// Tableau Detune
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
|
@ -810,7 +810,7 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
g.DT_TAB [i + 4] [j] = (int) -y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tableau LFO
|
||||
g.LFO_INC_TAB [0] = (unsigned int) (3.98 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
|
||||
g.LFO_INC_TAB [1] = (unsigned int) (5.56 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
|
||||
|
@ -820,35 +820,35 @@ void Ym2612_Impl::set_rate( double sample_rate, double clock_rate )
|
|||
g.LFO_INC_TAB [5] = (unsigned int) (9.63 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
|
||||
g.LFO_INC_TAB [6] = (unsigned int) (48.1 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
|
||||
g.LFO_INC_TAB [7] = (unsigned int) (72.2 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
impl = (Ym2612_Impl*) malloc( sizeof *impl );
|
||||
impl = (Ym2612_GENS_Impl*) malloc( sizeof *impl );
|
||||
if ( !impl )
|
||||
return "Out of memory";
|
||||
impl->mute_mask = 0;
|
||||
}
|
||||
memset( &impl->YM2612, 0, sizeof impl->YM2612 );
|
||||
|
||||
|
||||
impl->set_rate( sample_rate, clock_rate );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ym2612_Emu::~Ym2612_Emu()
|
||||
Ym2612_GENS_Emu::~Ym2612_GENS_Emu()
|
||||
{
|
||||
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 );
|
||||
|
||||
|
||||
if ( opn_addr < 0x30 )
|
||||
{
|
||||
YM2612.REG [0] [opn_addr] = data;
|
||||
|
@ -857,7 +857,7 @@ inline void Ym2612_Impl::write0( int opn_addr, int data )
|
|||
else if ( YM2612.REG [0] [opn_addr] != data )
|
||||
{
|
||||
YM2612.REG [0] [opn_addr] = data;
|
||||
|
||||
|
||||
if ( opn_addr < 0xA0 )
|
||||
SLOT_SET( opn_addr, data );
|
||||
else
|
||||
|
@ -865,10 +865,10 @@ 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 );
|
||||
|
||||
|
||||
if ( opn_addr >= 0x30 && YM2612.REG [1] [opn_addr] != data )
|
||||
{
|
||||
YM2612.REG [1] [opn_addr] = data;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
void Ym2612_Impl::reset()
|
||||
void Ym2612_GENS_Impl::reset()
|
||||
{
|
||||
g.LFOcnt = 0;
|
||||
YM2612.TimerA = 0;
|
||||
|
@ -902,7 +902,7 @@ void Ym2612_Impl::reset()
|
|||
for ( i = 0; i < channel_count; i++ )
|
||||
{
|
||||
channel_t& ch = YM2612.CHANNEL [i];
|
||||
|
||||
|
||||
ch.LEFT = ~0;
|
||||
ch.RIGHT = ~0;
|
||||
ch.ALGO = 0;
|
||||
|
@ -945,21 +945,21 @@ void Ym2612_Impl::reset()
|
|||
write0( i, 0 );
|
||||
write1( i, 0 );
|
||||
}
|
||||
|
||||
|
||||
write0( 0x2A, 0x80 );
|
||||
}
|
||||
|
||||
void Ym2612_Emu::write0( int addr, int data )
|
||||
void Ym2612_GENS_Emu::write0( int addr, int 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 );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
|
@ -967,7 +967,7 @@ static void update_envelope_( slot_t* sl )
|
|||
{
|
||||
case 0:
|
||||
// Env_Attack_Next
|
||||
|
||||
|
||||
// Verified with Gynoug even in HQ (explode SFX)
|
||||
sl->Ecnt = ENV_DECAY;
|
||||
|
||||
|
@ -975,10 +975,10 @@ static void update_envelope_( slot_t* sl )
|
|||
sl->Ecmp = sl->SLL;
|
||||
sl->Ecurp = DECAY;
|
||||
break;
|
||||
|
||||
|
||||
case 1:
|
||||
// Env_Decay_Next
|
||||
|
||||
|
||||
// Verified with Gynoug even in HQ (explode SFX)
|
||||
sl->Ecnt = sl->SLL;
|
||||
|
||||
|
@ -986,13 +986,13 @@ static void update_envelope_( slot_t* sl )
|
|||
sl->Ecmp = ENV_END;
|
||||
sl->Ecurp = SUBSTAIN;
|
||||
break;
|
||||
|
||||
|
||||
case 2:
|
||||
// Env_Substain_Next(slot_t *SL)
|
||||
if (sl->SEG & 8) // SSG envelope type
|
||||
{
|
||||
int release = sl->SEG & 1;
|
||||
|
||||
|
||||
if ( !release )
|
||||
{
|
||||
// re KEY ON
|
||||
|
@ -1007,19 +1007,19 @@ static void update_envelope_( slot_t* sl )
|
|||
}
|
||||
|
||||
set_seg( *sl, (sl->SEG << 1) & 4 );
|
||||
|
||||
|
||||
if ( !release )
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
|
||||
|
||||
case 3:
|
||||
// Env_Release_Next
|
||||
sl->Ecnt = ENV_END;
|
||||
sl->Einc = 0;
|
||||
sl->Ecmp = ENV_END + 1;
|
||||
break;
|
||||
|
||||
|
||||
// default: no op
|
||||
}
|
||||
}
|
||||
|
@ -1033,64 +1033,64 @@ inline void update_envelope( slot_t& sl )
|
|||
|
||||
template<int algo>
|
||||
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>
|
||||
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;
|
||||
|
||||
|
||||
// algo is a compile-time constant, so all conditions based on it are resolved
|
||||
// during compilation
|
||||
|
||||
|
||||
// special cases
|
||||
if ( algo == 7 )
|
||||
not_end |= ch.SLOT [S0].Ecnt - ENV_END;
|
||||
|
||||
|
||||
if ( algo >= 5 )
|
||||
not_end |= ch.SLOT [S2].Ecnt - ENV_END;
|
||||
|
||||
|
||||
if ( algo >= 4 )
|
||||
not_end |= ch.SLOT [S1].Ecnt - ENV_END;
|
||||
|
||||
|
||||
int CH_S0_OUT_1 = ch.S0_OUT [1];
|
||||
|
||||
|
||||
int in0 = ch.SLOT [S0].Fcnt;
|
||||
int in1 = ch.SLOT [S1].Fcnt;
|
||||
int in2 = ch.SLOT [S2].Fcnt;
|
||||
int in3 = ch.SLOT [S3].Fcnt;
|
||||
|
||||
|
||||
int YM2612_LFOinc = g.LFOinc;
|
||||
int YM2612_LFOcnt = g.LFOcnt + YM2612_LFOinc;
|
||||
|
||||
|
||||
if ( !not_end )
|
||||
return;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
// envelope
|
||||
int const env_LFO = g.LFO_ENV_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK];
|
||||
|
||||
|
||||
short const* const ENV_TAB = g.ENV_TAB;
|
||||
|
||||
|
||||
#define CALC_EN( x ) \
|
||||
int temp##x = ENV_TAB [ch.SLOT [S##x].Ecnt >> ENV_LBITS] + ch.SLOT [S##x].TLL; \
|
||||
int en##x = ((temp##x ^ ch.SLOT [S##x].env_xor) + (env_LFO >> ch.SLOT [S##x].AMS)) & \
|
||||
((temp##x - ch.SLOT [S##x].env_max) >> 31);
|
||||
|
||||
|
||||
CALC_EN( 0 )
|
||||
CALC_EN( 1 )
|
||||
CALC_EN( 2 )
|
||||
CALC_EN( 3 )
|
||||
|
||||
|
||||
int const* const TL_TAB = g.TL_TAB;
|
||||
|
||||
|
||||
#define SINT( i, o ) (TL_TAB [g.SIN_TAB [(i)] + (o)])
|
||||
|
||||
|
||||
// feedback
|
||||
int CH_S0_OUT_0 = ch.S0_OUT [0];
|
||||
{
|
||||
|
@ -1098,7 +1098,7 @@ void ym2612_update_chan<algo>::func( tables_t& g, channel_t& ch,
|
|||
CH_S0_OUT_1 = CH_S0_OUT_0;
|
||||
CH_S0_OUT_0 = SINT( (temp >> SIN_LBITS) & SIN_MASK, en0 );
|
||||
}
|
||||
|
||||
|
||||
int CH_OUTd;
|
||||
if ( algo == 0 )
|
||||
{
|
||||
|
@ -1155,9 +1155,9 @@ void ym2612_update_chan<algo>::func( tables_t& g, channel_t& ch,
|
|||
SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ) + CH_S0_OUT_1;
|
||||
//DO_LIMIT
|
||||
}
|
||||
|
||||
|
||||
CH_OUTd >>= MAX_OUT_BITS - output_bits + 2;
|
||||
|
||||
|
||||
// update phase
|
||||
unsigned freq_LFO = ((g.LFO_FREQ_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK] *
|
||||
ch.FMS) >> (LFO_HBITS - 1 + 1)) + (1L << (LFO_FMS_LBITS - 1));
|
||||
|
@ -1166,24 +1166,24 @@ void ym2612_update_chan<algo>::func( tables_t& g, channel_t& ch,
|
|||
in1 += (ch.SLOT [S1].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1);
|
||||
in2 += (ch.SLOT [S2].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1);
|
||||
in3 += (ch.SLOT [S3].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1);
|
||||
|
||||
|
||||
int t0 = buf [0] + (CH_OUTd & ch.LEFT);
|
||||
int t1 = buf [1] + (CH_OUTd & ch.RIGHT);
|
||||
|
||||
|
||||
update_envelope( ch.SLOT [0] );
|
||||
update_envelope( ch.SLOT [1] );
|
||||
update_envelope( ch.SLOT [2] );
|
||||
update_envelope( ch.SLOT [3] );
|
||||
|
||||
|
||||
ch.S0_OUT [0] = CH_S0_OUT_0;
|
||||
buf [0] = t0;
|
||||
buf [1] = t1;
|
||||
buf += 2;
|
||||
}
|
||||
while ( --length );
|
||||
|
||||
|
||||
ch.S0_OUT [1] = CH_S0_OUT_1;
|
||||
|
||||
|
||||
ch.SLOT [S0].Fcnt = in0;
|
||||
ch.SLOT [S1].Fcnt = in1;
|
||||
ch.SLOT [S2].Fcnt = in2;
|
||||
|
@ -1201,7 +1201,7 @@ static const ym2612_update_chan_t UPDATE_CHAN [8] = {
|
|||
&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 remain = length;
|
||||
|
@ -1211,7 +1211,7 @@ void Ym2612_Impl::run_timer( int length )
|
|||
if ( n > remain )
|
||||
n = remain;
|
||||
remain -= n;
|
||||
|
||||
|
||||
long i = n * YM2612.TimerBase;
|
||||
if (YM2612.Mode & 1) // Timer A ON ?
|
||||
{
|
||||
|
@ -1219,7 +1219,7 @@ void Ym2612_Impl::run_timer( int length )
|
|||
if ((YM2612.TimerAcnt -= i) <= 0)
|
||||
{
|
||||
// timer a overflow
|
||||
|
||||
|
||||
YM2612.Status |= (YM2612.Mode & 0x04) >> 2;
|
||||
YM2612.TimerAcnt += YM2612.TimerAL;
|
||||
|
||||
|
@ -1247,37 +1247,37 @@ void Ym2612_Impl::run_timer( int length )
|
|||
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 )
|
||||
return;
|
||||
|
||||
|
||||
if ( YM2612.Mode & 3 )
|
||||
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++ )
|
||||
{
|
||||
channel_t& ch = YM2612.CHANNEL [chi];
|
||||
if ( ch.SLOT [0].Finc != -1 )
|
||||
continue;
|
||||
|
||||
|
||||
int i2 = 0;
|
||||
if ( chi == 2 && (YM2612.Mode & 0x40) )
|
||||
i2 = 2;
|
||||
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
// static int seq [4] = { 2, 1, 3, 0 };
|
||||
// if ( i2 ) i2 = seq [i];
|
||||
|
||||
|
||||
slot_t& sl = ch.SLOT [i];
|
||||
int finc = g.FINC_TAB [ch.FNUM [i2]] >> (7 - ch.FOCT [i2]);
|
||||
int ksr = ch.KC [i2] >> sl.KSR_S; // keycode attenuation
|
||||
sl.Finc = (finc + sl.DT [ch.KC [i2]]) * sl.MUL;
|
||||
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.EincA = sl.AR [ksr];
|
||||
|
@ -1301,19 +1301,19 @@ void Ym2612_Impl::run( int pair_count, Ym2612_Emu::sample_t* out )
|
|||
sl.Einc = sl.EincR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( i2 )
|
||||
i2 = (i2 ^ 2) ^ (i2 >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for ( int i = 0; i < channel_count; i++ )
|
||||
{
|
||||
if ( !(mute_mask & (1 << i)) && (i != 5 || !YM2612.DAC) )
|
||||
UPDATE_CHAN [YM2612.CHANNEL [i].ALGO]( g, YM2612.CHANNEL [i], out, 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 ) \
|
||||
((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.
|
||||
#ifndef BOOST_STATIC_ASSERT
|
||||
#ifdef _MSC_VER
|
||||
|
@ -132,51 +135,12 @@ public:
|
|||
typedef unsigned blargg_ulong;
|
||||
#endif
|
||||
|
||||
// BOOST::int8_t etc.
|
||||
// int8_t etc.
|
||||
|
||||
// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
|
||||
#if defined (HAVE_STDINT_H)
|
||||
// TODO: Add CMake check for this, although I'd likely just point affected
|
||||
// persons to a real compiler...
|
||||
#if 1 || defined (HAVE_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
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
|
|
|
@ -123,15 +123,15 @@ inline void set_be32( void* p, blargg_ulong n )
|
|||
#if BLARGG_NONPORTABLE
|
||||
// Optimized implementation if byte order is known
|
||||
#if BLARGG_LITTLE_ENDIAN
|
||||
#define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
|
||||
#define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
|
||||
#define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#define GET_LE16( addr ) (*(uint16_t*) (addr))
|
||||
#define GET_LE32( addr ) (*(uint32_t*) (addr))
|
||||
#define SET_LE16( addr, data ) (void) (*(uint16_t*) (addr) = (data))
|
||||
#define SET_LE32( addr, data ) (void) (*(uint32_t*) (addr) = (data))
|
||||
#elif BLARGG_BIG_ENDIAN
|
||||
#define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
|
||||
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
|
||||
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#define GET_BE16( addr ) (*(uint16_t*) (addr))
|
||||
#define GET_BE32( addr ) (*(uint32_t*) (addr))
|
||||
#define SET_BE16( addr, data ) (void) (*(uint16_t*) (addr) = (data))
|
||||
#define SET_BE32( addr, data ) (void) (*(uint32_t*) (addr) = (data))
|
||||
|
||||
#if BLARGG_CPU_POWERPC
|
||||
// PowerPC has special byte-reversed instructions
|
||||
|
@ -172,13 +172,13 @@ inline void set_be32( void* p, blargg_ulong n )
|
|||
|
||||
// auto-selecting versions
|
||||
|
||||
inline void set_le( BOOST::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_be( BOOST::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 unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
|
||||
inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
|
||||
inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
|
||||
inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
|
||||
inline void set_le( uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
||||
inline void set_le( uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
|
||||
inline void set_be( uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
||||
inline void set_be( uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
|
||||
inline unsigned get_le( uint16_t* p ) { return GET_LE16( p ); }
|
||||
inline blargg_ulong get_le( uint32_t* p ) { return GET_LE32( p ); }
|
||||
inline unsigned get_be( uint16_t* p ) { return GET_BE16( p ); }
|
||||
inline blargg_ulong get_be( uint32_t* p ) { return GET_BE32( p ); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,19 @@ all other #include lines. */
|
|||
#undef require
|
||||
#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
|
||||
// nothing (not even evaluate its arguments).
|
||||
// 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"
|
||||
|
||||
|
@ -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('V','g','m',' '): return "VGM";
|
||||
}
|
||||
if (get_be16(header) == BLARGG_2CHAR(0x1F, 0x8B))
|
||||
return "VGZ";
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -111,6 +113,14 @@ BLARGG_EXPORT gme_type_t gme_identify_extension( const char* extension_ )
|
|||
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 )
|
||||
{
|
||||
*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;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
|
@ -198,9 +209,18 @@ BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
|
|||
if ( me )
|
||||
{
|
||||
#if !GME_DISABLE_STEREO_DEPTH
|
||||
me->set_multi_channel( multi_channel );
|
||||
|
||||
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 )
|
||||
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;
|
||||
}
|
||||
|
||||
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_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_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_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 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 )
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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
|
||||
#define GME_H
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
|||
extern "C" {
|
||||
#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) */
|
||||
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 */
|
||||
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 ********/
|
||||
|
||||
/* Error returned if file type is not supported */
|
||||
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 );
|
||||
|
||||
/* 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. */
|
||||
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).
|
||||
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 );
|
||||
|
@ -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. */
|
||||
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 */
|
||||
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
|
||||
#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
|
||||
* conditionally compile in the various emulator types.
|
||||
*
|
||||
* See gme_type_list() in gme.cpp
|
||||
/*
|
||||
* This is a default gme_types.h for use when *not* using
|
||||
* CMake. If CMake is in use gme_types.h.in will be
|
||||
* processed instead.
|
||||
*/
|
||||
|
||||
#define USE_GME_AY
|
||||
#define USE_GME_GBS
|
||||
#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
|
||||
support the following formats and systems:
|
||||
|
@ -34,10 +34,12 @@ several architectures, Mac OS, MorphOS, Xbox, PlayStation Portable,
|
|||
GP2X, and Nintendo DS.
|
||||
|
||||
Author : Shay Green <gblargg@gmail.com>
|
||||
Website: http://www.slack.net/~ant/
|
||||
Forum : http://groups.google.com/group/blargg-sound-libs
|
||||
Website: https://bitbucket.org/mpyne/game-music-emu/wiki/Home
|
||||
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>
|
||||
|
||||
Getting Started
|
||||
|
@ -191,8 +193,13 @@ gme/
|
|||
Sms_Apu.cpp Common Sega emulator files
|
||||
Sms_Apu.h
|
||||
Sms_Oscs.h
|
||||
Ym2612_Emu.cpp
|
||||
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.h
|
||||
Fir_Resampler.cpp
|
||||
|
@ -219,7 +226,7 @@ gme/
|
|||
Multi_Buffer.cpp
|
||||
Data_Reader.h
|
||||
Data_Reader.cpp
|
||||
|
||||
|
||||
CMakeLists.txt CMake build rules
|
||||
|
||||
|
||||
|
@ -227,6 +234,8 @@ Legal
|
|||
-----
|
||||
Game_Music_Emu library copyright (C) 2003-2009 Shay Green.
|
||||
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>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue