Upgrade game-music-emu to version 0.6.0

This commit is contained in:
Randy Heit 2014-04-03 09:18:00 -05:00
parent 1d1289722f
commit fbddfbe576
95 changed files with 1139 additions and 650 deletions

View file

@ -1,5 +1,15 @@
cmake_minimum_required( VERSION 2.4 ) # CMake project definition file.
include( CheckCXXCompilerFlag ) project(libgme)
include (CheckCXXCompilerFlag)
# When version is changed, also change the one in gme/gme.h to match
set(GME_VERSION 0.6.0 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.6 FATAL_ERROR)
make_release_only() make_release_only()
@ -19,51 +29,80 @@ if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STRE
endif( HAVE_NO_ARRAY_BOUNDS ) endif( HAVE_NO_ARRAY_BOUNDS )
endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
add_library( gme
gme/Blip_Buffer.cpp
gme/Classic_Emu.cpp # Default emulators to build (all of them! ;)
gme/Data_Reader.cpp if (NOT DEFINED USE_GME_AY)
gme/Dual_Resampler.cpp SET(USE_GME_AY 1 CACHE BOOL "Enable support for Spectrum ZX music emulation")
gme/Effects_Buffer.cpp endif()
gme/Fir_Resampler.cpp
gme/gme.cpp if (NOT DEFINED USE_GME_GBS)
gme/Gme_File.cpp SET(USE_GME_GBS 1 CACHE BOOL "Enable support for Game Boy music emulation")
gme/M3u_Playlist.cpp endif()
gme/Multi_Buffer.cpp
gme/Music_Emu.cpp if (NOT DEFINED USE_GME_GYM)
SET(USE_GME_GYM 1 CACHE BOOL "Enable Sega MegaDrive/Genesis music emulation")
gme/Ay_Apu.cpp endif()
gme/Ay_Cpu.cpp
gme/Ay_Emu.cpp if (NOT DEFINED USE_GME_HES)
gme/Gb_Apu.cpp SET(USE_GME_HES 1 CACHE BOOL "Enable PC Engine/TurboGrafx-16 music emulation")
gme/Gb_Cpu.cpp endif()
gme/Gb_Oscs.cpp
gme/Gbs_Emu.cpp if (NOT DEFINED USE_GME_KSS)
gme/Gym_Emu.cpp SET(USE_GME_KSS 1 CACHE BOOL "Enable MSX or other Z80 systems music emulation")
gme/Hes_Apu.cpp endif()
gme/Hes_Cpu.cpp
gme/Hes_Emu.cpp if (NOT DEFINED USE_GME_NSF)
gme/Kss_Cpu.cpp SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation")
gme/Kss_Emu.cpp endif()
gme/Kss_Scc_Apu.cpp
gme/Nes_Apu.cpp if (NOT DEFINED USE_GME_NSFE)
gme/Nes_Cpu.cpp SET(USE_GME_NSFE 1 CACHE BOOL "Enable NES NSFE and NSF music emulation")
gme/Nes_Fme7_Apu.cpp endif()
gme/Nes_Namco_Apu.cpp
gme/Nes_Oscs.cpp if (NOT DEFINED USE_GME_SAP)
gme/Nes_Vrc6_Apu.cpp SET(USE_GME_SAP 1 CACHE BOOL "Enable Atari SAP music emulation")
gme/Nsf_Emu.cpp endif()
gme/Nsfe_Emu.cpp
gme/Sap_Apu.cpp if (NOT DEFINED USE_GME_SPC)
gme/Sap_Cpu.cpp SET(USE_GME_SPC 1 CACHE BOOL "Enable SNES SPC music emulation")
gme/Sap_Emu.cpp endif()
gme/Sms_Apu.cpp
gme/Snes_Spc.cpp if (NOT DEFINED USE_GME_VGM)
gme/Spc_Cpu.cpp SET(USE_GME_VGM 1 CACHE BOOL "Enable Sega VGM/VGZ music emulation")
gme/Spc_Dsp.cpp endif()
gme/Spc_Emu.cpp
gme/Vgm_Emu.cpp if (USE_GME_NSFE AND NOT USE_GME_NSF)
gme/Vgm_Emu_Impl.cpp MESSAGE(" -- NSFE support requires NSF, enabling NSF support. --")
gme/Ym2413_Emu.cpp SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation" FORCE)
gme/Ym2612_Emu.cpp ) endif()
target_link_libraries( gme )
# 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}")
# 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)
# 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
endif (CMAKE_COMPILER_IS_GNUCXX)
# Cache this result
set( LIBGME_HAVE_GCC_VISIBILITY ${ENABLE_VISIBILITY} CACHE BOOL "GCC support for hidden visibility")
# Shared library defined here
add_subdirectory(gme)

View file

@ -1,6 +1,50 @@
Game_Music_Emu Change Log Game_Music_Emu Change Log
------------------------- -------------------------
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 Game_Music_Emu 0.5.2
-------------------- --------------------
- *TONS* of changes and improvements. You should re-read the new header - *TONS* of changes and improvements. You should re-read the new header

View file

@ -1,4 +1,4 @@
Game_Music_Emu 0.5.2 Design Game_Music_Emu 0.6.0 Design
--------------------------- ---------------------------
This might be slightly out-of-date at times, but will be a big help in This might be slightly out-of-date at times, but will be a big help in
understanding the library implementation. understanding the library implementation.

View file

@ -1,15 +1,14 @@
Game_Music_Emu 0.5.2 Game_Music_Emu 0.6.0
-------------------- --------------------
Author : Shay Green <gblargg@gmail.com> Author : Shay Green <gblargg@gmail.com>
Website: http://www.slack.net/~ant/libs/ Website: http://www.slack.net/~ant/libs/
Forum : http://groups.google.com/group/blargg-sound-libs Forum : http://groups.google.com/group/blargg-sound-libs
Source : https://code.google.com/p/game-music-emu/
License: GNU Lesser General Public License (LGPL) License: GNU Lesser General Public License (LGPL)
Contents Contents
-------- --------
* Overview * Overview
* C and C++ interfaces
* Function reference
* Error handling * Error handling
* Emulator types * Emulator types
* M3U playlist support * M3U playlist support
@ -21,7 +20,6 @@ Contents
* Modular construction * Modular construction
* Obscure features * Obscure features
* Solving problems * Solving problems
* Deprecated features
* Thanks * Thanks
@ -62,56 +60,15 @@ deleted with gme_set_user_cleanup()
Refer to gme.h for a comprehensive summary of features. Refer to gme.h for a comprehensive summary of features.
C and C++ interfaces
--------------------
While the library is written in C++, an extensive C interface is
provided in gme.h. This C interface will be referred to throughout this
documentation unless a feature is only available in the full C++
interface. All C interface functions and other names have the gme_
prefix, so you can recognize a C++-only feature by the lack of gme_ in
the names used (contact me if you'd like a feature added to the C
interface). If you're building a shared library, I highly recommend
sticking to the C interface only, because it will be more stable between
releases of the library than the C++ interface. Finally, the C and C++
interfaces can be freely mixed without problems. Compare demo/basics.c
with demo/cpp_basics.cpp to see how the C and C++ interfaces translate
between each other.
Function reference
------------------
Read the following header files for a complete reference to functions
and features. The second group of header files can only be used in C++.
blargg_config.h Library configuration
gme.h C interface (also usable from C++)
Gme_File.h File loading and track information
Music_Emu.h Track playback and adjustments
Data_Reader.h Custom data readers
Effects_Buffer.h Sound buffer with adjustable stereo echo and panning
M3u_Playlist.h M3U playlist support
Gbs_Emu.h GBS equalizer settings
Nsf_Emu.h NSF equalizer settings
Spc_Emu.h SPC surround disable
Vgm_Emu.h VGM oversampling disable and custom buffer query
Error handling Error handling
-------------- --------------
Functions which can fail have a return type of gme_err_t (blargg_err_t Functions which can fail have a return type of gme_err_t, which is a
in the C++ interfaces), which is a pointer to an error string (const pointer to an error string (const char*). If a function is successful it
char*). If a function is successful it returns NULL. Errors that you can returns NULL. Errors that you can easily avoid are checked with debug
easily avoid are checked with debug assertions; gme_err_t return values assertions; gme_err_t return values are only used for genuine run-time
are only used for genuine run-time errors that can't be easily predicted errors that can't be easily predicted in advance (out of memory, I/O
in advance (out of memory, I/O errors, incompatible file data). Your errors, incompatible file data). Your code should check all error
code should check all error values. values.
To improve usability for C programmers, C++ programmers unfamiliar with
exceptions, and compatibility with older C++ compilers, the library does
*not* throw any C++ exceptions and uses malloc() instead of the standard
operator new. This means that you *must* check for NULL when creating a
library object with the new operator.
When loading a music file in the wrong emulator or trying to load a When loading a music file in the wrong emulator or trying to load a
non-music file, gme_wrong_file_type is returned. You can check for this non-music file, gme_wrong_file_type is returned. You can check for this
@ -154,7 +111,9 @@ If you want to remove support for some music types to reduce your
executable size, edit GME_TYPE_LIST in blargg_config.h. For example, to executable size, edit GME_TYPE_LIST in blargg_config.h. For example, to
support just NSF and GBS, use this: support just NSF and GBS, use this:
#define GME_TYPE_LIST gme_nsf_type, gme_gbs_type #define GME_TYPE_LIST \
gme_nsf_type,\
gme_gbs_type
M3U playlist support M3U playlist support
@ -271,40 +230,6 @@ create an emulator, you can use the following methods of loading:
error = gme_load_custom( emu, my_read, file_size, my_data ); error = gme_load_custom( emu, my_read, file_size, my_data );
* If you must load the file data into memory yourself, you can have the
library use your data directly *without* making a copy. If you do this,
you must not free the data until you're done playing the file.
error = emu->load_mem( pointer, size );
* If you've already read the first bytes of a file (perhaps to determine
the file type) and want to avoid seeking back to the beginning for
performance reasons, use Remaining_Reader:
Std_File_Reader in;
error = in.open( file_path );
char header [4];
error = in.read( &header, sizeof header );
...
Remaining_Reader rem( &header, sizeof header, &in );
error = emu->load( rem );
If you merely need access to a file's header after loading, use the
emulator-specific header() functions, after casting the Music_Emu
pointer to the specific emulator's type. This example examines the
chip_flags field of the header if it's an NSF file:
if ( music_emu->type() == gme_nsf_type )
{
Nsf_Emu* nsf_emu = (Nsf_Emu*) music_emu;
if ( nsf_emu->header().chip_flags & 0x01 )
...
}
Contact me if you want more information about loading files.
Sound parameters Sound parameters
---------------- ----------------
@ -437,21 +362,6 @@ separate threads.
* If all else fails, see if the demos work. * If all else fails, see if the demos work.
Deprecated features
-------------------
The following functions and other features have been deprecated and will
be removed in a future release of the library. Alternatives to the
deprecated features are listed to the right.
Music_Emu::error_count() warning()
load( header, reader ) see "Loading file data" above
Spc_Emu::trailer() track_info()
Spc_Emu::trailer_size()
Gym_Emu::track_length() track_info()
Vgm_Emu::gd3_data() track_info()
Nsfe_Emu::disable_playlist() clear_playlist()
Thanks Thanks
------ ------
Big thanks to Chris Moeller (kode54) for help with library testing and Big thanks to Chris Moeller (kode54) for help with library testing and
@ -461,4 +371,6 @@ Brad Martin's excellent OpenSPC SNES DSP emulator worked well from the
start. Also thanks to Richard Bannister, Mahendra Tallur, Shazz, start. Also thanks to Richard Bannister, Mahendra Tallur, Shazz,
nenolod, theHobbit, Johan Samuelsson, and nes6502 for testing, using, nenolod, theHobbit, Johan Samuelsson, and nes6502 for testing, using,
and giving feedback for the library in their respective game music and giving feedback for the library in their respective game music
players. players. More recently, Lucas Paul and Michael Pyne have helped nudge the
library into a public repository and get its interface more stable for use
in shared libraries.

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Ay_Apu.h" #include "Ay_Apu.h"
@ -123,8 +123,8 @@ void Ay_Apu::write_data_( int addr, int data )
if ( (unsigned) addr >= 14 ) if ( (unsigned) addr >= 14 )
{ {
#ifdef dprintf #ifdef debug_printf
dprintf( "Wrote to I/O port %02X\n", (int) addr ); debug_printf( "Wrote to I/O port %02X\n", (int) addr );
#endif #endif
} }
@ -220,7 +220,7 @@ void Ay_Apu::run_until( blip_time_t final_end_time )
end_time = final_end_time; end_time = final_end_time;
//if ( !(regs [12] | regs [11]) ) //if ( !(regs [12] | regs [11]) )
// dprintf( "Used envelope period 0\n" ); // debug_printf( "Used envelope period 0\n" );
} }
else if ( !volume ) else if ( !volume )
{ {
@ -250,7 +250,7 @@ void Ay_Apu::run_until( blip_time_t final_end_time )
ntime = start_time + old_noise_delay; ntime = start_time + old_noise_delay;
noise_lfsr = old_noise_lfsr; noise_lfsr = old_noise_lfsr;
//if ( (regs [6] & 0x1F) == 0 ) //if ( (regs [6] & 0x1F) == 0 )
// dprintf( "Used noise period 0\n" ); // debug_printf( "Used noise period 0\n" );
} }
// The following efficiently handles several cases (least demanding first): // The following efficiently handles several cases (least demanding first):
@ -299,7 +299,7 @@ void Ay_Apu::run_until( blip_time_t final_end_time )
while ( ntime <= end ) // must advance *past* time to avoid hang while ( ntime <= end ) // must advance *past* time to avoid hang
{ {
int changed = noise_lfsr + 1; int changed = noise_lfsr + 1;
noise_lfsr = ((blargg_ulong)-(blargg_long)(noise_lfsr & 1) & 0x12000) ^ (noise_lfsr >> 1); noise_lfsr = (-(noise_lfsr & 1) & 0x12000) ^ (noise_lfsr >> 1);
if ( changed & 2 ) if ( changed & 2 )
{ {
delta = -delta; delta = -delta;

View file

@ -1,6 +1,6 @@
// AY-3-8910 sound chip emulator // AY-3-8910 sound chip emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef AY_APU_H #ifndef AY_APU_H
#define AY_APU_H #define AY_APU_H
@ -50,7 +50,6 @@ private:
Blip_Buffer* output; Blip_Buffer* output;
} oscs [osc_count]; } oscs [osc_count];
blip_time_t last_time; blip_time_t last_time;
byte latch;
byte regs [reg_count]; byte regs [reg_count];
struct { struct {

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
/* /*
Last validated with zexall 2006.11.21 5:26 PM Last validated with zexall 2006.11.21 5:26 PM
@ -807,6 +807,7 @@ possibly_out_of_time:
case 0xCB: case 0xCB:
unsigned data2; unsigned data2;
data2 = INSTR( 1 ); data2 = INSTR( 1 );
(void) data2; // TODO is this the same as data in all cases?
pc++; pc++;
switch ( data ) switch ( data )
{ {
@ -1047,7 +1048,7 @@ possibly_out_of_time:
blargg_ulong sum = temp + (flags & C01); blargg_ulong sum = temp + (flags & C01);
flags = ~data >> 2 & N02; flags = ~data >> 2 & N02;
if ( flags ) if ( flags )
sum = (blargg_ulong)-(blargg_long)sum; sum = -sum;
sum += rp.hl; sum += rp.hl;
temp ^= rp.hl; temp ^= rp.hl;
temp ^= sum; temp ^= sum;
@ -1252,7 +1253,7 @@ possibly_out_of_time:
case 0x4F: // LD R,A case 0x4F: // LD R,A
SET_R( rg.a ); SET_R( rg.a );
dprintf( "LD R,A not supported\n" ); debug_printf( "LD R,A not supported\n" );
warning = true; warning = true;
goto loop; goto loop;
@ -1262,7 +1263,7 @@ possibly_out_of_time:
case 0x5F: // LD A,R case 0x5F: // LD A,R
rg.a = GET_R(); rg.a = GET_R();
dprintf( "LD A,R not supported\n" ); debug_printf( "LD A,R not supported\n" );
warning = true; warning = true;
ld_ai_common: ld_ai_common:
flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04); flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04);
@ -1285,7 +1286,7 @@ possibly_out_of_time:
goto loop; goto loop;
default: default:
dprintf( "Opcode $ED $%02X not supported\n", data ); debug_printf( "Opcode $ED $%02X not supported\n", data );
warning = true; warning = true;
goto loop; goto loop;
} }
@ -1545,7 +1546,7 @@ possibly_out_of_time:
} }
default: default:
dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); debug_printf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 );
warning = true; warning = true;
goto loop; goto loop;
} }
@ -1634,7 +1635,7 @@ possibly_out_of_time:
} }
default: default:
dprintf( "Unnecessary DD/FD prefix encountered\n" ); debug_printf( "Unnecessary DD/FD prefix encountered\n" );
warning = true; warning = true;
pc--; pc--;
goto loop; goto loop;
@ -1643,7 +1644,7 @@ possibly_out_of_time:
} }
} }
dprintf( "Unhandled main opcode: $%02X\n", opcode ); debug_printf( "Unhandled main opcode: $%02X\n", opcode );
assert( false ); assert( false );
halt: halt:

View file

@ -1,6 +1,6 @@
// Z80 CPU emulator // Z80 CPU emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef AY_CPU_H #ifndef AY_CPU_H
#define AY_CPU_H #define AY_CPU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Ay_Emu.h" #include "Ay_Emu.h"
@ -47,8 +47,8 @@ Ay_Emu::~Ay_Emu() { }
static byte const* get_data( Ay_Emu::file_t const& file, byte const* ptr, int min_size ) static byte const* get_data( Ay_Emu::file_t const& file, byte const* ptr, int min_size )
{ {
long pos = long(ptr - (byte const*) file.header); long pos = ptr - (byte const*) file.header;
long file_size = long(file.end - (byte const*) file.header); long file_size = file.end - (byte const*) file.header;
assert( (unsigned long) pos <= (unsigned long) file_size - 2 ); assert( (unsigned long) pos <= (unsigned long) file_size - 2 );
int offset = (BOOST::int16_t) get_be16( ptr ); int offset = (BOOST::int16_t) get_be16( ptr );
if ( !offset || blargg_ulong (pos + offset) > blargg_ulong (file_size - min_size) ) if ( !offset || blargg_ulong (pos + offset) > blargg_ulong (file_size - min_size) )
@ -207,11 +207,11 @@ blargg_err_t Ay_Emu::start_track_( int track )
if ( len > blargg_ulong (file.end - in) ) if ( len > blargg_ulong (file.end - in) )
{ {
set_warning( "Missing file data" ); set_warning( "Missing file data" );
len = unsigned(file.end - in); len = file.end - in;
} }
//dprintf( "addr: $%04X, len: $%04X\n", addr, len ); //debug_printf( "addr: $%04X, len: $%04X\n", addr, len );
if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data
dprintf( "Block addr in ROM\n" ); debug_printf( "Block addr in ROM\n" );
memcpy( mem.ram + addr, in, len ); memcpy( mem.ram + addr, in, len );
if ( file.end - blocks < 8 ) if ( file.end - blocks < 8 )
@ -242,7 +242,7 @@ blargg_err_t Ay_Emu::start_track_( int track )
}; };
memcpy( mem.ram, passive, sizeof passive ); memcpy( mem.ram, passive, sizeof passive );
unsigned play_addr = get_be16( more_data + 4 ); unsigned play_addr = get_be16( more_data + 4 );
//dprintf( "Play: $%04X\n", play_addr ); //debug_printf( "Play: $%04X\n", play_addr );
if ( play_addr ) if ( play_addr )
{ {
memcpy( mem.ram, active, sizeof active ); memcpy( mem.ram, active, sizeof active );
@ -315,7 +315,7 @@ void Ay_Emu::cpu_out_misc( cpu_time_t time, unsigned addr, int data )
} }
} }
dprintf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); debug_printf( "Unmapped OUT: $%04X <- $%02X\n", addr, data );
return; return;
enable_cpc: enable_cpc:
@ -356,7 +356,7 @@ int ay_cpu_in( Ay_Cpu*, unsigned addr )
if ( (addr & 0xFF) == 0xFE ) if ( (addr & 0xFF) == 0xFE )
return 0xFF; // other values break some beeper tunes return 0xFF; // other values break some beeper tunes
dprintf( "Unmapped IN : $%04X\n", addr ); debug_printf( "Unmapped IN : $%04X\n", addr );
return 0xFF; return 0xFF;
} }

View file

@ -1,6 +1,6 @@
// Sinclair Spectrum AY music file emulator // Sinclair Spectrum AY music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef AY_EMU_H #ifndef AY_EMU_H
#define AY_EMU_H #define AY_EMU_H
@ -46,7 +46,6 @@ protected:
private: private:
file_t file; file_t file;
unsigned play_addr;
cpu_time_t play_period; cpu_time_t play_period;
cpu_time_t next_play; cpu_time_t next_play;
Blip_Buffer* beeper_output; Blip_Buffer* beeper_output;

View file

@ -233,18 +233,32 @@ static void gen_sinc( float* out, int count, double oversample, double treble, d
double const to_angle = PI / 2 / maxh / oversample; double const to_angle = PI / 2 / maxh / oversample;
for ( int i = 0; i < count; i++ ) for ( int i = 0; i < count; i++ )
{ {
double angle = ((i - count) * 2 + 1) * to_angle; double angle = ((i - count) * 2 + 1) * to_angle;
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle ); double angle_maxh = angle * maxh;
double cos_nc_angle = cos( maxh * cutoff * angle ); double angle_maxh_mid = angle_maxh * cutoff;
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; double y = maxh;
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
double b = 2.0 - cos_angle - cos_angle;
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d // 0 to Fs/2*cutoff, flat
if ( angle_maxh_mid ) // unstable at t=0
y *= sin( angle_maxh_mid ) / angle_maxh_mid;
// Fs/2*cutoff to Fs/2, logarithmic rolloff
double cosa = cos( angle );
double den = 1 + rolloff * (rolloff - cosa - cosa);
// Becomes unstable when rolloff is near 1.0 and t is near 0,
// which is the only time den becomes small
if ( den > 1e-13 )
{
double num =
(cos( angle_maxh - angle ) * rolloff - cos( angle_maxh )) * pow_a_n -
cos( angle_maxh_mid - angle ) * rolloff + cos( angle_maxh_mid );
y = y * cutoff + num / den;
}
out [i] = (float) y;
} }
} }

View file

@ -0,0 +1,153 @@
# List of source files required by libgme and any emulators
# This is not 100% accurate (Fir_Resampler for instance) but
# you'll be OK.
set(libgme_SRCS Blip_Buffer.cpp
Classic_Emu.cpp
Data_Reader.cpp
Dual_Resampler.cpp
Effects_Buffer.cpp
Fir_Resampler.cpp
gme.cpp
Gme_File.cpp
M3u_Playlist.cpp
Multi_Buffer.cpp
Music_Emu.cpp
)
# Ay_Apu is very popular around here
if (USE_GME_AY OR USE_GME_KSS)
set(libgme_SRCS ${libgme_SRCS}
Ay_Apu.cpp
)
endif()
# so is Ym2612_Emu
if (USE_GME_VGM OR USE_GME_GYM)
set(libgme_SRCS ${libgme_SRCS}
Ym2612_Emu.cpp
)
endif()
# But none are as popular as Sms_Apu
if (USE_GME_VGM OR USE_GME_GYM OR USE_GME_KSS)
set(libgme_SRCS ${libgme_SRCS}
Sms_Apu.cpp
)
endif()
if (USE_GME_AY)
set(libgme_SRCS ${libgme_SRCS}
# Ay_Apu.cpp included earlier
Ay_Cpu.cpp
Ay_Emu.cpp
)
endif()
if (USE_GME_GBS)
set(libgme_SRCS ${libgme_SRCS}
Gb_Apu.cpp
Gb_Cpu.cpp
Gb_Oscs.cpp
Gbs_Emu.cpp
)
endif()
if (USE_GME_GYM)
set(libgme_SRCS ${libgme_SRCS}
# Sms_Apu.cpp included earlier
# Ym2612_Emu.cpp included earlier
Gym_Emu.cpp
)
endif()
if (USE_GME_HES)
set(libgme_SRCS ${libgme_SRCS}
Hes_Apu.cpp
Hes_Cpu.cpp
Hes_Emu.cpp
)
endif()
if (USE_GME_KSS)
set(libgme_SRCS ${libgme_SRCS}
# Ay_Apu.cpp included earlier
# Sms_Apu.cpp included earlier
Kss_Cpu.cpp
Kss_Emu.cpp
Kss_Scc_Apu.cpp
)
endif()
if (USE_GME_NSF OR USE_GME_NSFE)
set(libgme_SRCS ${libgme_SRCS}
Nes_Apu.cpp
Nes_Cpu.cpp
Nes_Fme7_Apu.cpp
Nes_Namco_Apu.cpp
Nes_Oscs.cpp
Nes_Vrc6_Apu.cpp
Nsf_Emu.cpp
)
endif()
if (USE_GME_NSFE)
set(libgme_SRCS ${libgme_SRCS}
Nsfe_Emu.cpp
)
endif()
if (USE_GME_SAP)
set(libgme_SRCS ${libgme_SRCS}
Sap_Apu.cpp
Sap_Cpu.cpp
Sap_Emu.cpp
)
endif()
if (USE_GME_SPC)
set(libgme_SRCS ${libgme_SRCS}
Snes_Spc.cpp
Spc_Cpu.cpp
Spc_Dsp.cpp
Spc_Emu.cpp
Spc_Filter.cpp
)
endif()
if (USE_GME_VGM)
set(libgme_SRCS ${libgme_SRCS}
# Sms_Apu.cpp included earlier
# Ym2612_Emu.cpp included earlier
Vgm_Emu.cpp
Vgm_Emu_Impl.cpp
Ym2413_Emu.cpp
)
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)
# 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.
add_definitions(-DBLARGG_BUILD_DLL)
# For the gme_types.h
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Add library to be compiled.
add_library(gme ${libgme_SRCS})
# 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.
#set_target_properties(gme
# PROPERTIES VERSION ${GME_VERSION}
# SOVERSION 0)
target_link_libraries(gme)

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Classic_Emu.h" #include "Classic_Emu.h"
@ -176,9 +176,9 @@ void Rom_Data_::set_addr_( long addr, int unit )
if ( 0 ) if ( 0 )
{ {
dprintf( "addr: %X\n", addr ); debug_printf( "addr: %X\n", addr );
dprintf( "file_size: %d\n", file_size_ ); debug_printf( "file_size: %d\n", file_size_ );
dprintf( "rounded: %d\n", rounded ); debug_printf( "rounded: %d\n", rounded );
dprintf( "mask: $%X\n", mask ); debug_printf( "mask: $%X\n", mask );
} }
} }

View file

@ -1,6 +1,6 @@
// Common aspects of emulators which use Blip_Buffer for sound output // Common aspects of emulators which use Blip_Buffer for sound output
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef CLASSIC_EMU_H #ifndef CLASSIC_EMU_H
#define CLASSIC_EMU_H #define CLASSIC_EMU_H

View file

@ -1,15 +1,12 @@
// File_Extractor 0.4.0. http://www.slack.net/~ant/ // File_Extractor 0.4.0. http://www.slack.net/~ant/
#define _CRT_SECURE_NO_WARNINGS
#define IN_GME 1
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "Data_Reader.h" #include "Data_Reader.h"
#include "blargg_endian.h" #include "blargg_endian.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
/* Copyright (C) 2005-2006 Shay Green. This module is free software; you /* Copyright (C) 2005-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either General Public License as published by the Free Software Foundation; either
@ -92,11 +89,11 @@ Remaining_Reader::Remaining_Reader( void const* h, long size, Data_Reader* r )
in = r; in = r;
} }
long Remaining_Reader::remain() const { return long(header_end - header + in->remain()); } long Remaining_Reader::remain() const { return header_end - header + in->remain(); }
long Remaining_Reader::read_first( void* out, long count ) long Remaining_Reader::read_first( void* out, long count )
{ {
long first = long(header_end - header); long first = header_end - header;
if ( first ) if ( first )
{ {
if ( first > count ) if ( first > count )
@ -213,7 +210,7 @@ long Std_File_Reader::size() const
long Std_File_Reader::read_avail( void* p, long s ) long Std_File_Reader::read_avail( void* p, long s )
{ {
return (long)fread( p, 1, s, (FILE*) file_ ); return fread( p, 1, s, (FILE*) file_ );
} }
blargg_err_t Std_File_Reader::read( void* p, long s ) blargg_err_t Std_File_Reader::read( void* p, long s )

View file

@ -5,7 +5,6 @@
#define DATA_READER_H #define DATA_READER_H
#include "blargg_common.h" #include "blargg_common.h"
#include "gme.h"
// Supports reading and finding out how many bytes are remaining // Supports reading and finding out how many bytes are remaining
class Data_Reader { class Data_Reader {
@ -117,7 +116,7 @@ private:
// Invokes callback function to read data. Size of data must be specified in advance. // Invokes callback function to read data. Size of data must be specified in advance.
class Callback_Reader : public Data_Reader { class Callback_Reader : public Data_Reader {
public: public:
typedef const char* (GMEAPI *callback_t)( void* data, void* out, int count ); typedef const char* (*callback_t)( void* data, void* out, int count );
Callback_Reader( callback_t, long size, void* data = 0 ); Callback_Reader( callback_t, long size, void* data = 0 );
public: public:
long read_avail( void*, long ); long read_avail( void*, long );

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Dual_Resampler.h" #include "Dual_Resampler.h"
@ -20,7 +20,13 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
unsigned const resampler_extra = 256; unsigned const resampler_extra = 256;
Dual_Resampler::Dual_Resampler() { } Dual_Resampler::Dual_Resampler() :
sample_buf_size(0),
oversamples_per_frame(-1),
buf_pos(-1),
resampler_size(0)
{
}
Dual_Resampler::~Dual_Resampler() { } Dual_Resampler::~Dual_Resampler() { }
@ -62,10 +68,10 @@ void Dual_Resampler::play_frame_( Blip_Buffer& blip_buf, dsample_t* out )
assert( blip_buf.samples_avail() == pair_count ); assert( blip_buf.samples_avail() == pair_count );
resampler.write( new_count ); resampler.write( new_count );
long count = resampler.read( sample_buf.begin(), sample_buf_size ); long count = resampler.read( sample_buf.begin(), sample_buf_size );
assert( count == (long) sample_buf_size ); assert( count == (long) sample_buf_size );
mix_samples( blip_buf, out ); mix_samples( blip_buf, out );
blip_buf.remove_samples( pair_count ); blip_buf.remove_samples( pair_count );
} }

View file

@ -1,6 +1,6 @@
// Combination of Fir_Resampler and Blip_Buffer mixing. Used by Sega FM emulators. // Combination of Fir_Resampler and Blip_Buffer mixing. Used by Sega FM emulators.
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef DUAL_RESAMPLER_H #ifndef DUAL_RESAMPLER_H
#define DUAL_RESAMPLER_H #define DUAL_RESAMPLER_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Effects_Buffer.h" #include "Effects_Buffer.h"

View file

@ -1,6 +1,6 @@
// Multi-channel effects buffer with panning, echo and reverb // Multi-channel effects buffer with panning, echo and reverb
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef EFFECTS_BUFFER_H #ifndef EFFECTS_BUFFER_H
#define EFFECTS_BUFFER_H #define EFFECTS_BUFFER_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Fir_Resampler.h" #include "Fir_Resampler.h"
@ -156,7 +156,7 @@ int Fir_Resampler_::input_needed( blargg_long output_count ) const
output_count -= 2; output_count -= 2;
} }
long input_extra = long(input_count - (write_pos - &buf [(width_ - 1) * stereo])); long input_extra = input_count - (write_pos - &buf [(width_ - 1) * stereo]);
if ( input_extra < 0 ) if ( input_extra < 0 )
input_extra = 0; input_extra = 0;
return input_extra; return input_extra;
@ -186,7 +186,7 @@ int Fir_Resampler_::avail_( blargg_long input_count ) const
int Fir_Resampler_::skip_input( long count ) int Fir_Resampler_::skip_input( long count )
{ {
int remain = int(write_pos - buf.begin()); int remain = write_pos - buf.begin();
int max_count = remain - width_ * stereo; int max_count = remain - width_ * stereo;
if ( count > max_count ) if ( count > max_count )
count = max_count; count = max_count;

View file

@ -1,6 +1,6 @@
// Finite impulse response (FIR) resampler with adjustable FIR size // Finite impulse response (FIR) resampler with adjustable FIR size
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef FIR_RESAMPLER_H #ifndef FIR_RESAMPLER_H
#define FIR_RESAMPLER_H #define FIR_RESAMPLER_H
@ -31,7 +31,7 @@ public:
void clear(); void clear();
// Number of input samples that can be written // Number of input samples that can be written
int max_write() const { return int(buf.end() - write_pos); } int max_write() const { return buf.end() - write_pos; }
// Pointer to place to write input samples // Pointer to place to write input samples
sample_t* buffer() { return write_pos; } sample_t* buffer() { return write_pos; }
@ -40,7 +40,7 @@ public:
void write( long count ); void write( long count );
// Number of input samples in buffer // Number of input samples in buffer
int written() const { return int(write_pos - &buf [write_offset]); } int written() const { return write_pos - &buf [write_offset]; }
// Skip 'count' input samples. Returns number of samples actually skipped. // Skip 'count' input samples. Returns number of samples actually skipped.
int skip_input( long count ); int skip_input( long count );
@ -51,7 +51,7 @@ public:
int input_needed( blargg_long count ) const; int input_needed( blargg_long count ) const;
// Number of output samples available // Number of output samples available
int avail() const { return avail_( blargg_long(write_pos - &buf [width_ * stereo]) ); } int avail() const { return avail_( write_pos - &buf [width_ * stereo] ); }
public: public:
~Fir_Resampler_(); ~Fir_Resampler_();
@ -161,11 +161,11 @@ int Fir_Resampler<width>::read( sample_t* out_begin, blargg_long count )
imp_phase = res - remain; imp_phase = res - remain;
int left = int(write_pos - in); int left = write_pos - in;
write_pos = &buf [left]; write_pos = &buf [left];
memmove( buf.begin(), in, left * sizeof *in ); memmove( buf.begin(), in, left * sizeof *in );
return int(out - out_begin); return out - out_begin;
} }
#endif #endif

View file

@ -271,7 +271,7 @@ void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data )
} }
else else
{ {
//dprintf( "APU powered on\n" ); //debug_printf( "APU powered on\n" );
} }
} }
} }

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Gb_Cpu.h" #include "Gb_Cpu.h"
@ -89,11 +89,6 @@ unsigned const n_flag = 0x40;
unsigned const h_flag = 0x20; unsigned const h_flag = 0x20;
unsigned const c_flag = 0x10; unsigned const c_flag = 0x10;
#ifdef _MSC_VER
// warning C4101: 'blargg_failed_' : unreferenced local variable
// -- produced by the BOOST_STATIC_ASSERT line below
#pragma warning(disable:4101)
#endif
bool Gb_Cpu::run( blargg_long cycle_count ) bool Gb_Cpu::run( blargg_long cycle_count )
{ {
state_.remain = blargg_ulong (cycle_count + clocks_per_instr) / clocks_per_instr; state_.remain = blargg_ulong (cycle_count + clocks_per_instr) / clocks_per_instr;

View file

@ -1,7 +1,7 @@
// Nintendo Game Boy CPU emulator // Nintendo Game Boy CPU emulator
// Treats every instruction as taking 4 cycles // Treats every instruction as taking 4 cycles
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef GB_CPU_H #ifndef GB_CPU_H
#define GB_CPU_H #define GB_CPU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Gbs_Emu.h" #include "Gbs_Emu.h"
@ -18,8 +18,10 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h" #include "blargg_source.h"
Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = { -47.0, 2000, 0, 0, 0, 0, 0, 0, 0, 0 }; Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq =
Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 300, 0, 0, 0, 0, 0, 0, 0, 0 }; Music_Emu::make_equalizer( -47.0, 2000 );
Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq =
Music_Emu::make_equalizer( 0.0, 300 );
Gbs_Emu::Gbs_Emu() Gbs_Emu::Gbs_Emu()
{ {
@ -39,8 +41,7 @@ Gbs_Emu::Gbs_Emu()
set_max_initial_silence( 21 ); set_max_initial_silence( 21 );
set_gain( 1.2 ); set_gain( 1.2 );
static equalizer_t const eq = { -1.0, 120, 0, 0, 0, 0, 0, 0, 0, 0 }; set_equalizer( make_equalizer( -1.0, 120 ) );
set_equalizer( eq );
} }
Gbs_Emu::~Gbs_Emu() { } Gbs_Emu::~Gbs_Emu() { }
@ -151,7 +152,7 @@ void Gbs_Emu::set_bank( int n )
{ {
// TODO: what is the correct behavior? Current Game & Watch Gallery // TODO: what is the correct behavior? Current Game & Watch Gallery
// rip requires that this have no effect or set to bank 1. // rip requires that this have no effect or set to bank 1.
//dprintf( "Selected ROM bank 0\n" ); //debug_printf( "Selected ROM bank 0\n" );
return; return;
//n = 1; //n = 1;
} }
@ -212,11 +213,11 @@ blargg_err_t Gbs_Emu::start_track_( int track )
for ( int i = 0; i < (int) sizeof sound_data; i++ ) for ( int i = 0; i < (int) sizeof sound_data; i++ )
apu.write_register( 0, i + apu.start_addr, sound_data [i] ); apu.write_register( 0, i + apu.start_addr, sound_data [i] );
cpu::reset( rom.unmapped() );
unsigned load_addr = get_le16( header_.load_addr ); unsigned load_addr = get_le16( header_.load_addr );
cpu::rst_base = load_addr;
rom.set_addr( load_addr ); rom.set_addr( load_addr );
cpu::rst_base = load_addr;
cpu::reset( rom.unmapped() );
cpu::map_code( ram_addr, 0x10000 - ram_addr, ram ); cpu::map_code( ram_addr, 0x10000 - ram_addr, ram );
cpu::map_code( 0, bank_size, rom.at_addr( 0 ) ); cpu::map_code( 0, bank_size, rom.at_addr( 0 ) );
@ -265,13 +266,13 @@ blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int )
} }
else if ( cpu::r.pc > 0xFFFF ) else if ( cpu::r.pc > 0xFFFF )
{ {
dprintf( "PC wrapped around\n" ); debug_printf( "PC wrapped around\n" );
cpu::r.pc &= 0xFFFF; cpu::r.pc &= 0xFFFF;
} }
else else
{ {
set_warning( "Emulation error (illegal/unsupported instruction)" ); set_warning( "Emulation error (illegal/unsupported instruction)" );
dprintf( "Bad opcode $%.2x at $%.4x\n", debug_printf( "Bad opcode $%.2x at $%.4x\n",
(int) *cpu::get_code( cpu::r.pc ), (int) cpu::r.pc ); (int) *cpu::get_code( cpu::r.pc ), (int) cpu::r.pc );
cpu::r.pc = (cpu::r.pc + 1) & 0xFFFF; cpu::r.pc = (cpu::r.pc + 1) & 0xFFFF;
cpu_time += 6; cpu_time += 6;

View file

@ -1,6 +1,6 @@
// Nintendo Game Boy GBS music file emulator // Nintendo Game Boy GBS music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef GBS_EMU_H #ifndef GBS_EMU_H
#define GBS_EMU_H #define GBS_EMU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Gme_File.h" #include "Gme_File.h"
@ -60,8 +60,8 @@ blargg_err_t Gme_File::load_mem_( byte const* data, long size )
blargg_err_t Gme_File::load_( Data_Reader& in ) blargg_err_t Gme_File::load_( Data_Reader& in )
{ {
RETURN_ERR( file_data.resize( in.remain() ) ); RETURN_ERR( file_data.resize( in.remain() ) );
RETURN_ERR( in.read( file_data.begin(), (long)file_data.size() ) ); RETURN_ERR( in.read( file_data.begin(), file_data.size() ) );
return load_mem_( file_data.begin(), (long)file_data.size() ); return load_mem_( file_data.begin(), file_data.size() );
} }
// public load functions call this at beginning // public load functions call this at beginning

View file

@ -1,6 +1,6 @@
// Common interface to game music file loading and information // Common interface to game music file loading and information
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef GME_FILE_H #ifndef GME_FILE_H
#define GME_FILE_H #define GME_FILE_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Gym_Emu.h" #include "Gym_Emu.h"

View file

@ -1,7 +1,7 @@
// Sega Genesis/Mega Drive GYM music file emulator // Sega Genesis/Mega Drive GYM music file emulator
// Includes with PCM timing recovery to improve sample quality. // Includes with PCM timing recovery to improve sample quality.
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef GYM_EMU_H #ifndef GYM_EMU_H
#define GYM_EMU_H #define GYM_EMU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Hes_Apu.h" #include "Hes_Apu.h"
@ -106,10 +106,10 @@ void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time )
unsigned noise_lfsr = this->noise_lfsr; unsigned noise_lfsr = this->noise_lfsr;
do do
{ {
int new_dac = 0x1F & (unsigned)-(signed)(noise_lfsr >> 1 & 1); int new_dac = 0x1F & -(noise_lfsr >> 1 & 1);
// Implemented using "Galios configuration" // Implemented using "Galios configuration"
// TODO: find correct LFSR algorithm // TODO: find correct LFSR algorithm
noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & (unsigned)-(signed)(noise_lfsr & 1)); noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1));
//noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1)); //noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
int delta = new_dac - dac; int delta = new_dac - dac;
if ( delta ) if ( delta )
@ -158,7 +158,7 @@ void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time )
//period = 0x1000 * 2; //period = 0x1000 * 2;
period = 1; period = 1;
//if ( !(volume_0 | volume_1) ) //if ( !(volume_0 | volume_1) )
// dprintf( "Used period 0\n" ); // debug_printf( "Used period 0\n" );
} }
// maintain phase when silent // maintain phase when silent
@ -295,7 +295,7 @@ void Hes_Apu::write_data( blip_time_t time, int addr, int data )
case 0x809: case 0x809:
if ( !(data & 0x80) && (data & 0x03) != 0 ) if ( !(data & 0x80) && (data & 0x03) != 0 )
dprintf( "HES LFO not supported\n" ); debug_printf( "HES LFO not supported\n" );
} }
} }
} }

View file

@ -1,6 +1,6 @@
// Turbo Grafx 16 (PC Engine) PSG sound chip emulator // Turbo Grafx 16 (PC Engine) PSG sound chip emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef HES_APU_H #ifndef HES_APU_H
#define HES_APU_H #define HES_APU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Hes_Cpu.h" #include "Hes_Cpu.h"
@ -148,7 +148,7 @@ loop:
/* /*
static long count; static long count;
if ( count == 1844 ) Debugger(); if ( count == 1844 ) Debugger();
if ( s.base != correct ) dprintf( "%ld\n", count ); if ( s.base != correct ) debug_printf( "%ld\n", count );
count++; count++;
*/ */
} }
@ -741,7 +741,7 @@ possibly_out_of_time:
ARITH_ADDR_MODES( 0x65 ) // ADC ARITH_ADDR_MODES( 0x65 ) // ADC
adc_imm: { adc_imm: {
if ( status & st_d ) if ( status & st_d )
dprintf( "Decimal mode not supported\n" ); debug_printf( "Decimal mode not supported\n" );
fint16 carry = c >> 8 & 1; fint16 carry = c >> 8 & 1;
fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend fint16 ov = (a ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend
status &= ~st_v; status &= ~st_v;
@ -1085,7 +1085,7 @@ possibly_out_of_time:
goto loop; goto loop;
} }
delayed_cli: delayed_cli:
dprintf( "Delayed CLI not supported\n" ); // TODO: implement debug_printf( "Delayed CLI not supported\n" ); // TODO: implement
goto loop; goto loop;
} }
@ -1100,7 +1100,7 @@ possibly_out_of_time:
s_time += delta; s_time += delta;
if ( s_time < 0 ) if ( s_time < 0 )
goto loop; goto loop;
dprintf( "Delayed SEI not supported\n" ); // TODO: implement debug_printf( "Delayed SEI not supported\n" ); // TODO: implement
goto loop; goto loop;
} }
@ -1145,7 +1145,7 @@ possibly_out_of_time:
goto loop; goto loop;
case 0x54: // CSL case 0x54: // CSL
dprintf( "CSL not supported\n" ); debug_printf( "CSL not supported\n" );
illegal_encountered = true; illegal_encountered = true;
goto loop; goto loop;
@ -1154,7 +1154,7 @@ possibly_out_of_time:
case 0xF4: { // SET case 0xF4: { // SET
//fuint16 operand = GET_MSB(); //fuint16 operand = GET_MSB();
dprintf( "SET not handled\n" ); debug_printf( "SET not handled\n" );
//switch ( data ) //switch ( data )
//{ //{
//} //}
@ -1233,7 +1233,7 @@ possibly_out_of_time:
default: default:
assert( (unsigned) opcode <= 0xFF ); assert( (unsigned) opcode <= 0xFF );
dprintf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 ); debug_printf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 );
illegal_encountered = true; illegal_encountered = true;
goto loop; goto loop;
} }

View file

@ -1,6 +1,6 @@
// PC Engine CPU emulator for use with HES music files // PC Engine CPU emulator for use with HES music files
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef HES_CPU_H #ifndef HES_CPU_H
#define HES_CPU_H #define HES_CPU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Hes_Emu.h" #include "Hes_Emu.h"
@ -273,12 +273,12 @@ void Hes_Emu::cpu_write_vdp( int addr, int data )
} }
else else
{ {
dprintf( "VDP not supported: $%02X <- $%02X\n", vdp.latch, data ); debug_printf( "VDP not supported: $%02X <- $%02X\n", vdp.latch, data );
} }
break; break;
case 3: case 3:
dprintf( "VDP MSB not supported: $%02X <- $%02X\n", vdp.latch, data ); debug_printf( "VDP MSB not supported: $%02X <- $%02X\n", vdp.latch, data );
break; break;
} }
} }
@ -325,7 +325,7 @@ void Hes_Emu::cpu_write_( hes_addr_t addr, int data )
run_until( time ); run_until( time );
irq.disables = data; irq.disables = data;
if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) // flag questionable values if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) // flag questionable values
dprintf( "Int mask: $%02X\n", data ); debug_printf( "Int mask: $%02X\n", data );
break; break;
case 0x1403: case 0x1403:
@ -344,7 +344,7 @@ void Hes_Emu::cpu_write_( hes_addr_t addr, int data )
return; return;
default: default:
dprintf( "unmapped write $%04X <- $%02X\n", addr, data ); debug_printf( "unmapped write $%04X <- $%02X\n", addr, data );
return; return;
#endif #endif
} }
@ -368,14 +368,14 @@ int Hes_Emu::cpu_read_( hes_addr_t addr )
case 0x0002: case 0x0002:
case 0x0003: case 0x0003:
dprintf( "VDP read not supported: %d\n", addr ); debug_printf( "VDP read not supported: %d\n", addr );
return 0; return 0;
case 0x0C01: case 0x0C01:
//return timer.enabled; // TODO: remove? //return timer.enabled; // TODO: remove?
case 0x0C00: case 0x0C00:
run_until( time ); run_until( time );
dprintf( "Timer count read\n" ); debug_printf( "Timer count read\n" );
return (unsigned) (timer.count - 1) / timer_base; return (unsigned) (timer.count - 1) / timer_base;
case 0x1402: case 0x1402:
@ -396,7 +396,7 @@ int Hes_Emu::cpu_read_( hes_addr_t addr )
break; break;
default: default:
dprintf( "unmapped read $%04X\n", addr ); debug_printf( "unmapped read $%04X\n", addr );
#endif #endif
} }

View file

@ -1,6 +1,6 @@
// TurboGrafx-16/PC Engine HES music file emulator // TurboGrafx-16/PC Engine HES music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef HES_EMU_H #ifndef HES_EMU_H
#define HES_EMU_H #define HES_EMU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
/* /*
Last validated with zexall 2006.11.14 2:19 PM Last validated with zexall 2006.11.14 2:19 PM
@ -841,6 +841,7 @@ possibly_out_of_time:
case 0xCB: case 0xCB:
unsigned data2; unsigned data2;
data2 = instr [1]; data2 = instr [1];
(void) data2; // TODO is this the same as data in all cases?
pc++; pc++;
switch ( data ) switch ( data )
{ {
@ -1084,7 +1085,7 @@ possibly_out_of_time:
blargg_ulong sum = temp + (flags & C01); blargg_ulong sum = temp + (flags & C01);
flags = ~data >> 2 & N02; flags = ~data >> 2 & N02;
if ( flags ) if ( flags )
sum = (blargg_ulong)-(blargg_long)sum; sum = -sum;
sum += rp.hl; sum += rp.hl;
temp ^= rp.hl; temp ^= rp.hl;
temp ^= sum; temp ^= sum;
@ -1289,7 +1290,7 @@ possibly_out_of_time:
case 0x4F: // LD R,A case 0x4F: // LD R,A
SET_R( rg.a ); SET_R( rg.a );
dprintf( "LD R,A not supported\n" ); debug_printf( "LD R,A not supported\n" );
warning = true; warning = true;
goto loop; goto loop;
@ -1299,7 +1300,7 @@ possibly_out_of_time:
case 0x5F: // LD A,R case 0x5F: // LD A,R
rg.a = GET_R(); rg.a = GET_R();
dprintf( "LD A,R not supported\n" ); debug_printf( "LD A,R not supported\n" );
warning = true; warning = true;
ld_ai_common: ld_ai_common:
flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04); flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04);
@ -1322,7 +1323,7 @@ possibly_out_of_time:
goto loop; goto loop;
default: default:
dprintf( "Opcode $ED $%02X not supported\n", data ); debug_printf( "Opcode $ED $%02X not supported\n", data );
warning = true; warning = true;
goto loop; goto loop;
} }
@ -1583,7 +1584,7 @@ possibly_out_of_time:
} }
default: default:
dprintf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); debug_printf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 );
warning = true; warning = true;
goto loop; goto loop;
} }
@ -1672,7 +1673,7 @@ possibly_out_of_time:
} }
default: default:
dprintf( "Unnecessary DD/FD prefix encountered\n" ); debug_printf( "Unnecessary DD/FD prefix encountered\n" );
warning = true; warning = true;
pc--; pc--;
goto loop; goto loop;
@ -1681,7 +1682,7 @@ possibly_out_of_time:
} }
} }
dprintf( "Unhandled main opcode: $%02X\n", opcode ); debug_printf( "Unhandled main opcode: $%02X\n", opcode );
assert( false ); assert( false );
hit_idle_addr: hit_idle_addr:

View file

@ -1,6 +1,6 @@
// Z80 CPU emulator // Z80 CPU emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef KSS_CPU_H #ifndef KSS_CPU_H
#define KSS_CPU_H #define KSS_CPU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Kss_Emu.h" #include "Kss_Emu.h"
@ -230,9 +230,9 @@ blargg_err_t Kss_Emu::start_track_( int track )
bank_count = max_banks; bank_count = max_banks;
set_warning( "Bank data missing" ); set_warning( "Bank data missing" );
} }
//dprintf( "load_size : $%X\n", load_size ); //debug_printf( "load_size : $%X\n", load_size );
//dprintf( "bank_size : $%X\n", bank_size ); //debug_printf( "bank_size : $%X\n", bank_size );
//dprintf( "bank_count: %d (%d claimed)\n", bank_count, header_.bank_mode & 0x7F ); //debug_printf( "bank_count: %d (%d claimed)\n", bank_count, header_.bank_mode & 0x7F );
ram [idle_addr] = 0xFF; ram [idle_addr] = 0xFF;
cpu::reset( unmapped_write, unmapped_read ); cpu::reset( unmapped_write, unmapped_read );
@ -301,7 +301,7 @@ void Kss_Emu::cpu_write( unsigned addr, int data )
return; return;
} }
dprintf( "LD ($%04X),$%02X\n", addr, data ); debug_printf( "LD ($%04X),$%02X\n", addr, data );
} }
void kss_cpu_write( Kss_Cpu* cpu, unsigned addr, int data ) void kss_cpu_write( Kss_Cpu* cpu, unsigned addr, int data )
@ -358,7 +358,7 @@ void kss_cpu_out( Kss_Cpu* cpu, cpu_time_t time, unsigned addr, int data )
#endif #endif
} }
dprintf( "OUT $%04X,$%02X\n", addr, data ); debug_printf( "OUT $%04X,$%02X\n", addr, data );
} }
int kss_cpu_in( Kss_Cpu*, cpu_time_t, unsigned addr ) int kss_cpu_in( Kss_Cpu*, cpu_time_t, unsigned addr )
@ -368,7 +368,7 @@ int kss_cpu_in( Kss_Cpu*, cpu_time_t, unsigned addr )
//{ //{
//} //}
dprintf( "IN $%04X\n", addr ); debug_printf( "IN $%04X\n", addr );
return 0; return 0;
} }

View file

@ -1,6 +1,6 @@
// MSX computer KSS music file emulator // MSX computer KSS music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef KSS_EMU_H #ifndef KSS_EMU_H
#define KSS_EMU_H #define KSS_EMU_H
@ -68,7 +68,6 @@ private:
void update_gain(); void update_gain();
unsigned scc_enabled; // 0 or 0xC000 unsigned scc_enabled; // 0 or 0xC000
byte const* bank_data;
int bank_count; int bank_count;
void set_bank( int logical, int physical ); void set_bank( int logical, int physical );
blargg_long bank_size() const { return (16 * 1024L) >> (header_.bank_mode >> 7 & 1); } blargg_long bank_size() const { return (16 * 1024L) >> (header_.bank_mode >> 7 & 1); }

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Kss_Scc_Apu.h" #include "Kss_Scc_Apu.h"

View file

@ -1,6 +1,6 @@
// Konami SCC sound chip emulator // Konami SCC sound chip emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef KSS_SCC_APU_H #ifndef KSS_SCC_APU_H
#define KSS_SCC_APU_H #define KSS_SCC_APU_H

View file

@ -1,6 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#define IN_GME 1
#include "M3u_Playlist.h" #include "M3u_Playlist.h"
#include "Music_Emu.h" #include "Music_Emu.h"
@ -54,9 +52,9 @@ blargg_err_t Gme_File::load_m3u( const char* path ) { return load_m3u_( playlist
blargg_err_t Gme_File::load_m3u( Data_Reader& in ) { return load_m3u_( playlist.load( in ) ); } blargg_err_t Gme_File::load_m3u( Data_Reader& in ) { return load_m3u_( playlist.load( in ) ); }
gme_err_t GMEAPI gme_load_m3u( Music_Emu* me, const char* path ) { return me->load_m3u( path ); } BLARGG_EXPORT gme_err_t gme_load_m3u( Music_Emu* me, const char* path ) { return me->load_m3u( path ); }
gme_err_t GMEAPI gme_load_m3u_data( Music_Emu* me, const void* data, long size ) BLARGG_EXPORT gme_err_t gme_load_m3u_data( Music_Emu* me, const void* data, long size )
{ {
Mem_File_Reader in( data, size ); Mem_File_Reader in( data, size );
return me->load_m3u( in ); return me->load_m3u( in );
@ -409,7 +407,7 @@ blargg_err_t M3u_Playlist::parse()
blargg_err_t M3u_Playlist::load( Data_Reader& in ) blargg_err_t M3u_Playlist::load( Data_Reader& in )
{ {
RETURN_ERR( data.resize( in.remain() + 1 ) ); RETURN_ERR( data.resize( in.remain() + 1 ) );
RETURN_ERR( in.read( data.begin(), long(data.size() - 1) ) ); RETURN_ERR( in.read( data.begin(), data.size() - 1 ) );
return parse(); return parse();
} }

View file

@ -1,6 +1,6 @@
// M3U playlist file parser, with support for subtrack information // M3U playlist file parser, with support for subtrack information
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef M3U_PLAYLIST_H #ifndef M3U_PLAYLIST_H
#define M3U_PLAYLIST_H #define M3U_PLAYLIST_H
@ -43,7 +43,7 @@ public:
int repeat; // count int repeat; // count
}; };
entry_t const& operator [] ( int i ) const { return entries [i]; } entry_t const& operator [] ( int i ) const { return entries [i]; }
int size() const { return (int)entries.size(); } int size() const { return entries.size(); }
void clear(); void clear();

View file

@ -114,7 +114,7 @@ long Stereo_Buffer::read_samples( blip_sample_t* out, long count )
if ( count ) if ( count )
{ {
int bufs_used = stereo_added | was_stereo; int bufs_used = stereo_added | was_stereo;
//dprintf( "%X\n", bufs_used ); //debug_printf( "%X\n", bufs_used );
if ( bufs_used <= 1 ) if ( bufs_used <= 1 )
{ {
mix_mono( out, count ); mix_mono( out, count );

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Music_Emu.h" #include "Music_Emu.h"
@ -24,7 +24,8 @@ int const silence_threshold = 0x10;
long const fade_block_size = 512; long const fade_block_size = 512;
int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift)
Music_Emu::equalizer_t const Music_Emu::tv_eq = { -8.0, 180, 0, 0, 0, 0, 0, 0, 0, 0 }; Music_Emu::equalizer_t const Music_Emu::tv_eq =
Music_Emu::make_equalizer( -8.0, 180 );
void Music_Emu::clear_track_vars() void Music_Emu::clear_track_vars()
{ {
@ -305,7 +306,7 @@ static long count_silence( Music_Emu::sample_t* begin, long size )
Music_Emu::sample_t* p = begin + size; Music_Emu::sample_t* p = begin + size;
while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { }
*begin = first; *begin = first;
return size - long(p - begin); return size - (p - begin);
} }
// fill internal buffer and check it for silence // fill internal buffer and check it for silence
@ -340,14 +341,14 @@ blargg_err_t Music_Emu::play( long out_count, sample_t* out )
assert( emu_time >= out_time ); assert( emu_time >= out_time );
// prints nifty graph of how far ahead we are when searching for silence // prints nifty graph of how far ahead we are when searching for silence
//dprintf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" );
long pos = 0; long pos = 0;
if ( silence_count ) if ( silence_count )
{ {
// during a run of silence, run emulator at >=2x speed so it gets ahead // during a run of silence, run emulator at >=2x speed so it gets ahead
long ahead_time = silence_lookahead * (out_time + out_count - silence_time) + silence_time; long ahead_time = silence_lookahead * (out_time + out_count - silence_time) + silence_time;
while ( emu_time < ahead_time && !(buf_remain || emu_track_ended_) ) while ( emu_time < ahead_time && !(buf_remain | emu_track_ended_) )
fill_buf(); fill_buf();
// fill with silence // fill with silence
@ -404,6 +405,7 @@ blargg_err_t Gme_Info_::set_sample_rate_( long ) { return 0; }
void Gme_Info_::pre_load() { Gme_File::pre_load(); } // skip Music_Emu void Gme_Info_::pre_load() { Gme_File::pre_load(); } // skip Music_Emu
void Gme_Info_::post_load_() { Gme_File::post_load_(); } // skip Music_Emu void Gme_Info_::post_load_() { Gme_File::post_load_(); } // skip Music_Emu
void Gme_Info_::set_equalizer_( equalizer_t const& ){ check( false ); } void Gme_Info_::set_equalizer_( equalizer_t const& ){ check( false ); }
void Gme_Info_::enable_accuracy_( bool ) { check( false ); }
void Gme_Info_::mute_voices_( int ) { check( false ); } void Gme_Info_::mute_voices_( int ) { check( false ); }
void Gme_Info_::set_tempo_( double ) { } void Gme_Info_::set_tempo_( double ) { }
blargg_err_t Gme_Info_::start_track_( int ) { return "Use full emulator for playback"; } blargg_err_t Gme_Info_::start_track_( int ) { return "Use full emulator for playback"; }

View file

@ -1,6 +1,6 @@
// Common interface to game music file emulators // Common interface to game music file emulators
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef MUSIC_EMU_H #ifndef MUSIC_EMU_H
#define MUSIC_EMU_H #define MUSIC_EMU_H
@ -82,6 +82,10 @@ public:
// on others this has no effect. Should be called only once *before* set_sample_rate(). // on others this has no effect. Should be called only once *before* set_sample_rate().
virtual void set_buffer( Multi_Buffer* ) { } virtual void set_buffer( Multi_Buffer* ) { }
// Enables/disables accurate emulation options, if any are supported. Might change
// equalizer settings.
void enable_accuracy( bool enable = true );
// Sound equalization (treble/bass) // Sound equalization (treble/bass)
// Frequency equalizer parameters (see gme.txt) // Frequency equalizer parameters (see gme.txt)
@ -93,6 +97,14 @@ public:
// Set frequency equalizer parameters // Set frequency equalizer parameters
void set_equalizer( equalizer_t const& ); void set_equalizer( equalizer_t const& );
// Construct equalizer of given treble/bass settings
static const equalizer_t make_equalizer( double treble, double bass )
{
const Music_Emu::equalizer_t e = { treble, bass,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
return e;
}
// Equalizer settings for TV speaker // Equalizer settings for TV speaker
static equalizer_t const tv_eq; static equalizer_t const tv_eq;
@ -111,7 +123,8 @@ protected:
void remute_voices(); void remute_voices();
virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0; virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
virtual void set_equalizer_( equalizer_t const& ) { }; virtual void set_equalizer_( equalizer_t const& ) { }
virtual void enable_accuracy_( bool /* enable */ ) { }
virtual void mute_voices_( int mask ) = 0; virtual void mute_voices_( int mask ) = 0;
virtual void set_tempo_( double ) = 0; virtual void set_tempo_( double ) = 0;
virtual blargg_err_t start_track_( int ) = 0; // tempo is set before this virtual blargg_err_t start_track_( int ) = 0; // tempo is set before this
@ -160,8 +173,8 @@ private:
void emu_play( long count, sample_t* out ); void emu_play( long count, sample_t* out );
Multi_Buffer* effects_buffer; Multi_Buffer* effects_buffer;
friend GMEDLL Music_Emu* GMEAPI gme_new_emu( gme_type_t, int ); friend Music_Emu* gme_new_emu( gme_type_t, int );
friend GMEDLL void GMEAPI gme_set_stereo_depth( Music_Emu*, double ); friend void gme_set_stereo_depth( Music_Emu*, double );
}; };
// base class for info-only derivations // base class for info-only derivations
@ -169,6 +182,7 @@ struct Gme_Info_ : Music_Emu
{ {
virtual blargg_err_t set_sample_rate_( long sample_rate ); virtual blargg_err_t set_sample_rate_( long sample_rate );
virtual void set_equalizer_( equalizer_t const& ); virtual void set_equalizer_( equalizer_t const& );
virtual void enable_accuracy_( bool );
virtual void mute_voices_( int mask ); virtual void mute_voices_( int mask );
virtual void set_tempo_( double ); virtual void set_tempo_( double );
virtual blargg_err_t start_track_( int ); virtual blargg_err_t start_track_( int );
@ -189,6 +203,7 @@ inline int Music_Emu::current_track() const { return current_track_; }
inline bool Music_Emu::track_ended() const { return track_ended_; } inline bool Music_Emu::track_ended() const { return track_ended_; }
inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; } inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; }
inline void Music_Emu::enable_accuracy( bool b ) { enable_accuracy_( b ); }
inline void Music_Emu::set_tempo_( double t ) { tempo_ = t; } inline void Music_Emu::set_tempo_( double t ) { tempo_ = t; }
inline void Music_Emu::remute_voices() { mute_voices( mute_mask_ ); } inline void Music_Emu::remute_voices() { mute_voices( mute_mask_ ); }
inline void Music_Emu::ignore_silence( bool b ) { ignore_silence_ = b; } inline void Music_Emu::ignore_silence( bool b ) { ignore_silence_ = b; }

View file

@ -385,7 +385,7 @@ int Nes_Apu::read_status( nes_time_t time )
irq_changed(); irq_changed();
} }
//dprintf( "%6d/%d Read $4015->$%02X\n", frame_delay, frame, result ); //debug_printf( "%6d/%d Read $4015->$%02X\n", frame_delay, frame, result );
return result; return result;
} }

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Nes_Cpu.h" #include "Nes_Cpu.h"
@ -921,7 +921,7 @@ imm##op:
goto loop; goto loop;
status &= ~st_i; status &= ~st_i;
handle_cli: { handle_cli: {
//dprintf( "CLI at %d\n", TIME ); //debug_printf( "CLI at %d\n", TIME );
this->r.status = status; // update externally-visible I flag this->r.status = status; // update externally-visible I flag
blargg_long delta = s.base - irq_time_; blargg_long delta = s.base - irq_time_;
if ( delta <= 0 ) if ( delta <= 0 )
@ -944,7 +944,7 @@ imm##op:
// TODO: implement // TODO: implement
delayed_cli: delayed_cli:
dprintf( "Delayed CLI not emulated\n" ); debug_printf( "Delayed CLI not emulated\n" );
goto loop; goto loop;
} }
@ -960,7 +960,7 @@ imm##op:
if ( s_time < 0 ) if ( s_time < 0 )
goto loop; goto loop;
dprintf( "Delayed SEI not emulated\n" ); debug_printf( "Delayed SEI not emulated\n" );
goto loop; goto loop;
} }

View file

@ -1,6 +1,6 @@
// NES 6502 CPU emulator // NES 6502 CPU emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef NES_CPU_H #ifndef NES_CPU_H
#define NES_CPU_H #define NES_CPU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Nes_Fme7_Apu.h" #include "Nes_Fme7_Apu.h"
@ -56,7 +56,7 @@ void Nes_Fme7_Apu::run_until( blip_time_t end_time )
// check for unsupported mode // check for unsupported mode
#ifndef NDEBUG #ifndef NDEBUG
if ( (mode & 011) <= 001 && vol_mode & 0x1F ) if ( (mode & 011) <= 001 && vol_mode & 0x1F )
dprintf( "FME7 used unimplemented sound mode: %02X, vol_mode: %02X\n", debug_printf( "FME7 used unimplemented sound mode: %02X, vol_mode: %02X\n",
mode, vol_mode & 0x1F ); mode, vol_mode & 0x1F );
#endif #endif

View file

@ -1,6 +1,6 @@
// Sunsoft FME-7 sound emulator // Sunsoft FME-7 sound emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef NES_FME7_APU_H #ifndef NES_FME7_APU_H
#define NES_FME7_APU_H #define NES_FME7_APU_H
@ -97,8 +97,8 @@ inline void Nes_Fme7_Apu::write_data( blip_time_t time, int data )
{ {
if ( (unsigned) latch >= reg_count ) if ( (unsigned) latch >= reg_count )
{ {
#ifdef dprintf #ifdef debug_printf
dprintf( "FME7 write to %02X (past end of sound registers)\n", (int) latch ); debug_printf( "FME7 write to %02X (past end of sound registers)\n", (int) latch );
#endif #endif
return; return;
} }

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Nsf_Emu.h" #include "Nsf_Emu.h"
@ -31,8 +31,10 @@ int const fme7_flag = 0x20;
long const clock_divisor = 12; long const clock_divisor = 12;
Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq = { -1.0, 80, 0, 0, 0, 0, 0, 0, 0, 0 }; Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq =
Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq = { -15.0, 80, 0, 0, 0, 0, 0, 0, 0, 0 }; Music_Emu::make_equalizer( -1.0, 80 );
Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq =
Music_Emu::make_equalizer( -15.0, 80 );
int Nsf_Emu::pcm_read( void* emu, nes_addr_t addr ) int Nsf_Emu::pcm_read( void* emu, nes_addr_t addr )
{ {
@ -442,7 +444,7 @@ void Nsf_Emu::cpu_write_misc( nes_addr_t addr, int data )
// memory mapper? // memory mapper?
if ( addr == 0xFFF8 ) return; if ( addr == 0xFFF8 ) return;
dprintf( "write_unmapped( 0x%04X, 0x%02X )\n", (unsigned) addr, (unsigned) data ); debug_printf( "write_unmapped( 0x%04X, 0x%02X )\n", (unsigned) addr, (unsigned) data );
} }
#endif #endif
} }

View file

@ -1,6 +1,6 @@
// Nintendo NES/Famicom NSF music file emulator // Nintendo NES/Famicom NSF music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef NSF_EMU_H #ifndef NSF_EMU_H
#define NSF_EMU_H #define NSF_EMU_H

View file

@ -1,6 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#define _CRT_SECURE_NO_WARNINGS
#include "Nsfe_Emu.h" #include "Nsfe_Emu.h"
@ -37,7 +35,7 @@ inline void Nsfe_Info::unload()
void Nsfe_Info::disable_playlist( bool b ) void Nsfe_Info::disable_playlist( bool b )
{ {
playlist_disabled = b; playlist_disabled = b;
info.track_count = (byte)playlist.size(); info.track_count = playlist.size();
if ( !info.track_count || playlist_disabled ) if ( !info.track_count || playlist_disabled )
info.track_count = actual_track_count_; info.track_count = actual_track_count_;
} }
@ -137,7 +135,7 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
blargg_long size = get_le32( block_header [0] ); blargg_long size = get_le32( block_header [0] );
blargg_long tag = get_le32( block_header [1] ); blargg_long tag = get_le32( block_header [1] );
//dprintf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) ); //debug_printf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) );
switch ( tag ) switch ( tag )
{ {
@ -173,7 +171,7 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
blargg_vector<char> chars; blargg_vector<char> chars;
blargg_vector<const char*> strs; blargg_vector<const char*> strs;
RETURN_ERR( read_strs( in, size, chars, strs ) ); RETURN_ERR( read_strs( in, size, chars, strs ) );
int n = (int)strs.size(); int n = strs.size();
if ( n > 3 ) if ( n > 3 )
copy_str( strs [3], info.dumper, sizeof info.dumper ); copy_str( strs [3], info.dumper, sizeof info.dumper );
@ -192,7 +190,7 @@ blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu )
case BLARGG_4CHAR('e','m','i','t'): case BLARGG_4CHAR('e','m','i','t'):
RETURN_ERR( track_times.resize( size / 4 ) ); RETURN_ERR( track_times.resize( size / 4 ) );
RETURN_ERR( in.read( track_times.begin(), (long)track_times.size() * 4 ) ); RETURN_ERR( in.read( track_times.begin(), track_times.size() * 4 ) );
break; break;
case BLARGG_4CHAR('l','b','l','t'): case BLARGG_4CHAR('l','b','l','t'):

View file

@ -1,6 +1,6 @@
// Nintendo NES/Famicom NSFE music file emulator // Nintendo NES/Famicom NSFE music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef NSFE_EMU_H #ifndef NSFE_EMU_H
#define NSFE_EMU_H #define NSFE_EMU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Sap_Apu.h" #include "Sap_Apu.h"
@ -30,7 +30,7 @@ static void gen_poly( blargg_ulong mask, int count, byte* out )
{ {
// implemented using "Galios configuration" // implemented using "Galios configuration"
bits |= (n & 1) << b; bits |= (n & 1) << b;
n = (n >> 1) ^ (mask & (blargg_ulong)-(blargg_long)(n & 1)); n = (n >> 1) ^ (mask & -(n & 1));
} }
while ( b++ < 7 ); while ( b++ < 7 );
*out++ = bits; *out++ = bits;
@ -66,7 +66,7 @@ Sap_Apu_Impl::Sap_Apu_Impl()
blargg_ulong rev = n & 1; blargg_ulong rev = n & 1;
for ( int i = 1; i < poly5_len; i++ ) for ( int i = 1; i < poly5_len; i++ )
rev |= (n >> i & 1) << (poly5_len - i); rev |= (n >> i & 1) << (poly5_len - i);
dprintf( "poly5: 0x%08lX\n", rev ); debug_printf( "poly5: 0x%08lX\n", rev );
} }
} }
@ -114,7 +114,7 @@ inline void Sap_Apu::calc_periods()
period = (period - 6) * divider; period = (period - 6) * divider;
if ( (osc [-1].regs [1] & 0x1F) > 0x10 ) if ( (osc [-1].regs [1] & 0x1F) > 0x10 )
dprintf( "Use of slave channel in 16-bit mode not supported\n" ); debug_printf( "Use of slave channel in 16-bit mode not supported\n" );
} }
} }
osc->period = period; osc->period = period;

View file

@ -1,6 +1,6 @@
// Atari POKEY sound chip emulator // Atari POKEY sound chip emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef SAP_APU_H #ifndef SAP_APU_H
#define SAP_APU_H #define SAP_APU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Sap_Cpu.h" #include "Sap_Cpu.h"
@ -889,7 +889,7 @@ imm##op:
goto loop; goto loop;
} }
delayed_cli: delayed_cli:
dprintf( "Delayed CLI not emulated\n" ); debug_printf( "Delayed CLI not emulated\n" );
goto loop; goto loop;
} }
@ -904,7 +904,7 @@ imm##op:
s_time += delta; s_time += delta;
if ( s_time < 0 ) if ( s_time < 0 )
goto loop; goto loop;
dprintf( "Delayed SEI not emulated\n" ); debug_printf( "Delayed SEI not emulated\n" );
goto loop; goto loop;
} }
@ -945,7 +945,7 @@ handle_brk:
goto idle_done; goto idle_done;
pc++; pc++;
result_ = 4; result_ = 4;
dprintf( "BRK executed\n" ); debug_printf( "BRK executed\n" );
interrupt: interrupt:
{ {

View file

@ -1,6 +1,6 @@
// Atari 6502 CPU emulator // Atari 6502 CPU emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef SAP_CPU_H #ifndef SAP_CPU_H
#define SAP_CPU_H #define SAP_CPU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Sap_Emu.h" #include "Sap_Emu.h"
@ -119,7 +119,7 @@ static blargg_err_t parse_info( byte const* in, long size, Sap_Emu::info_t* out
char const* tag = (char const*) in; char const* tag = (char const*) in;
while ( in < line_end && *in > ' ' ) while ( in < line_end && *in > ' ' )
in++; in++;
int tag_len = int((char const*) in - tag); int tag_len = (char const*) in - tag;
while ( in < line_end && *in <= ' ' ) in++; while ( in < line_end && *in <= ' ' ) in++;
@ -256,7 +256,7 @@ blargg_err_t Sap_Emu::load_mem_( byte const* in, long size )
set_warning( info.warning ); set_warning( info.warning );
set_track_count( info.track_count ); set_track_count( info.track_count );
set_voice_count( Sap_Apu::osc_count << (int)info.stereo ); set_voice_count( Sap_Apu::osc_count << info.stereo );
apu_impl.volume( gain() ); apu_impl.volume( gain() );
return setup_buffer( 1773447 ); return setup_buffer( 1773447 );
@ -315,8 +315,8 @@ inline void Sap_Emu::call_init( int track )
case 'C': case 'C':
r.a = 0x70; r.a = 0x70;
r.x = (BOOST::uint8_t)(info.music_addr&0xFF); r.x = info.music_addr&0xFF;
r.y = (BOOST::uint8_t)(info.music_addr >> 8); r.y = info.music_addr >> 8;
run_routine( info.play_addr + 3 ); run_routine( info.play_addr + 3 );
r.a = 0; r.a = 0;
r.x = track; r.x = track;
@ -336,7 +336,7 @@ blargg_err_t Sap_Emu::start_track_( int track )
{ {
unsigned start = get_le16( in ); unsigned start = get_le16( in );
unsigned end = get_le16( in + 2 ); unsigned end = get_le16( in + 2 );
//dprintf( "Block $%04X-$%04X\n", start, end ); //debug_printf( "Block $%04X-$%04X\n", start, end );
in += 4; in += 4;
if ( end < start ) if ( end < start )
{ {
@ -390,7 +390,7 @@ void Sap_Emu::cpu_write_( sap_addr_t addr, int data )
} }
if ( (addr & ~0x0010) != 0xD20F || data != 0x03 ) if ( (addr & ~0x0010) != 0xD20F || data != 0x03 )
dprintf( "Unmapped write $%04X <- $%02X\n", addr, data ); debug_printf( "Unmapped write $%04X <- $%02X\n", addr, data );
} }
inline void Sap_Emu::call_play() inline void Sap_Emu::call_play()

View file

@ -1,6 +1,6 @@
// Atari XL/XE SAP music file emulator // Atari XL/XE SAP music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef SAP_EMU_H #ifndef SAP_EMU_H
#define SAP_EMU_H #define SAP_EMU_H

View file

@ -141,7 +141,7 @@ void Sms_Noise::run( blip_time_t time, blip_time_t end_time )
do do
{ {
int changed = shifter + 1; int changed = shifter + 1;
shifter = (feedback & (unsigned)-(signed)(shifter & 1)) ^ (shifter >> 1); shifter = (feedback & -(shifter & 1)) ^ (shifter >> 1);
if ( changed & 2 ) // true if bits 0 and 1 differ if ( changed & 2 ) // true if bits 0 and 1 differ
{ {
delta = -delta; delta = -delta;

View file

@ -1,6 +1,6 @@
// SPC emulation support: init, sample buffering, reset, SPC loading // SPC emulation support: init, sample buffering, reset, SPC loading
// snes_spc 0.9.0. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Snes_Spc.h" #include "Snes_Spc.h"
@ -303,7 +303,7 @@ void Snes_Spc::set_output( sample_t* out, int size )
assert( out <= out_end ); assert( out <= out_end );
} }
dsp.set_output( out, int(out_end - out) ); dsp.set_output( out, out_end - out );
} }
else else
{ {

View file

@ -1,6 +1,6 @@
// SNES SPC-700 APU emulator // SNES SPC-700 APU emulator
// snes_spc 0.9.0 // Game_Music_Emu 0.6.0
#ifndef SNES_SPC_H #ifndef SNES_SPC_H
#define SNES_SPC_H #define SNES_SPC_H
@ -66,10 +66,7 @@ public:
// Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc.
enum { tempo_unit = 0x100 }; enum { tempo_unit = 0x100 };
void set_tempo( int ); void set_tempo( int );
enum { gain_unit = Spc_Dsp::gain_unit };
void set_gain( int gain );
// SPC music files // SPC music files
// Loads SPC data into emulator // Loads SPC data into emulator
@ -107,6 +104,22 @@ public:
bool check_kon(); bool check_kon();
#endif #endif
public:
// TODO: document
struct regs_t
{
int pc;
int a;
int x;
int y;
int psw;
int sp;
};
regs_t& smp_regs() { return m.cpu_regs; }
uint8_t* smp_ram() { return m.ram.ram; }
void run_until( time_t t ) { run_until_( t ); }
public: public:
BLARGG_DISABLE_NOTHROW BLARGG_DISABLE_NOTHROW
@ -146,15 +159,7 @@ private:
uint8_t smp_regs [2] [reg_count]; uint8_t smp_regs [2] [reg_count];
struct regs_t cpu_regs;
{
int pc;
int a;
int x;
int y;
int psw;
int sp;
} cpu_regs;
rel_time_t dsp_time; rel_time_t dsp_time;
time_t spc_time; time_t spc_time;
@ -271,8 +276,6 @@ inline void Snes_Spc::write_port( time_t t, int port, int data )
run_until_( t ) [0x10 + port] = data; run_until_( t ) [0x10 + port] = data;
} }
inline void Snes_Spc::set_gain( int gain ) { dsp.set_gain( gain ); }
inline void Snes_Spc::mute_voices( int mask ) { dsp.mute_voices( mask ); } inline void Snes_Spc::mute_voices( int mask ) { dsp.mute_voices( mask ); }
inline void Snes_Spc::disable_surround( bool disable ) { dsp.disable_surround( disable ); } inline void Snes_Spc::disable_surround( bool disable ) { dsp.disable_surround( disable ); }

View file

@ -1,6 +1,6 @@
// Core SPC emulation: CPU, timers, SMP registers, memory // Core SPC emulation: CPU, timers, SMP registers, memory
// snes_spc 0.9.0. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Snes_Spc.h" #include "Snes_Spc.h"
@ -176,7 +176,7 @@ inline void Snes_Spc::dsp_write( int data, rel_time_t time )
if ( REGS [r_dspaddr] <= 0x7F ) if ( REGS [r_dspaddr] <= 0x7F )
dsp.write( REGS [r_dspaddr], data ); dsp.write( REGS [r_dspaddr], data );
else if ( !SPC_MORE_ACCURACY ) else if ( !SPC_MORE_ACCURACY )
dprintf( "SPC wrote to DSP register > $7F\n" ); debug_printf( "SPC wrote to DSP register > $7F\n" );
} }
@ -277,8 +277,9 @@ static unsigned char const glitch_probs [3] [256] =
}; };
#endif #endif
// divided into multiple functions to keep rarely-used functionality separate // Read/write handlers are divided into multiple functions to keep rarely-used
// so often-used functionality can be optimized better by compiler // functionality separate so often-used functionality can be optimized better
// by compiler.
// If write isn't preceded by read, data has this added to it // If write isn't preceded by read, data has this added to it
int const no_read_before_write = 0x2000; int const no_read_before_write = 0x2000;
@ -302,7 +303,7 @@ void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
t->next_time == time + TIMER_MUL( t, 1 ) && t->next_time == time + TIMER_MUL( t, 1 ) &&
((period - 1) | ~0x0F) & period ) ((period - 1) | ~0x0F) & period )
{ {
//dprintf( "SPC pathological timer target write\n" ); //debug_printf( "SPC pathological timer target write\n" );
// If the period is 3, 5, or 9, there's a probability this behavior won't occur, // If the period is 3, 5, or 9, there's a probability this behavior won't occur,
// based on the previous period // based on the previous period
@ -331,7 +332,7 @@ void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
case r_t1out: case r_t1out:
case r_t2out: case r_t2out:
if ( !SPC_MORE_ACCURACY ) if ( !SPC_MORE_ACCURACY )
dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out ); debug_printf( "SPC wrote to counter %d\n", (int) addr - r_t0out );
if ( data < no_read_before_write / 2 ) if ( data < no_read_before_write / 2 )
run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0; run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0;
@ -345,7 +346,7 @@ void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
case r_test: case r_test:
if ( (uint8_t) data != 0x0A ) if ( (uint8_t) data != 0x0A )
dprintf( "SPC wrote to test register\n" ); debug_printf( "SPC wrote to test register\n" );
break; break;
case r_control: case r_control:

View file

@ -1,4 +1,4 @@
// snes_spc 0.9.0. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
/* Copyright (C) 2004-2007 Shay Green. This module is free software; you /* Copyright (C) 2004-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser can redistribute it and/or modify it under the terms of the GNU Lesser
@ -16,7 +16,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#if SPC_MORE_ACCURACY #if SPC_MORE_ACCURACY
#define SUSPICIOUS_OPCODE( name ) ((void) 0) #define SUSPICIOUS_OPCODE( name ) ((void) 0)
#else #else
#define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" ) #define SUSPICIOUS_OPCODE( name ) debug_printf( "SPC: suspicious opcode: " name "\n" )
#endif #endif
#define CPU_READ( time, offset, addr )\ #define CPU_READ( time, offset, addr )\
@ -69,7 +69,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define READ_PROG16( addr ) GET_LE16( ram + (addr) ) #define READ_PROG16( addr ) GET_LE16( ram + (addr) )
#define SET_PC( n ) (pc = ram + (n)) #define SET_PC( n ) (pc = ram + (n))
#define GET_PC() (int(pc - ram)) #define GET_PC() (pc - ram)
#define READ_PC( pc ) (*(pc)) #define READ_PC( pc ) (*(pc))
#define READ_PC16( pc ) GET_LE16( pc ) #define READ_PC16( pc ) GET_LE16( pc )
@ -77,7 +77,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define SPC_NO_SP_WRAPAROUND 0 #define SPC_NO_SP_WRAPAROUND 0
#define SET_SP( v ) (sp = ram + 0x101 + (v)) #define SET_SP( v ) (sp = ram + 0x101 + (v))
#define GET_SP() (int(sp - 0x101 - ram)) #define GET_SP() (sp - 0x101 - ram)
#if SPC_NO_SP_WRAPAROUND #if SPC_NO_SP_WRAPAROUND
#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))
@ -87,7 +87,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#else #else
#define PUSH16( data )\ #define PUSH16( data )\
{\ {\
int addr = int((sp -= 2) - ram);\ int addr = (sp -= 2) - ram;\
if ( addr > 0x100 )\ if ( addr > 0x100 )\
{\ {\
SET_LE16( sp, data );\ SET_LE16( sp, data );\
@ -242,7 +242,7 @@ loop:
BRANCH( (uint8_t) nz ) BRANCH( (uint8_t) nz )
case 0x3F:{// CALL case 0x3F:{// CALL
int old_addr = int(GET_PC() + 2); int old_addr = GET_PC() + 2;
SET_PC( READ_PC16( pc ) ); SET_PC( READ_PC16( pc ) );
PUSH16( old_addr ); PUSH16( old_addr );
goto loop; goto loop;
@ -256,7 +256,7 @@ loop:
} }
#else #else
{ {
int addr = int(sp - ram); int addr = sp - ram;
SET_PC( GET_LE16( sp ) ); SET_PC( GET_LE16( sp ) );
sp += 2; sp += 2;
if ( addr < 0x1FF ) if ( addr < 0x1FF )
@ -1184,7 +1184,7 @@ loop:
{ {
addr &= 0xFFFF; addr &= 0xFFFF;
SET_PC( addr ); SET_PC( addr );
dprintf( "SPC: PC wrapped around\n" ); debug_printf( "SPC: PC wrapped around\n" );
goto loop; goto loop;
} }
} }
@ -1205,7 +1205,7 @@ stop:
// Uncache registers // Uncache registers
if ( GET_PC() >= 0x10000 ) if ( GET_PC() >= 0x10000 )
dprintf( "SPC: PC wrapped around\n" ); debug_printf( "SPC: PC wrapped around\n" );
m.cpu_regs.pc = (uint16_t) GET_PC(); m.cpu_regs.pc = (uint16_t) GET_PC();
m.cpu_regs.sp = ( uint8_t) GET_SP(); m.cpu_regs.sp = ( uint8_t) GET_SP();
m.cpu_regs.a = ( uint8_t) a; m.cpu_regs.a = ( uint8_t) a;

View file

@ -1,4 +1,4 @@
// snes_spc 0.9.0. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Spc_Dsp.h" #include "Spc_Dsp.h"
@ -155,7 +155,7 @@ inline void Spc_Dsp::init_counter()
// counters start out with this synchronization // counters start out with this synchronization
m.counters [0] = 1; m.counters [0] = 1;
m.counters [1] = 0; m.counters [1] = 0;
m.counters [2] = -0x20; m.counters [2] = -0x20u;
m.counters [3] = 0x0B; m.counters [3] = 0x0B;
int n = 2; int n = 2;
@ -606,8 +606,8 @@ skip_brr:
} }
// Sound out // Sound out
int l = (((main_out_l * mvoll + echo_in_l * (int8_t) REG(evoll)) >> 14) * m.gain) >> 8; int l = (main_out_l * mvoll + echo_in_l * (int8_t) REG(evoll)) >> 14;
int r = (((main_out_r * mvolr + echo_in_r * (int8_t) REG(evolr)) >> 14) * m.gain) >> 8; int r = (main_out_r * mvolr + echo_in_r * (int8_t) REG(evolr)) >> 14;
CLAMP16( l ); CLAMP16( l );
CLAMP16( r ); CLAMP16( r );
@ -641,7 +641,6 @@ void Spc_Dsp::mute_voices( int mask )
void Spc_Dsp::init( void* ram_64k ) void Spc_Dsp::init( void* ram_64k )
{ {
m.ram = (uint8_t*) ram_64k; m.ram = (uint8_t*) ram_64k;
set_gain( gain_unit );
mute_voices( 0 ); mute_voices( 0 );
disable_surround( false ); disable_surround( false );
set_output( 0, 0 ); set_output( 0, 0 );

View file

@ -1,12 +1,12 @@
// Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one) // Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one)
// snes_spc 0.9.0 // Game_Music_Emu 0.6.0
#ifndef SPC_DSP_H #ifndef SPC_DSP_H
#define SPC_DSP_H #define SPC_DSP_H
#include "blargg_common.h" #include "blargg_common.h"
class Spc_Dsp { struct Spc_Dsp {
public: public:
typedef BOOST::uint8_t uint8_t; typedef BOOST::uint8_t uint8_t;
@ -51,10 +51,7 @@ public:
// If true, prevents channels and global volumes from being phase-negated // If true, prevents channels and global volumes from being phase-negated
void disable_surround( bool disable = true ); void disable_surround( bool disable = true );
enum { gain_unit = 0x100 };
void set_gain( int gain );
// State // State
// Resets DSP and uses supplied values to initialize registers // Resets DSP and uses supplied values to initialize registers
@ -140,7 +137,6 @@ private:
// non-emulation state // non-emulation state
uint8_t* ram; // 64K shared RAM between DSP and SMP uint8_t* ram; // 64K shared RAM between DSP and SMP
int mute_mask; int mute_mask;
int gain;
int surround_threshold; int surround_threshold;
sample_t* out; sample_t* out;
sample_t* out_end; sample_t* out_end;
@ -158,7 +154,7 @@ private:
#include <assert.h> #include <assert.h>
inline int Spc_Dsp::sample_count() const { return int(m.out - m.out_begin); } inline int Spc_Dsp::sample_count() const { return m.out - m.out_begin; }
inline int Spc_Dsp::read( int addr ) const inline int Spc_Dsp::read( int addr ) const
{ {
@ -204,8 +200,6 @@ inline void Spc_Dsp::write( int addr, int data )
} }
} }
inline void Spc_Dsp::set_gain( int gain ) { m.gain = gain; }
inline void Spc_Dsp::disable_surround( bool disable ) inline void Spc_Dsp::disable_surround( bool disable )
{ {
m.surround_threshold = disable ? 0 : -0x4000; m.surround_threshold = disable ? 0 : -0x4000;

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Spc_Emu.h" #include "Spc_Emu.h"
@ -19,6 +19,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h" #include "blargg_source.h"
// TODO: support Spc_Filter's bass
Spc_Emu::Spc_Emu() Spc_Emu::Spc_Emu()
{ {
set_type( gme_spc_type ); set_type( gme_spc_type );
@ -54,7 +56,7 @@ static void get_spc_xid6( byte const* begin, long size, track_info_t* out )
byte const* in = begin + 8; byte const* in = begin + 8;
if ( end - in > info_size ) if ( end - in > info_size )
{ {
dprintf( "Extra data after SPC xid6 info\n" ); debug_printf( "Extra data after SPC xid6 info\n" );
end = in + info_size; end = in + info_size;
} }
@ -114,7 +116,7 @@ static void get_spc_xid6( byte const* begin, long size, track_info_t* out )
default: default:
if ( id < 0x01 || (id > 0x07 && id < 0x10) || if ( id < 0x01 || (id > 0x07 && id < 0x10) ||
(id > 0x14 && id < 0x30) || id > 0x36 ) (id > 0x14 && id < 0x30) || id > 0x36 )
dprintf( "Unknown SPC xid6 block: %X\n", (int) id ); debug_printf( "Unknown SPC xid6 block: %X\n", (int) id );
break; break;
} }
if ( field ) if ( field )
@ -134,7 +136,7 @@ static void get_spc_xid6( byte const* begin, long size, track_info_t* out )
{ {
// ...but some files have no padding // ...but some files have no padding
in = unaligned; in = unaligned;
dprintf( "SPC info tag wasn't properly padded to align\n" ); debug_printf( "SPC info tag wasn't properly padded to align\n" );
break; break;
} }
} }
@ -226,14 +228,14 @@ struct Spc_File : Gme_Info_
{ {
RETURN_ERR( xid6.resize( xid6_size ) ); RETURN_ERR( xid6.resize( xid6_size ) );
RETURN_ERR( in.skip( xid6_offset - Spc_Emu::header_size ) ); RETURN_ERR( in.skip( xid6_offset - Spc_Emu::header_size ) );
RETURN_ERR( in.read( xid6.begin(), (long)xid6.size() ) ); RETURN_ERR( in.read( xid6.begin(), xid6.size() ) );
} }
return 0; return 0;
} }
blargg_err_t track_info_( track_info_t* out, int ) const blargg_err_t track_info_( track_info_t* out, int ) const
{ {
get_spc_info( header, xid6.begin(), (long)xid6.size(), out ); get_spc_info( header, xid6.begin(), xid6.size(), out );
return 0; return 0;
} }
}; };
@ -244,12 +246,13 @@ static Music_Emu* new_spc_file() { return BLARGG_NEW Spc_File; }
static gme_type_t_ const gme_spc_type_ = { "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 }; static gme_type_t_ const gme_spc_type_ = { "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 };
gme_type_t const gme_spc_type = &gme_spc_type_; gme_type_t const gme_spc_type = &gme_spc_type_;
// Setup // Setup
blargg_err_t Spc_Emu::set_sample_rate_( long sample_rate ) blargg_err_t Spc_Emu::set_sample_rate_( long sample_rate )
{ {
RETURN_ERR( apu.init() ); RETURN_ERR( apu.init() );
apu.set_gain( (int) (gain() * Snes_Spc::gain_unit) ); enable_accuracy( false );
if ( sample_rate != native_sample_rate ) if ( sample_rate != native_sample_rate )
{ {
RETURN_ERR( resampler.buffer_size( native_sample_rate / 20 * 2 ) ); RETURN_ERR( resampler.buffer_size( native_sample_rate / 20 * 2 ) );
@ -258,6 +261,12 @@ blargg_err_t Spc_Emu::set_sample_rate_( long sample_rate )
return 0; return 0;
} }
void Spc_Emu::enable_accuracy_( bool b )
{
Music_Emu::enable_accuracy_( b );
filter.enable( b );
}
void Spc_Emu::mute_voices_( int m ) void Spc_Emu::mute_voices_( int m )
{ {
Music_Emu::mute_voices_( m ); Music_Emu::mute_voices_( m );
@ -277,17 +286,29 @@ blargg_err_t Spc_Emu::load_mem_( byte const* in, long size )
// Emulation // Emulation
void Spc_Emu::set_tempo_( double t ) { apu.set_tempo( (int) (t * Snes_Spc::tempo_unit) ); } void Spc_Emu::set_tempo_( double t )
{
apu.set_tempo( (int) (t * apu.tempo_unit) );
}
blargg_err_t Spc_Emu::start_track_( int track ) blargg_err_t Spc_Emu::start_track_( int track )
{ {
RETURN_ERR( Music_Emu::start_track_( track ) ); RETURN_ERR( Music_Emu::start_track_( track ) );
resampler.clear(); resampler.clear();
filter.clear();
RETURN_ERR( apu.load_spc( file_data, file_size ) ); RETURN_ERR( apu.load_spc( file_data, file_size ) );
filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) );
apu.clear_echo(); apu.clear_echo();
return 0; return 0;
} }
blargg_err_t Spc_Emu::play_and_filter( long count, sample_t out [] )
{
RETURN_ERR( apu.play( count, out ) );
filter.run( out, count );
return 0;
}
blargg_err_t Spc_Emu::skip_( long count ) blargg_err_t Spc_Emu::skip_( long count )
{ {
if ( sample_rate() != native_sample_rate ) if ( sample_rate() != native_sample_rate )
@ -299,7 +320,10 @@ blargg_err_t Spc_Emu::skip_( long count )
// TODO: shouldn't skip be adjusted for the 64 samples read afterwards? // TODO: shouldn't skip be adjusted for the 64 samples read afterwards?
if ( count > 0 ) if ( count > 0 )
{
RETURN_ERR( apu.skip( count ) ); RETURN_ERR( apu.skip( count ) );
filter.clear();
}
// eliminate pop due to resampler // eliminate pop due to resampler
const int resampler_latency = 64; const int resampler_latency = 64;
@ -310,7 +334,7 @@ blargg_err_t Spc_Emu::skip_( long count )
blargg_err_t Spc_Emu::play_( long count, sample_t* out ) blargg_err_t Spc_Emu::play_( long count, sample_t* out )
{ {
if ( sample_rate() == native_sample_rate ) if ( sample_rate() == native_sample_rate )
return apu.play( count, out ); return play_and_filter( count, out );
long remain = count; long remain = count;
while ( remain > 0 ) while ( remain > 0 )
@ -319,7 +343,7 @@ blargg_err_t Spc_Emu::play_( long count, sample_t* out )
if ( remain > 0 ) if ( remain > 0 )
{ {
long n = resampler.max_write(); long n = resampler.max_write();
RETURN_ERR( apu.play( n, resampler.buffer() ) ); RETURN_ERR( play_and_filter( n, resampler.buffer() ) );
resampler.write( n ); resampler.write( n );
} }
} }

View file

@ -1,12 +1,13 @@
// Super Nintendo SPC music file emulator // Super Nintendo SPC music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef SPC_EMU_H #ifndef SPC_EMU_H
#define SPC_EMU_H #define SPC_EMU_H
#include "Fir_Resampler.h" #include "Fir_Resampler.h"
#include "Music_Emu.h" #include "Music_Emu.h"
#include "Snes_Spc.h" #include "Snes_Spc.h"
#include "Spc_Filter.h"
class Spc_Emu : public Music_Emu { class Spc_Emu : public Music_Emu {
public: public:
@ -65,11 +66,15 @@ protected:
blargg_err_t skip_( long ); blargg_err_t skip_( long );
void mute_voices_( int ); void mute_voices_( int );
void set_tempo_( double ); void set_tempo_( double );
void enable_accuracy_( bool );
private: private:
byte const* file_data; byte const* file_data;
long file_size; long file_size;
Fir_Resampler<24> resampler; Fir_Resampler<24> resampler;
SPC_Filter filter;
Snes_Spc apu; Snes_Spc apu;
blargg_err_t play_and_filter( long count, sample_t out [] );
}; };
inline void Spc_Emu::disable_surround( bool b ) { apu.disable_surround( b ); } inline void Spc_Emu::disable_surround( bool b ) { apu.disable_surround( b ); }

View file

@ -0,0 +1,83 @@
// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Spc_Filter.h"
#include <string.h>
/* Copyright (C) 2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h"
void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); }
SPC_Filter::SPC_Filter()
{
enabled = true;
gain = gain_unit;
bass = bass_norm;
clear();
}
void SPC_Filter::run( short* io, int count )
{
require( (count & 1) == 0 ); // must be even
int const gain = this->gain;
if ( enabled )
{
int const bass = this->bass;
chan_t* c = &ch [2];
do
{
// cache in registers
int sum = (--c)->sum;
int pp1 = c->pp1;
int p1 = c->p1;
for ( int i = 0; i < count; i += 2 )
{
// Low-pass filter (two point FIR with coeffs 0.25, 0.75)
int f = io [i] + p1;
p1 = io [i] * 3;
// High-pass filter ("leaky integrator")
int delta = f - pp1;
pp1 = f;
int s = sum >> (gain_bits + 2);
sum += (delta * gain) - (sum >> bass);
// Clamp to 16 bits
if ( (short) s != s )
s = (s >> 31) ^ 0x7FFF;
io [i] = (short) s;
}
c->p1 = p1;
c->pp1 = pp1;
c->sum = sum;
++io;
}
while ( c != ch );
}
else if ( gain != gain_unit )
{
short* const end = io + count;
while ( io < end )
{
int s = (*io * gain) >> gain_bits;
if ( (short) s != s )
s = (s >> 31) ^ 0x7FFF;
*io++ = (short) s;
}
}
}

View file

@ -0,0 +1,53 @@
// Simple low-pass and high-pass filter to better match sound output of a SNES
// Game_Music_Emu 0.6.0
#ifndef SPC_FILTER_H
#define SPC_FILTER_H
#include "blargg_common.h"
struct SPC_Filter {
public:
// Filters count samples of stereo sound in place. Count must be a multiple of 2.
typedef short sample_t;
void run( sample_t* io, int count );
// Optional features
// Clears filter to silence
void clear();
// Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit
// are fine, since output is clamped to 16-bit sample range.
enum { gain_unit = 0x100 };
void set_gain( int gain );
// Enables/disables filtering (when disabled, gain is still applied)
void enable( bool b );
// Sets amount of bass (logarithmic scale)
enum { bass_none = 0 };
enum { bass_norm = 8 }; // normal amount
enum { bass_max = 31 };
void set_bass( int bass );
public:
SPC_Filter();
BLARGG_DISABLE_NOTHROW
private:
enum { gain_bits = 8 };
int gain;
int bass;
bool enabled;
struct chan_t { int p1, pp1, sum; };
chan_t ch [2];
};
inline void SPC_Filter::enable( bool b ) { enabled = b; }
inline void SPC_Filter::set_gain( int g ) { gain = g; }
inline void SPC_Filter::set_bass( int b ) { bass = b; }
#endif

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Vgm_Emu.h" #include "Vgm_Emu.h"
@ -36,8 +36,7 @@ Vgm_Emu::Vgm_Emu()
set_silence_lookahead( 1 ); // tracks should already be trimmed set_silence_lookahead( 1 ); // tracks should already be trimmed
static equalizer_t const eq = { -14.0, 80, 0, 0, 0, 0, 0, 0, 0, 0 }; set_equalizer( make_equalizer( -14.0, 80 ) );
set_equalizer( eq );
} }
Vgm_Emu::~Vgm_Emu() { } Vgm_Emu::~Vgm_Emu() { }
@ -58,7 +57,7 @@ static byte const* skip_gd3_str( byte const* in, byte const* end )
static byte const* get_gd3_str( byte const* in, byte const* end, char* field ) static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
{ {
byte const* mid = skip_gd3_str( in, end ); byte const* mid = skip_gd3_str( in, end );
int len = int(mid - in) / 2 - 1; int len = (mid - in) / 2 - 1;
if ( len > 0 ) if ( len > 0 )
{ {
len = min( len, (int) Gme_File::max_field_ ); len = min( len, (int) Gme_File::max_field_ );
@ -109,7 +108,7 @@ byte const* Vgm_Emu::gd3_data( int* size ) const
return 0; return 0;
byte const* gd3 = data + header_size + gd3_offset; byte const* gd3 = data + header_size + gd3_offset;
long gd3_size = check_gd3_header( gd3, long(data_end - gd3) ); long gd3_size = check_gd3_header( gd3, data_end - gd3 );
if ( !gd3_size ) if ( !gd3_size )
return 0; return 0;
@ -185,7 +184,7 @@ struct Vgm_File : Gme_Info_
if ( gd3_size ) if ( gd3_size )
{ {
RETURN_ERR( gd3.resize( gd3_size ) ); RETURN_ERR( gd3.resize( gd3_size ) );
RETURN_ERR( in.read( gd3.begin(), (long)gd3.size() ) ); RETURN_ERR( in.read( gd3.begin(), gd3.size() ) );
} }
} }
return 0; return 0;
@ -218,8 +217,8 @@ void Vgm_Emu::set_tempo_( double t )
{ {
vgm_rate = (long) (44100 * t + 0.5); vgm_rate = (long) (44100 * t + 0.5);
blip_time_factor = (long) floor( double (1L << blip_time_bits) / vgm_rate * psg_rate + 0.5 ); blip_time_factor = (long) floor( double (1L << blip_time_bits) / vgm_rate * psg_rate + 0.5 );
//dprintf( "blip_time_factor: %ld\n", blip_time_factor ); //debug_printf( "blip_time_factor: %ld\n", blip_time_factor );
//dprintf( "vgm_rate: %ld\n", vgm_rate ); //debug_printf( "vgm_rate: %ld\n", vgm_rate );
// TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only) // TODO: remove? calculates vgm_rate more accurately (above differs at most by one Hz only)
//blip_time_factor = (long) floor( double (1L << blip_time_bits) * psg_rate / 44100 / t + 0.5 ); //blip_time_factor = (long) floor( double (1L << blip_time_bits) * psg_rate / 44100 / t + 0.5 );
//vgm_rate = (long) floor( double (1L << blip_time_bits) * psg_rate / blip_time_factor + 0.5 ); //vgm_rate = (long) floor( double (1L << blip_time_bits) * psg_rate / blip_time_factor + 0.5 );

View file

@ -1,6 +1,6 @@
// Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator // Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef VGM_EMU_H #ifndef VGM_EMU_H
#define VGM_EMU_H #define VGM_EMU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Vgm_Emu.h" #include "Vgm_Emu.h"
@ -244,7 +244,7 @@ int Vgm_Emu_Impl::play_frame( blip_time_t blip_time, int sample_count, sample_t*
int pairs = min_pairs; int pairs = min_pairs;
while ( (pairs = to_fm_time( vgm_time )) < min_pairs ) while ( (pairs = to_fm_time( vgm_time )) < min_pairs )
vgm_time++; vgm_time++;
//dprintf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs ); //debug_printf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs );
if ( ym2612.enabled() ) if ( ym2612.enabled() )
{ {

View file

@ -1,6 +1,6 @@
// Low-level parts of Vgm_Emu // Low-level parts of Vgm_Emu
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef VGM_EMU_IMPL_H #ifndef VGM_EMU_IMPL_H
#define VGM_EMU_IMPL_H #define VGM_EMU_IMPL_H

View file

@ -1,7 +1,7 @@
// Use in place of Ym2413_Emu.cpp and ym2413.c to disable support for this chip // Use in place of Ym2413_Emu.cpp and ym2413.c to disable support for this chip
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#include "Ym2413_Emu.h" #include "Ym2413_Emu.h"

View file

@ -1,6 +1,6 @@
// YM2413 FM sound chip emulator interface // YM2413 FM sound chip emulator interface
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef YM2413_EMU_H #ifndef YM2413_EMU_H
#define YM2413_EMU_H #define YM2413_EMU_H

View file

@ -1,4 +1,4 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
// Based on Gens 2.10 ym2612.c // Based on Gens 2.10 ym2612.c

View file

@ -1,6 +1,6 @@
// YM2612 FM sound chip emulator interface // YM2612 FM sound chip emulator interface
// Game_Music_Emu 0.5.2 // Game_Music_Emu 0.6.0
#ifndef YM2612_EMU_H #ifndef YM2612_EMU_H
#define YM2612_EMU_H #define YM2612_EMU_H

View file

@ -15,6 +15,13 @@
#ifndef BLARGG_COMMON_H #ifndef BLARGG_COMMON_H
#define BLARGG_COMMON_H #define BLARGG_COMMON_H
// BLARGG_RESTRICT: equivalent to restrict, where supported
#if __GNUC__ >= 3 || _MSC_VER >= 1100
#define BLARGG_RESTRICT __restrict
#else
#define BLARGG_RESTRICT
#endif
// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr) // STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
#ifndef STATIC_CAST #ifndef STATIC_CAST
#define STATIC_CAST(T,expr) ((T) (expr)) #define STATIC_CAST(T,expr) ((T) (expr))
@ -54,10 +61,11 @@ public:
}; };
#ifndef BLARGG_DISABLE_NOTHROW #ifndef BLARGG_DISABLE_NOTHROW
#if __cplusplus < 199711 // throw spec mandatory in ISO C++ if operator new can return NULL
#define BLARGG_THROWS( spec ) #if __cplusplus >= 199711 || __GNUC__ >= 3
#else
#define BLARGG_THROWS( spec ) throw spec #define BLARGG_THROWS( spec ) throw spec
#else
#define BLARGG_THROWS( spec )
#endif #endif
#define BLARGG_DISABLE_NOTHROW \ #define BLARGG_DISABLE_NOTHROW \
void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
@ -68,6 +76,7 @@ public:
#define BLARGG_NEW new (std::nothrow) #define BLARGG_NEW new (std::nothrow)
#endif #endif
// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
#define BLARGG_4CHAR( a, b, c, d ) \ #define BLARGG_4CHAR( a, b, c, d ) \
((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
@ -110,18 +119,17 @@ public:
#endif #endif
// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough // blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
#include <limits.h>
#if INT_MAX >= 0x7FFFFFFF #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
typedef int blargg_long;
#else
typedef long blargg_long; typedef long blargg_long;
#else
typedef int blargg_long;
#endif #endif
#if UINT_MAX >= 0xFFFFFFFF #if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
typedef unsigned blargg_ulong;
#else
typedef unsigned long blargg_ulong; typedef unsigned long blargg_ulong;
#else
typedef unsigned blargg_ulong;
#endif #endif
// BOOST::int8_t etc. // BOOST::int8_t etc.
@ -171,5 +179,18 @@ public:
}; };
#endif #endif
#if __GNUC__ >= 3
#define BLARGG_DEPRECATED __attribute__ ((deprecated))
#else
#define BLARGG_DEPRECATED
#endif
// Use in place of "= 0;" for a pure virtual, since these cause calls to std C++ lib.
// During development, BLARGG_PURE( x ) expands to = 0;
// virtual int func() BLARGG_PURE( { return 0; } )
#ifndef BLARGG_PURE
#define BLARGG_PURE( def ) def
#endif
#endif #endif
#endif #endif

View file

@ -6,9 +6,22 @@
// Uncomment to use zlib for transparent decompression of gzipped files // Uncomment to use zlib for transparent decompression of gzipped files
//#define HAVE_ZLIB_H //#define HAVE_ZLIB_H
// Uncomment to support only the listed game music types. See gme_type_list.cpp // Uncomment and edit list to support only the listed game music types,
// for a list of all types. // so that the others don't get linked in at all.
//#define GME_TYPE_LIST gme_nsf_type, gme_gbs_type /*
#define GME_TYPE_LIST \
gme_ay_type,\
gme_gbs_type,\
gme_gym_type,\
gme_hes_type,\
gme_kss_type,\
gme_nsf_type,\
gme_nsfe_type,\
gme_sap_type,\
gme_spc_type,\
gme_vgm_type,\
gme_vgz_type
*/
// Uncomment to enable platform-specific optimizations // Uncomment to enable platform-specific optimizations
//#define BLARGG_NONPORTABLE 1 //#define BLARGG_NONPORTABLE 1
@ -27,5 +40,4 @@
#include "config.h" #include "config.h"
#endif #endif
#endif #endif

View file

@ -1,20 +1,20 @@
// CPU Byte Order Utilities // CPU Byte Order Utilities
// Game_Music_Emu 0.5.2
#ifndef BLARGG_ENDIAN #ifndef BLARGG_ENDIAN
#define BLARGG_ENDIAN #define BLARGG_ENDIAN
#include "blargg_common.h" #include "blargg_common.h"
// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) // BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ #if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
#define BLARGG_CPU_X86 1 #define BLARGG_CPU_X86 1
#define BLARGG_CPU_CISC 1 #define BLARGG_CPU_CISC 1
#endif #endif
#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \
defined (__POWERPC__) || defined (__powerc)
#define BLARGG_CPU_POWERPC 1 #define BLARGG_CPU_POWERPC 1
#define BLARGG_CPU_RISC 1
#endif #endif
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
@ -36,10 +36,10 @@
#endif #endif
#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ #if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
defined (__mips__) || defined (__sparc__) || BLARGG_CPU_POWERPC || \ defined (__sparc__) || BLARGG_CPU_POWERPC || \
(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
#define BLARGG_BIG_ENDIAN 1 #define BLARGG_BIG_ENDIAN 1
#else #elif !defined (__mips__)
// No endian specified; assume little-endian, since it's most common // No endian specified; assume little-endian, since it's most common
#define BLARGG_LITTLE_ENDIAN 1 #define BLARGG_LITTLE_ENDIAN 1
#endif #endif
@ -64,45 +64,60 @@ inline void blargg_verify_byte_order()
#endif #endif
} }
inline unsigned get_le16( void const* p ) { inline unsigned get_le16( void const* p )
return ((unsigned char const*) p) [1] * 0x100u + {
((unsigned char const*) p) [0]; return (unsigned) ((unsigned char const*) p) [1] << 8 |
(unsigned) ((unsigned char const*) p) [0];
} }
inline unsigned get_be16( void const* p ) {
return ((unsigned char const*) p) [0] * 0x100u + inline unsigned get_be16( void const* p )
((unsigned char const*) p) [1]; {
return (unsigned) ((unsigned char const*) p) [0] << 8 |
(unsigned) ((unsigned char const*) p) [1];
} }
inline blargg_ulong get_le32( void const* p ) {
return ((unsigned char const*) p) [3] * 0x01000000u + inline blargg_ulong get_le32( void const* p )
((unsigned char const*) p) [2] * 0x00010000u + {
((unsigned char const*) p) [1] * 0x00000100u + return (blargg_ulong) ((unsigned char const*) p) [3] << 24 |
((unsigned char const*) p) [0]; (blargg_ulong) ((unsigned char const*) p) [2] << 16 |
(blargg_ulong) ((unsigned char const*) p) [1] << 8 |
(blargg_ulong) ((unsigned char const*) p) [0];
} }
inline blargg_ulong get_be32( void const* p ) {
return ((unsigned char const*) p) [0] * 0x01000000u + inline blargg_ulong get_be32( void const* p )
((unsigned char const*) p) [1] * 0x00010000u + {
((unsigned char const*) p) [2] * 0x00000100u + return (blargg_ulong) ((unsigned char const*) p) [0] << 24 |
((unsigned char const*) p) [3]; (blargg_ulong) ((unsigned char const*) p) [1] << 16 |
(blargg_ulong) ((unsigned char const*) p) [2] << 8 |
(blargg_ulong) ((unsigned char const*) p) [3];
} }
inline void set_le16( void* p, unsigned n ) {
inline void set_le16( void* p, unsigned n )
{
((unsigned char*) p) [1] = (unsigned char) (n >> 8); ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [0] = (unsigned char) n; ((unsigned char*) p) [0] = (unsigned char) n;
} }
inline void set_be16( void* p, unsigned n ) {
inline void set_be16( void* p, unsigned n )
{
((unsigned char*) p) [0] = (unsigned char) (n >> 8); ((unsigned char*) p) [0] = (unsigned char) (n >> 8);
((unsigned char*) p) [1] = (unsigned char) n; ((unsigned char*) p) [1] = (unsigned char) n;
} }
inline void set_le32( void* p, blargg_ulong n ) {
((unsigned char*) p) [3] = (unsigned char) (n >> 24); inline void set_le32( void* p, blargg_ulong n )
((unsigned char*) p) [2] = (unsigned char) (n >> 16); {
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [0] = (unsigned char) n; ((unsigned char*) p) [0] = (unsigned char) n;
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
} }
inline void set_be32( void* p, blargg_ulong n ) {
((unsigned char*) p) [0] = (unsigned char) (n >> 24); inline void set_be32( void* p, blargg_ulong n )
((unsigned char*) p) [1] = (unsigned char) (n >> 16); {
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
((unsigned char*) p) [3] = (unsigned char) n; ((unsigned char*) p) [3] = (unsigned char) n;
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
} }
#if BLARGG_NONPORTABLE #if BLARGG_NONPORTABLE
@ -117,30 +132,41 @@ inline void set_be32( void* p, blargg_ulong n ) {
#define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
#endif
#if BLARGG_CPU_POWERPC
#if BLARGG_CPU_POWERPC && defined (__MWERKS__) // PowerPC has special byte-reversed instructions
// PowerPC has special byte-reversed instructions #if defined (__MWERKS__)
// to do: assumes that PowerPC is running in big-endian mode #define GET_LE16( addr ) (__lhbrx( addr, 0 ))
// to do: implement for other compilers which don't support these macros #define GET_LE32( addr ) (__lwbrx( addr, 0 ))
#define GET_LE16( addr ) (__lhbrx( (addr), 0 )) #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 ))
#define GET_LE32( addr ) (__lwbrx( (addr), 0 )) #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 ))
#define SET_LE16( addr, data ) (__sthbrx( (data), (addr), 0 )) #elif defined (__GNUC__)
#define SET_LE32( addr, data ) (__stwbrx( (data), (addr), 0 )) #define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;})
#define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;})
#define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
#define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
#endif
#endif
#endif #endif
#endif #endif
#ifndef GET_LE16 #ifndef GET_LE16
#define GET_LE16( addr ) get_le16( addr ) #define GET_LE16( addr ) get_le16( addr )
#define GET_LE32( addr ) get_le32( addr )
#define SET_LE16( addr, data ) set_le16( addr, data ) #define SET_LE16( addr, data ) set_le16( addr, data )
#endif
#ifndef GET_LE32
#define GET_LE32( addr ) get_le32( addr )
#define SET_LE32( addr, data ) set_le32( addr, data ) #define SET_LE32( addr, data ) set_le32( addr, data )
#endif #endif
#ifndef GET_BE16 #ifndef GET_BE16
#define GET_BE16( addr ) get_be16( addr ) #define GET_BE16( addr ) get_be16( addr )
#define GET_BE32( addr ) get_be32( addr )
#define SET_BE16( addr, data ) set_be16( addr, data ) #define SET_BE16( addr, data ) set_be16( addr, data )
#endif
#ifndef GET_BE32
#define GET_BE32( addr ) get_be32( addr )
#define SET_BE32( addr, data ) set_be32( addr, data ) #define SET_BE32( addr, data ) set_be32( addr, data )
#endif #endif

View file

@ -1,4 +1,8 @@
// Included at the beginning of library source files, after all other #include lines /* Included at the beginning of library source files, after all other #include lines.
Sets up helpful macros and services used in my source code. They don't need
module an annoying module prefix on their names since they are defined after
all other #include lines. */
#ifndef BLARGG_SOURCE_H #ifndef BLARGG_SOURCE_H
#define BLARGG_SOURCE_H #define BLARGG_SOURCE_H
@ -16,10 +20,10 @@
// Like printf() except output goes to debug log file. Might be defined to do // Like printf() except output goes to debug log file. Might be defined to do
// nothing (not even evaluate its arguments). // nothing (not even evaluate its arguments).
// void dprintf( const char* format, ... ); // void debug_printf( const char* format, ... );
inline void blargg_dprintf_( const char*, ... ) { } static inline void blargg_dprintf_( const char*, ... ) { }
#undef dprintf #undef debug_printf
#define dprintf (1) ? (void) 0 : blargg_dprintf_ #define debug_printf (1) ? (void) 0 : blargg_dprintf_
// If enabled, evaluate expr and if false, make debug log entry with source file // If enabled, evaluate expr and if false, make debug log entry with source file
// and line. Meant for finding situations that should be examined further, but that // and line. Meant for finding situations that should be examined further, but that
@ -42,9 +46,25 @@ inline void blargg_dprintf_( const char*, ... ) { }
#undef min #undef min
#undef max #undef max
#define DEF_MIN_MAX( type ) \
static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\
static inline type max( type x, type y ) { if ( y < x ) return x; return y; }
DEF_MIN_MAX( int )
DEF_MIN_MAX( unsigned )
DEF_MIN_MAX( long )
DEF_MIN_MAX( unsigned long )
DEF_MIN_MAX( float )
DEF_MIN_MAX( double )
#undef DEF_MIN_MAX
/*
// using const references generates crappy code, and I am currenly only using these // using const references generates crappy code, and I am currenly only using these
// for built-in types, so they take arguments by value // for built-in types, so they take arguments by value
// TODO: remove
inline int min( int x, int y )
template<class T> template<class T>
inline T min( T x, T y ) inline T min( T x, T y )
{ {
@ -60,17 +80,29 @@ inline T max( T x, T y )
return y; return y;
return x; return x;
} }
*/
// TODO: good idea? bad idea? // TODO: good idea? bad idea?
#undef byte #undef byte
#define byte byte_ #define byte byte_
typedef unsigned char byte; typedef unsigned char byte;
// Setup compiler defines useful for exporting required public API symbols in gme.cpp
#ifndef BLARGG_EXPORT
#if defined (_WIN32) && defined(BLARGG_BUILD_DLL)
#define BLARGG_EXPORT __declspec(dllexport)
#elif defined (LIBGME_VISIBILITY)
#define BLARGG_EXPORT __attribute__((visibility ("default")))
#else
#define BLARGG_EXPORT
#endif
#endif
// deprecated // deprecated
#define BLARGG_CHECK_ALLOC CHECK_ALLOC #define BLARGG_CHECK_ALLOC CHECK_ALLOC
#define BLARGG_RETURN_ERR RETURN_ERR #define BLARGG_RETURN_ERR RETURN_ERR
// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check // BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of debug_printf and check
#ifdef BLARGG_SOURCE_BEGIN #ifdef BLARGG_SOURCE_BEGIN
#include BLARGG_SOURCE_BEGIN #include BLARGG_SOURCE_BEGIN
#endif #endif

View file

@ -10,9 +10,9 @@ int Gbs_Emu::cpu_read( gb_addr_t addr )
result = apu.read_register( clock(), addr ); result = apu.read_register( clock(), addr );
#ifndef NDEBUG #ifndef NDEBUG
else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 ) else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 )
dprintf( "Read from unmapped memory $%.4x\n", (unsigned) addr ); debug_printf( "Read from unmapped memory $%.4x\n", (unsigned) addr );
else if ( unsigned (addr - 0xFF01) < 0xFF80 - 0xFF01 ) else if ( unsigned (addr - 0xFF01) < 0xFF80 - 0xFF01 )
dprintf( "Unhandled I/O read 0x%4X\n", (unsigned) addr ); debug_printf( "Unhandled I/O read 0x%4X\n", (unsigned) addr );
#endif #endif
return result; return result;
} }
@ -38,7 +38,7 @@ void Gbs_Emu::cpu_write( gb_addr_t addr, int data )
ram [offset] = 0xFF; ram [offset] = 0xFF;
//if ( addr == 0xFFFF ) //if ( addr == 0xFFFF )
// dprintf( "Wrote interrupt mask\n" ); // debug_printf( "Wrote interrupt mask\n" );
} }
} }
else if ( (addr ^ 0x2000) <= 0x2000 - 1 ) else if ( (addr ^ 0x2000) <= 0x2000 - 1 )
@ -48,7 +48,7 @@ void Gbs_Emu::cpu_write( gb_addr_t addr, int data )
#ifndef NDEBUG #ifndef NDEBUG
else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 ) else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 )
{ {
dprintf( "Wrote to unmapped memory $%.4x\n", (unsigned) addr ); debug_printf( "Wrote to unmapped memory $%.4x\n", (unsigned) addr );
} }
#endif #endif
} }
@ -59,7 +59,7 @@ void Gbs_Emu::cpu_write( gb_addr_t addr, int data )
#define CPU_READ_FAST_( emu, addr, time, out ) \ #define CPU_READ_FAST_( emu, addr, time, out ) \
{\ {\
out = READ_PROG( addr );\ out = READ_PROG( addr );\
if ( unsigned (addr - Gb_Apu::start_addr) <= Gb_Apu::register_count )\ if ( unsigned (addr - Gb_Apu::start_addr) < Gb_Apu::register_count )\
out = emu->apu.read_register( emu->cpu_time - time * clocks_per_instr, addr );\ out = emu->apu.read_register( emu->cpu_time - time * clocks_per_instr, addr );\
else\ else\
check( out == emu->cpu_read( addr ) );\ check( out == emu->cpu_read( addr ) );\

View file

@ -1,9 +1,8 @@
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
#define IN_GME 1
#include "Music_Emu.h" #include "Music_Emu.h"
#include "gme_types.h"
#if !GME_DISABLE_STEREO_DEPTH #if !GME_DISABLE_STEREO_DEPTH
#include "Effects_Buffer.h" #include "Effects_Buffer.h"
#endif #endif
@ -24,32 +23,51 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h" #include "blargg_source.h"
#ifndef GME_TYPE_LIST BLARGG_EXPORT gme_type_t const* gme_type_list()
// Default list of all supported game music types (copy this to blargg_config.h
// if you want to modify it)
#define GME_TYPE_LIST \
gme_ay_type,\
gme_gbs_type,\
gme_gym_type,\
gme_hes_type,\
gme_kss_type,\
gme_nsf_type,\
gme_nsfe_type,\
gme_sap_type,\
gme_spc_type,\
gme_vgm_type,\
gme_vgz_type
#endif
gme_type_t const* GMEAPI gme_type_list()
{ {
static gme_type_t const gme_type_list_ [] = { GME_TYPE_LIST, 0 }; static gme_type_t const gme_type_list_ [] = {
#ifdef GME_TYPE_LIST
GME_TYPE_LIST,
#else
#ifdef USE_GME_AY
gme_ay_type,
#endif
#ifdef USE_GME_GBS
gme_gbs_type,
#endif
#ifdef USE_GME_GYM
gme_gym_type,
#endif
#ifdef USE_GME_HES
gme_hes_type,
#endif
#ifdef USE_GME_KSS
gme_kss_type,
#endif
#ifdef USE_GME_NSF
gme_nsf_type,
#endif
#ifdef USE_GME_NSFE
gme_nsfe_type,
#endif
#ifdef USE_GME_SAP
gme_sap_type,
#endif
#ifdef USE_GME_SPC
gme_spc_type,
#endif
#ifdef USE_GME_VGM
gme_vgm_type,
gme_vgz_type,
#endif
#endif
0
};
return gme_type_list_; return gme_type_list_;
} }
const char* GMEAPI gme_identify_header( void const* header ) BLARGG_EXPORT const char* gme_identify_header( void const* header )
{ {
switch ( get_be32( header ) ) switch ( get_be32( header ) )
{ {
@ -78,7 +96,7 @@ static void to_uppercase( const char* in, int len, char* out )
*out = 0; // extension too long *out = 0; // extension too long
} }
gme_type_t GMEAPI gme_identify_extension( const char* extension_ ) BLARGG_EXPORT gme_type_t gme_identify_extension( const char* extension_ )
{ {
char const* end = strrchr( extension_, '.' ); char const* end = strrchr( extension_, '.' );
if ( end ) if ( end )
@ -93,7 +111,7 @@ gme_type_t GMEAPI gme_identify_extension( const char* extension_ )
return 0; return 0;
} }
gme_err_t GMEAPI gme_identify_file( const char* path, gme_type_t* type_out ) BLARGG_EXPORT gme_err_t gme_identify_file( const char* path, gme_type_t* type_out )
{ {
*type_out = gme_identify_extension( path ); *type_out = gme_identify_extension( path );
// TODO: don't examine header if file has extension? // TODO: don't examine header if file has extension?
@ -108,7 +126,7 @@ gme_err_t GMEAPI gme_identify_file( const char* path, gme_type_t* type_out )
return 0; return 0;
} }
gme_err_t GMEAPI gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate ) BLARGG_EXPORT gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate )
{ {
require( (data || !size) && out ); require( (data || !size) && out );
*out = 0; *out = 0;
@ -132,7 +150,7 @@ gme_err_t GMEAPI gme_open_data( void const* data, long size, Music_Emu** out, in
return err; return err;
} }
GMEEXPORT gme_err_t GMEAPI gme_open_file( const char* path, Music_Emu** out, int sample_rate ) BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sample_rate )
{ {
require( path && out ); require( path && out );
*out = 0; *out = 0;
@ -169,7 +187,7 @@ GMEEXPORT gme_err_t GMEAPI gme_open_file( const char* path, Music_Emu** out, int
return err; return err;
} }
Music_Emu* GMEAPI gme_new_emu( gme_type_t type, int rate ) BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate )
{ {
if ( type ) if ( type )
{ {
@ -202,27 +220,27 @@ Music_Emu* GMEAPI gme_new_emu( gme_type_t type, int rate )
return 0; return 0;
} }
gme_err_t GMEAPI gme_load_file( Music_Emu* me, const char* path ) { return me->load_file( path ); } BLARGG_EXPORT gme_err_t gme_load_file( Music_Emu* me, const char* path ) { return me->load_file( path ); }
gme_err_t GMEAPI gme_load_data( Music_Emu* me, void const* data, long size ) BLARGG_EXPORT gme_err_t gme_load_data( Music_Emu* me, void const* data, long size )
{ {
Mem_File_Reader in( data, size ); Mem_File_Reader in( data, size );
return me->load( in ); return me->load( in );
} }
gme_err_t GMEAPI gme_load_custom( Music_Emu* me, gme_reader_t func, long size, void* data ) BLARGG_EXPORT gme_err_t gme_load_custom( Music_Emu* me, gme_reader_t func, long size, void* data )
{ {
Callback_Reader in( func, size, data ); Callback_Reader in( func, size, data );
return me->load( in ); return me->load( in );
} }
void GMEAPI gme_delete( Music_Emu* me ) { delete me; } BLARGG_EXPORT void gme_delete( Music_Emu* me ) { delete me; }
gme_type_t GMEAPI gme_type( Music_Emu const* me ) { return me->type(); } BLARGG_EXPORT gme_type_t gme_type( Music_Emu const* me ) { return me->type(); }
const char* GMEAPI gme_warning( Music_Emu* me ) { return me->warning(); } BLARGG_EXPORT const char* gme_warning( Music_Emu* me ) { return me->warning(); }
int GMEAPI gme_track_count( Music_Emu const* me ) { return me->track_count(); } BLARGG_EXPORT int gme_track_count( Music_Emu const* me ) { return me->track_count(); }
struct gme_info_t_ : gme_info_t struct gme_info_t_ : gme_info_t
{ {
@ -231,7 +249,7 @@ struct gme_info_t_ : gme_info_t
BLARGG_DISABLE_NOTHROW BLARGG_DISABLE_NOTHROW
}; };
gme_err_t GMEAPI gme_track_info( Music_Emu const* me, gme_info_t** out, int track ) BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track )
{ {
*out = NULL; *out = NULL;
@ -297,12 +315,12 @@ gme_err_t GMEAPI gme_track_info( Music_Emu const* me, gme_info_t** out, int trac
return 0; return 0;
} }
void GMEAPI gme_free_info( gme_info_t* info ) BLARGG_EXPORT void gme_free_info( gme_info_t* info )
{ {
delete STATIC_CAST(gme_info_t_*,info); delete STATIC_CAST(gme_info_t_*,info);
} }
void GMEAPI gme_set_stereo_depth( Music_Emu* me, double depth ) BLARGG_EXPORT void gme_set_stereo_depth( Music_Emu* me, double depth )
{ {
#if !GME_DISABLE_STEREO_DEPTH #if !GME_DISABLE_STEREO_DEPTH
if ( me->effects_buffer ) if ( me->effects_buffer )
@ -310,24 +328,26 @@ void GMEAPI gme_set_stereo_depth( Music_Emu* me, double depth )
#endif #endif
} }
void* GMEAPI gme_user_data ( Music_Emu const* me ) { return me->user_data(); } BLARGG_EXPORT void* gme_user_data ( Music_Emu const* me ) { return me->user_data(); }
void GMEAPI gme_set_user_data ( Music_Emu* me, void* new_user_data ) { me->set_user_data( new_user_data ); } BLARGG_EXPORT void gme_set_user_data ( Music_Emu* me, void* new_user_data ) { me->set_user_data( new_user_data ); }
void GMEAPI gme_set_user_cleanup(Music_Emu* me, gme_user_cleanup_t func ) { me->set_user_cleanup( func ); } BLARGG_EXPORT void gme_set_user_cleanup(Music_Emu* me, gme_user_cleanup_t func ) { me->set_user_cleanup( func ); }
gme_err_t GMEAPI gme_start_track ( Music_Emu* me, int index ) { return me->start_track( index ); } BLARGG_EXPORT gme_err_t gme_start_track ( Music_Emu* me, int index ) { return me->start_track( index ); }
gme_err_t GMEAPI gme_play ( Music_Emu* me, int n, short* p ) { return me->play( n, p ); } BLARGG_EXPORT gme_err_t gme_play ( Music_Emu* me, int n, short* p ) { return me->play( n, p ); }
gme_err_t GMEAPI gme_skip ( Music_Emu* me, long n ) { return me->skip( n ); } BLARGG_EXPORT void gme_set_fade ( Music_Emu* me, int start_msec ) { me->set_fade( start_msec ); }
void GMEAPI gme_set_fade ( Music_Emu* me, int start_msec ) { me->set_fade( start_msec ); } BLARGG_EXPORT int gme_track_ended ( Music_Emu const* me ) { return me->track_ended(); }
int GMEAPI gme_track_ended ( Music_Emu const* me ) { return me->track_ended(); } BLARGG_EXPORT int gme_tell ( Music_Emu const* me ) { return me->tell(); }
int GMEAPI gme_tell ( Music_Emu const* me ) { return me->tell(); } BLARGG_EXPORT gme_err_t gme_seek ( Music_Emu* me, int msec ) { return me->seek( msec ); }
gme_err_t GMEAPI gme_seek ( Music_Emu* me, int msec ) { return me->seek( msec ); } BLARGG_EXPORT int gme_voice_count ( Music_Emu const* me ) { return me->voice_count(); }
int GMEAPI gme_voice_count ( Music_Emu const* me ) { return me->voice_count(); } BLARGG_EXPORT void gme_ignore_silence ( Music_Emu* me, int disable ) { me->ignore_silence( disable != 0 ); }
void GMEAPI gme_ignore_silence ( Music_Emu* me, int disable ) { me->ignore_silence( disable != 0 ); } BLARGG_EXPORT void gme_set_tempo ( Music_Emu* me, double t ) { me->set_tempo( t ); }
void GMEAPI 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 ); }
void GMEAPI 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 ); }
void GMEAPI 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_clear_playlist ( Music_Emu* me ) { me->clear_playlist(); }
BLARGG_EXPORT int gme_type_multitrack( gme_type_t t ) { return t->track_count != 1; }
void GMEAPI gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq ) BLARGG_EXPORT void gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq )
{ {
Music_Emu::equalizer_t e = me->equalizer(); Music_Emu::equalizer_t e = me->equalizer();
e.treble = eq->treble; e.treble = eq->treble;
@ -335,16 +355,22 @@ void GMEAPI gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq )
me->set_equalizer( e ); me->set_equalizer( e );
} }
void GMEAPI gme_equalizer( Music_Emu const* me, gme_equalizer_t* out ) BLARGG_EXPORT void gme_equalizer( Music_Emu const* me, gme_equalizer_t* out )
{ {
gme_equalizer_t e = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; gme_equalizer_t e = gme_equalizer_t(); // Default-init all fields to 0.0f
e.treble = me->equalizer().treble; e.treble = me->equalizer().treble;
e.bass = me->equalizer().bass; e.bass = me->equalizer().bass;
*out = e; *out = e;
} }
const char* GMEAPI gme_voice_name( Music_Emu const* me, int i ) BLARGG_EXPORT const char* gme_voice_name( Music_Emu const* me, int i )
{ {
assert( (unsigned) i < (unsigned) me->voice_count() ); assert( (unsigned) i < (unsigned) me->voice_count() );
return me->voice_names() [i]; return me->voice_names() [i];
} }
BLARGG_EXPORT const char* gme_type_system( gme_type_t type )
{
assert( type );
return type->system;
}

View file

@ -1,33 +1,15 @@
/* Game music emulator library C interface (also usable from C++) */ /* Game music emulator library C interface (also usable from C++) */
/* Game_Music_Emu 0.5.2 */ /* Game_Music_Emu 0.6.0 */
#ifndef GME_H #ifndef GME_H
#define GME_H #define GME_H
#ifdef _MSC_VER
#define GMEAPI __stdcall
#else
#define GMEAPI
#endif
#if defined(_MSC_VER) && defined(GME_DLL)
#define GMEEXPORT __declspec(dllexport)
#define GMEIMPORT __declspec(dllimport)
#if IN_GME
#define GMEDLL GMEEXPORT
#else
#define GMEDLL GMEIMPORT
#endif
#else
#define GMEEXPORT
#define GMEIMPORT
#define GMEDLL
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define GME_VERSION 0x000600 /* 1 byte major, 1 byte minor, 1 byte patch-level */
/* Error string returned by library functions, or NULL if no error (success) */ /* Error string returned by library functions, or NULL if no error (success) */
typedef const char* gme_err_t; typedef const char* gme_err_t;
@ -38,38 +20,35 @@ typedef struct Music_Emu Music_Emu;
/******** Basic operations ********/ /******** Basic operations ********/
/* Create emulator and load game music file/data into it. Sets *out to new emulator. */ /* Create emulator and load game music file/data into it. Sets *out to new emulator. */
GMEDLL gme_err_t GMEAPI gme_open_file( const char path [], Music_Emu** out, int sample_rate ); gme_err_t gme_open_file( const char path [], Music_Emu** out, int sample_rate );
/* Number of tracks available */ /* Number of tracks available */
GMEDLL int GMEAPI gme_track_count( Music_Emu const* ); int gme_track_count( Music_Emu const* );
/* Start a track, where 0 is the first track */ /* Start a track, where 0 is the first track */
GMEDLL gme_err_t GMEAPI gme_start_track( Music_Emu*, int index ); gme_err_t gme_start_track( Music_Emu*, int index );
/* Generate 'count' 16-bit signed samples info 'out'. Output is in stereo. */ /* Generate 'count' 16-bit signed samples info 'out'. Output is in stereo. */
GMEDLL gme_err_t GMEAPI gme_play( Music_Emu*, int count, short out [] ); gme_err_t gme_play( Music_Emu*, int count, short out [] );
/* Skip n samples */
GMEDLL gme_err_t GMEAPI gme_skip( Music_Emu*, long n );
/* Finish using emulator and free memory */ /* Finish using emulator and free memory */
GMEDLL void GMEAPI gme_delete( Music_Emu* ); void gme_delete( Music_Emu* );
/******** Track position/length ********/ /******** Track position/length ********/
/* Set time to start fading track out. Once fade ends track_ended() returns true. /* Set time to start fading track out. Once fade ends track_ended() returns true.
Fade time can be changed while track is playing. */ Fade time can be changed while track is playing. */
GMEDLL void GMEAPI gme_set_fade( Music_Emu*, int start_msec ); void gme_set_fade( Music_Emu*, int start_msec );
/* True if a track has reached its end */ /* True if a track has reached its end */
GMEDLL int GMEAPI gme_track_ended( Music_Emu const* ); int gme_track_ended( Music_Emu const* );
/* Number of milliseconds (1000 = one second) played since beginning of track */ /* Number of milliseconds (1000 = one second) played since beginning of track */
GMEDLL int GMEAPI gme_tell( Music_Emu const* ); int gme_tell( Music_Emu const* );
/* Seek to new time in track. Seeking backwards or far forward can take a while. */ /* Seek to new time in track. Seeking backwards or far forward can take a while. */
GMEDLL gme_err_t GMEAPI gme_seek( Music_Emu*, int msec ); gme_err_t gme_seek( Music_Emu*, int msec );
/******** Informational ********/ /******** Informational ********/
@ -80,22 +59,22 @@ enum { gme_info_only = -1 };
/* Most recent warning string, or NULL if none. Clears current warning after returning. /* Most recent warning string, or NULL if none. Clears current warning after returning.
Warning is also cleared when loading a file and starting a track. */ Warning is also cleared when loading a file and starting a track. */
GMEDLL const char* GMEAPI gme_warning( Music_Emu* ); const char* gme_warning( Music_Emu* );
/* Load m3u playlist file (must be done after loading music) */ /* Load m3u playlist file (must be done after loading music) */
GMEDLL gme_err_t GMEAPI gme_load_m3u( Music_Emu*, const char path [] ); gme_err_t gme_load_m3u( Music_Emu*, const char path [] );
/* Clear any loaded m3u playlist and any internal playlist that the music format /* Clear any loaded m3u playlist and any internal playlist that the music format
supports (NSFE for example). */ supports (NSFE for example). */
GMEDLL void GMEAPI gme_clear_playlist( Music_Emu* ); void gme_clear_playlist( Music_Emu* );
/* Gets information for a particular track (length, name, author, etc.). /* Gets information for a particular track (length, name, author, etc.).
Must be freed after use. */ Must be freed after use. */
typedef struct gme_info_t gme_info_t; typedef struct gme_info_t gme_info_t;
GMEDLL gme_err_t GMEAPI gme_track_info( Music_Emu const*, gme_info_t** out, int track ); gme_err_t gme_track_info( Music_Emu const*, gme_info_t** out, int track );
/* Frees track information */ /* Frees track information */
GMEDLL void GMEAPI gme_free_info( gme_info_t* ); void gme_free_info( gme_info_t* );
struct gme_info_t struct gme_info_t
{ {
@ -127,30 +106,31 @@ struct gme_info_t
/* Adjust stereo echo depth, where 0.0 = off and 1.0 = maximum. Has no effect for /* Adjust stereo echo depth, where 0.0 = off and 1.0 = maximum. Has no effect for
GYM, SPC, and Sega Genesis VGM music */ GYM, SPC, and Sega Genesis VGM music */
GMEDLL void GMEAPI gme_set_stereo_depth( Music_Emu*, double depth ); void gme_set_stereo_depth( Music_Emu*, double depth );
/* Disable automatic end-of-track detection and skipping of silence at beginning /* Disable automatic end-of-track detection and skipping of silence at beginning
if ignore is true */ if ignore is true */
GMEDLL void GMEAPI gme_ignore_silence( Music_Emu*, int ignore ); void gme_ignore_silence( Music_Emu*, int ignore );
/* Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. /* Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
Track length as returned by track_info() assumes a tempo of 1.0. */ Track length as returned by track_info() assumes a tempo of 1.0. */
GMEDLL void GMEAPI gme_set_tempo( Music_Emu*, double tempo ); void gme_set_tempo( Music_Emu*, double tempo );
/* Number of voices used by currently loaded file */ /* Number of voices used by currently loaded file */
GMEDLL int GMEAPI gme_voice_count( Music_Emu const* ); int gme_voice_count( Music_Emu const* );
/* Name of voice i, from 0 to gme_voice_count() - 1 */ /* Name of voice i, from 0 to gme_voice_count() - 1 */
GMEDLL const char* GMEAPI gme_voice_name( Music_Emu const*, int i ); const char* gme_voice_name( Music_Emu const*, int i );
/* Mute/unmute voice i, where voice 0 is first voice */ /* Mute/unmute voice i, where voice 0 is first voice */
GMEDLL void GMEAPI gme_mute_voice( Music_Emu*, int index, int mute ); void gme_mute_voice( Music_Emu*, int index, int mute );
/* Set muting state of all voices at once using a bit mask, where -1 mutes all /* Set muting state of all voices at once using a bit mask, where -1 mutes all
voices, 0 unmutes them all, 0x01 mutes just the first voice, etc. */ voices, 0 unmutes them all, 0x01 mutes just the first voice, etc. */
GMEDLL void GMEAPI gme_mute_voices( Music_Emu*, int muting_mask ); void gme_mute_voices( Music_Emu*, int muting_mask );
/* Frequency equalizer parameters (see gme.txt) */ /* Frequency equalizer parameters (see gme.txt) */
/* Implementers: If modified, also adjust Music_Emu::make_equalizer as needed */
typedef struct gme_equalizer_t typedef struct gme_equalizer_t
{ {
double treble; /* -50.0 = muffled, 0 = flat, +5.0 = extra-crisp */ double treble; /* -50.0 = muffled, 0 = flat, +5.0 = extra-crisp */
@ -160,11 +140,13 @@ typedef struct gme_equalizer_t
} gme_equalizer_t; } gme_equalizer_t;
/* Get current frequency equalizater parameters */ /* Get current frequency equalizater parameters */
GMEDLL void GMEAPI gme_equalizer( Music_Emu const*, gme_equalizer_t* out ); void gme_equalizer( Music_Emu const*, gme_equalizer_t* out );
/* Change frequency equalizer parameters */ /* Change frequency equalizer parameters */
GMEDLL void GMEAPI gme_set_equalizer( Music_Emu*, gme_equalizer_t const* eq ); void gme_set_equalizer( Music_Emu*, gme_equalizer_t const* eq );
/* Enables/disables most accurate sound emulation options */
void gme_enable_accuracy( Music_Emu*, int enabled );
/******** Game music types ********/ /******** Game music types ********/
@ -187,17 +169,17 @@ extern const gme_type_t
gme_vgz_type; gme_vgz_type;
/* Type of this emulator */ /* Type of this emulator */
GMEDLL gme_type_t GMEAPI gme_type( Music_Emu const* ); gme_type_t gme_type( Music_Emu const* );
/* Pointer to array of all music types, with NULL entry at end. Allows a player linked /* Pointer to array of all music types, with NULL entry at end. Allows a player linked
to this library to support new music types without having to be updated. */ to this library to support new music types without having to be updated. */
GMEDLL gme_type_t const* GMEAPI gme_type_list(); gme_type_t const* gme_type_list();
/* Name of game system for this music file type */ /* Name of game system for this music file type */
GMEDLL const char* GMEAPI gme_type_system( gme_type_t ); const char* gme_type_system( gme_type_t );
/* True if this music file type supports multiple tracks */ /* True if this music file type supports multiple tracks */
GMEDLL int GMEAPI gme_type_multitrack( gme_type_t ); int gme_type_multitrack( gme_type_t );
/******** Advanced file loading ********/ /******** Advanced file loading ********/
@ -206,50 +188,50 @@ GMEDLL int GMEAPI gme_type_multitrack( gme_type_t );
extern const char* const gme_wrong_file_type; extern const char* const gme_wrong_file_type;
/* Same as gme_open_file(), but uses file data already in memory. Makes copy of data. */ /* Same as gme_open_file(), but uses file data already in memory. Makes copy of data. */
GMEDLL gme_err_t GMEAPI gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate ); gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate );
/* Determine likely game music type based on first four bytes of file. Returns /* Determine likely game music type based on first four bytes of file. Returns
string containing proper file suffix (i.e. "NSF", "SPC", etc.) or "" if string containing proper file suffix (i.e. "NSF", "SPC", etc.) or "" if
file header is not recognized. */ file header is not recognized. */
GMEDLL const char* GMEAPI gme_identify_header( void const* header ); const char* gme_identify_header( void const* header );
/* Get corresponding music type for file path or extension passed in. */ /* Get corresponding music type for file path or extension passed in. */
GMEDLL gme_type_t GMEAPI gme_identify_extension( const char path_or_extension [] ); gme_type_t gme_identify_extension( const char path_or_extension [] );
/* Determine file type based on file's extension or header (if extension isn't recognized). /* Determine file type based on file's extension or header (if extension isn't recognized).
Sets *type_out to type, or 0 if unrecognized or error. */ Sets *type_out to type, or 0 if unrecognized or error. */
GMEDLL gme_err_t GMEAPI gme_identify_file( const char path [], gme_type_t* type_out ); gme_err_t gme_identify_file( const char path [], gme_type_t* type_out );
/* Create new emulator and set sample rate. Returns NULL if out of memory. If you only need /* Create new emulator and set sample rate. Returns NULL if out of memory. If you only need
track information, pass gme_info_only for sample_rate. */ track information, pass gme_info_only for sample_rate. */
GMEDLL Music_Emu* GMEAPI gme_new_emu( gme_type_t, int sample_rate ); Music_Emu* gme_new_emu( gme_type_t, int sample_rate );
/* Load music file into emulator */ /* Load music file into emulator */
GMEDLL gme_err_t GMEAPI gme_load_file( Music_Emu*, const char path [] ); gme_err_t gme_load_file( Music_Emu*, const char path [] );
/* Load music file from memory into emulator. Makes a copy of data passed. */ /* Load music file from memory into emulator. Makes a copy of data passed. */
GMEDLL gme_err_t GMEAPI gme_load_data( Music_Emu*, void const* data, long size ); gme_err_t gme_load_data( Music_Emu*, void const* data, long size );
/* Load music file using custom data reader function that will be called to /* Load music file using custom data reader function that will be called to
read file data. Most emulators load the entire file in one read call. */ read file data. Most emulators load the entire file in one read call. */
typedef gme_err_t (GMEAPI *gme_reader_t)( void* your_data, void* out, int count ); typedef gme_err_t (*gme_reader_t)( void* your_data, void* out, int count );
GMEDLL gme_err_t GMEAPI gme_load_custom( Music_Emu*, gme_reader_t, long file_size, void* your_data ); gme_err_t gme_load_custom( Music_Emu*, gme_reader_t, long file_size, void* your_data );
/* Load m3u playlist file from memory (must be done after loading music) */ /* Load m3u playlist file from memory (must be done after loading music) */
GMEDLL gme_err_t GMEAPI gme_load_m3u_data( Music_Emu*, void const* data, long size ); gme_err_t gme_load_m3u_data( Music_Emu*, void const* data, long size );
/******** User data ********/ /******** User data ********/
/* Set/get pointer to data you want to associate with this emulator. /* Set/get pointer to data you want to associate with this emulator.
You can use this for whatever you want. */ You can use this for whatever you want. */
GMEDLL void GMEAPI gme_set_user_data( Music_Emu*, void* new_user_data ); void gme_set_user_data( Music_Emu*, void* new_user_data );
GMEDLL void* GMEAPI gme_user_data( Music_Emu const* ); void* gme_user_data( Music_Emu const* );
/* Register cleanup function to be called when deleting emulator, or NULL to /* Register cleanup function to be called when deleting emulator, or NULL to
clear it. Passes user_data to cleanup function. */ clear it. Passes user_data to cleanup function. */
typedef void (GMEAPI *gme_user_cleanup_t)( void* user_data ); typedef void (*gme_user_cleanup_t)( void* user_data );
GMEDLL void GMEAPI gme_set_user_cleanup( Music_Emu*, gme_user_cleanup_t func ); void gme_set_user_cleanup( Music_Emu*, gme_user_cleanup_t func );
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -0,0 +1,21 @@
#ifndef GME_TYPES_H
#define GME_TYPES_H
/*
* 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
#define USE_GME_HES
#define USE_GME_KSS
#define USE_GME_NSF
#define USE_GME_NSFE
#define USE_GME_SAP
#define USE_GME_SPC
/* VGM and VGZ are a package deal */
#define USE_GME_VGM
#endif /* GME_TYPES_H */

View file

@ -0,0 +1,23 @@
#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
*/
#cmakedefine USE_GME_AY
#cmakedefine USE_GME_GBS
#cmakedefine USE_GME_GYM
#cmakedefine USE_GME_HES
#cmakedefine USE_GME_KSS
#cmakedefine USE_GME_NSF
#cmakedefine USE_GME_NSFE
#cmakedefine USE_GME_SAP
#cmakedefine USE_GME_SPC
/* VGM and VGZ are a package deal */
#cmakedefine USE_GME_VGM
#endif /* GME_TYPES_H */

View file

@ -44,7 +44,7 @@ inline byte const* Hes_Emu::cpu_set_mmr( int page, int bank )
default: default:
if ( bank != 0xFF ) if ( bank != 0xFF )
dprintf( "Unmapped bank $%02X\n", bank ); debug_printf( "Unmapped bank $%02X\n", bank );
return rom.unmapped(); return rom.unmapped();
} }

View file

@ -34,7 +34,7 @@ int Nsf_Emu::cpu_read( nes_addr_t addr )
result = addr >> 8; // simulate open bus result = addr >> 8; // simulate open bus
if ( addr != 0x2002 ) if ( addr != 0x2002 )
dprintf( "Read unmapped $%.4X\n", (unsigned) addr ); debug_printf( "Read unmapped $%.4X\n", (unsigned) addr );
exit: exit:
return result; return result;

View file

@ -20,7 +20,7 @@ void Sap_Emu::cpu_write( sap_addr_t addr, int data )
int Sap_Emu::cpu_read( sap_addr_t addr ) int Sap_Emu::cpu_read( sap_addr_t addr )
{ {
if ( (addr & 0xF900) == 0xD000 ) if ( (addr & 0xF900) == 0xD000 )
dprintf( "Unmapped read $%04X\n", addr ); debug_printf( "Unmapped read $%04X\n", addr );
return mem.ram [addr]; return mem.ram [addr];
} }
#endif #endif

View file

@ -1,4 +1,4 @@
Game_Music_Emu 0.5.2: Game Music Emulators Game_Music_Emu 0.6.0: Game Music Emulators
------------------------------------------ ------------------------------------------
Game_Music_Emu is a collection of video game music file emulators that Game_Music_Emu is a collection of video game music file emulators that
support the following formats and systems: support the following formats and systems:
@ -14,7 +14,7 @@ SPC Super Nintendo/Super Famicom
VGM/VGZ Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro VGM/VGZ Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro
Features: Features:
* Can be used in C and C++ code * C interface for use in C, C++, and other compatible languages
* High emphasis has been placed on making the library very easy to use * High emphasis has been placed on making the library very easy to use
* One set of common functions work with all emulators the same way * One set of common functions work with all emulators the same way
* Several code examples, including music player using SDL * Several code examples, including music player using SDL
@ -42,8 +42,17 @@ License: GNU Lesser General Public License (LGPL)
Getting Started Getting Started
--------------- ---------------
Build a program consisting of demo/basics.c, demo/Wave_Writer.cpp, and Build a program consisting of demo/basics.c, demo/Wave_Writer.cpp, and
all source files in gme/. Be sure "test.nsf" is in the same directory. all source files in gme/. If you have CMake 2.6 or later, execute
Running the program should generate the recording "out.wav".
run cmake
cd demo
run make
Be sure "test.nsf" is in the same directory as the program. Running it
should generate the recording "out.wav".
A slightly more extensive demo application is available in the player/
directory. It requires SDL to build.
Read gme.txt for more information. Post to the discussion forum for Read gme.txt for more information. Post to the discussion forum for
assistance. assistance.
@ -55,16 +64,17 @@ gme.txt General notes about the library
changes.txt Changes made since previous releases changes.txt Changes made since previous releases
design.txt Library design notes design.txt Library design notes
license.txt GNU Lesser General Public License license.txt GNU Lesser General Public License
CMakeLists.txt CMake build rules
test.nsf Test file for NSF emulator test.nsf Test file for NSF emulator
test.m3u Test m3u playlist for features.c demo test.m3u Test m3u playlist for features.c demo
demo/ demo/
basics.c Records NSF file to wave sound file basics.c Records NSF file to wave sound file
cpp_basics.cpp C++ version of basics.c
features.c Demonstrates many additional features features.c Demonstrates many additional features
Wave_Writer.h WAVE sound file writer used for demo output Wave_Writer.h WAVE sound file writer used for demo output
Wave_Writer.cpp Wave_Writer.cpp
CMakeLists.txt CMake build rules
player/ Player using the SDL multimedia library player/ Player using the SDL multimedia library
player.cpp Simple music player with waveform display player.cpp Simple music player with waveform display
@ -72,22 +82,13 @@ player/ Player using the SDL multimedia library
Music_Player.h Music_Player.h
Audio_Scope.cpp Audio waveform scope Audio_Scope.cpp Audio waveform scope
Audio_Scope.h Audio_Scope.h
CMakeLists.txt CMake build rules
gme/ gme/
blargg_config.h Library configuration (modify this file as needed) blargg_config.h Library configuration (modify this file as needed)
gme.h C interface (also usable in C++, and simpler too) gme.h Library interface header file
gme.cpp gme.cpp
Gme_File.h File loading and track information
Music_Emu.h Track playback and adjustments
Data_Reader.h Custom data readers
Effects_Buffer.h Sound buffer with stereo echo and panning
Effects_Buffer.cpp
M3u_Playlist.h M3U playlist support
M3u_Playlist.cpp
Ay_Emu.h ZX Spectrum AY emulator Ay_Emu.h ZX Spectrum AY emulator
Ay_Emu.cpp Ay_Emu.cpp
@ -113,7 +114,7 @@ gme/
Hes_Cpu.h Hes_Cpu.h
hes_cpu_io.h hes_cpu_io.h
Hes_Emu.cpp Hes_Emu.cpp
Kss_Emu.h MSX Home Computer/other Z80 systems KSS emulator Kss_Emu.h MSX Home Computer/other Z80 systems KSS emulator
Kss_Emu.cpp Kss_Emu.cpp
Kss_Cpu.cpp Kss_Cpu.cpp
@ -180,26 +181,36 @@ gme/
Dual_Resampler.h Dual_Resampler.h
Fir_Resampler.cpp Fir_Resampler.cpp
Fir_Resampler.h Fir_Resampler.h
M3u_Playlist.h M3U playlist support
M3u_Playlist.cpp
Effects_Buffer.h Sound buffer with stereo echo and panning
Effects_Buffer.cpp
blargg_common.h Common files needed by all emulators blargg_common.h Common files needed by all emulators
blargg_endian.h blargg_endian.h
blargg_source.h blargg_source.h
Blip_Buffer.cpp Blip_Buffer.cpp
Blip_Buffer.h Blip_Buffer.h
Gme_File.h
Gme_File.cpp Gme_File.cpp
Music_Emu.h
Music_Emu.cpp Music_Emu.cpp
Classic_Emu.h Classic_Emu.h
Classic_Emu.cpp Classic_Emu.cpp
Multi_Buffer.h Multi_Buffer.h
Multi_Buffer.cpp Multi_Buffer.cpp
Data_Reader.h
Data_Reader.cpp Data_Reader.cpp
CMakeLists.txt CMake build rules
Legal Legal
----- -----
Game_Music_Emu library copyright (C) 2003-2006 Shay Green. Game_Music_Emu library copyright (C) 2003-2009 Shay Green.
SNES SPC DSP emulator based on OpenSPC, copyright (C) 2002 Brad Martin.
Sega Genesis YM2612 emulator copyright (C) 2002 Stephane Dallongeville. Sega Genesis YM2612 emulator copyright (C) 2002 Stephane Dallongeville.
-- --
Shay Green <gblargg@gmail.com> Shay Green <gblargg@gmail.com>