diff --git a/CMakeLists.txt b/CMakeLists.txt index 0020de417..453718045 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -166,14 +166,6 @@ target_architecture(DEMOLITION_TARGET_ARCH) # find_package( asmjit ) #endif() -# GME -#find_path( GME_INCLUDE_DIR gme/gme.h ) -#find_library( GME_LIBRARIES gme ) -#mark_as_advanced( GME_INCLUDE_DIR GME_LIBRARIES ) -#FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME -# REQUIRED_VARS GME_LIBRARIES GME_INCLUDE_DIR -#) - if( MSVC ) # Eliminate unreferenced functions and data # Perform identical COMDAT folding @@ -302,10 +294,8 @@ set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" ) option(FORCE_INTERNAL_ZLIB "Use internal zlib") option(FORCE_INTERNAL_JPEG "Use internal jpeg") option(FORCE_INTERNAL_BZIP2 "Use internal bzip2") -option(FORCE_INTERNAL_GME "Use internal gme" ON) -mark_as_advanced( FORCE_INTERNAL_GME ) -option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON) -mark_as_advanced( FORCE_INTERNAL_ASMJIT ) +#option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON) +#mark_as_advanced( FORCE_INTERNAL_ASMJIT ) if (HAVE_VULKAN) add_subdirectory( libraries/glslang/glslang) @@ -378,20 +368,7 @@ else() set( BZIP2_LIBRARY bz2 ) endif() -if( GME_FOUND AND NOT FORCE_INTERNAL_GME ) - message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" ) -else() - message( STATUS "Using internal gme library" ) - # Use MAME as it's balanced emulator: well-accurate, but doesn't eats lot of CPU - # Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow - set( GME_YM2612_EMU "MAME" ) - add_subdirectory( libraries/game-music-emu ) - set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/game-music-emu" ) - set( GME_LIBRARIES gme ) -endif() - set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" ) -set( ENET_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/enet" ) set( GDTOA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/gdtoa" ) if( NOT CMAKE_CROSSCOMPILING ) @@ -412,9 +389,7 @@ endif() add_subdirectory( libraries/lzma ) add_subdirectory( tools ) -add_subdirectory( libraries/dumb ) add_subdirectory( libraries/gdtoa ) -add_subdirectory( libraries/enet ) add_subdirectory( wadsrc ) add_subdirectory( source ) add_subdirectory( source/duke3d ) diff --git a/libraries/dumb/CMakeLists.txt b/libraries/dumb/CMakeLists.txt deleted file mode 100644 index 91dd1e51b..000000000 --- a/libraries/dumb/CMakeLists.txt +++ /dev/null @@ -1,121 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -make_release_only() - -include( CheckFunctionExists ) -include( CheckCXXCompilerFlag ) - -set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DDEBUGMODE=1" ) - -if( DEM_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-pointer-sign -Wno-uninitialized" ) - if( CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.5" ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-but-set-variable" ) - endif() -endif() - -# Enable fast flag for dumb -set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DEM_FASTMATH_FLAG}" ) - -CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS ) -if( NOT ITOA_EXISTS ) - add_definitions( -DNEED_ITOA=1 ) -endif() - -include_directories( include ) - -add_library( dumb STATIC - src/core/unload.c - src/core/rendsig.c - src/core/rendduh.c - src/core/register.c - src/core/readduh.c - src/core/rawsig.c - src/core/makeduh.c - src/core/loadduh.c - src/core/dumbfile.c - src/core/duhtag.c - src/core/duhlen.c - src/core/atexit.c - src/helpers/stdfile.c - src/helpers/silence.c - src/helpers/sampbuf.c - src/helpers/riff.c - src/helpers/resample.c - src/helpers/memfile.c - src/helpers/clickrem.c - src/helpers/barray.c - src/it/xmeffect.c - src/it/readxm2.c - src/it/readxm.c - src/it/readstm2.c - src/it/readstm.c - src/it/reads3m2.c - src/it/reads3m.c - src/it/readriff.c - src/it/readptm.c - src/it/readpsm.c - src/it/readoldpsm.c - src/it/readokt2.c - src/it/readokt.c - src/it/readmtm.c - src/it/readmod2.c - src/it/readmod.c - src/it/readdsmf.c - src/it/readasy.c - src/it/readamf2.c - src/it/readamf.c - src/it/readam.c - src/it/read6692.c - src/it/read669.c - src/it/ptmeffect.c - src/it/loadxm2.c - src/it/loadxm.c - src/it/loadstm2.c - src/it/loadstm.c - src/it/loads3m2.c - src/it/loads3m.c - src/it/loadriff2.c - src/it/loadriff.c - src/it/loadptm2.c - src/it/loadptm.c - src/it/loadpsm2.c - src/it/loadpsm.c - src/it/loadoldpsm2.c - src/it/loadoldpsm.c - src/it/loadokt2.c - src/it/loadokt.c - src/it/loadmtm2.c - src/it/loadmtm.c - src/it/loadmod2.c - src/it/loadmod.c - src/it/loadasy2.c - src/it/loadasy.c - src/it/loadamf2.c - src/it/loadamf.c - src/it/load6692.c - src/it/load669.c - src/it/itunload.c - src/it/itrender.c - src/it/itread2.c - src/it/itread.c - src/it/itorder.c - src/it/itmisc.c - src/it/itload2.c - src/it/itload.c - src/it/readany.c - src/it/loadany2.c - src/it/loadany.c - src/it/readany2.c - src/helpers/resampler.c - src/helpers/lpc.c -) -target_link_libraries( dumb ) - -if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - CHECK_CXX_COMPILER_FLAG( -msse DUMB_CAN_USE_SSE ) - - if( DUMB_CAN_USE_SSE ) - set_source_files_properties( src/helpers/resampler.c PROPERTIES COMPILE_FLAGS -msse ) - endif() -endif() diff --git a/libraries/dumb/cmake/CMakeLists.txt b/libraries/dumb/cmake/CMakeLists.txt deleted file mode 100644 index 6cafa7219..000000000 --- a/libraries/dumb/cmake/CMakeLists.txt +++ /dev/null @@ -1,118 +0,0 @@ -cmake_minimum_required(VERSION 2.8.7) -project(libdumb C) - -set(CMAKE_C_FLAGS "-Wall -DDUMB_DECLARE_DEPRECATED -D_USE_SSE -msse -Wno-unused-variable -Wno-unused-but-set-variable") -set(CMAKE_C_FLAGS_DEBUG "-ggdb -DDEBUGMODE=1 -D_DEBUG") -set(CMAKE_C_FLAGS_RELEASE "-ffast-math -O2 -DNDEBUG") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "-ffast-math -g -O2 -DNDEBUG") -set(CMAKE_C_FLAGS_MINSIZEREL "-ffast-math -Os -DNDEBUG") - -link_directories(${CMAKE_CURRENT_BINARY_DIR}) -include_directories(../include/) - -SET(SOURCES - ../src/core/unload.c - ../src/core/rendsig.c - ../src/core/rendduh.c - ../src/core/register.c - ../src/core/readduh.c - ../src/core/rawsig.c - ../src/core/makeduh.c - ../src/core/loadduh.c - ../src/core/dumbfile.c - ../src/core/duhtag.c - ../src/core/duhlen.c - ../src/core/atexit.c - ../src/helpers/stdfile.c - ../src/helpers/silence.c - ../src/helpers/sampbuf.c - ../src/helpers/riff.c - ../src/helpers/resample.c - ../src/helpers/memfile.c - ../src/helpers/clickrem.c - ../src/helpers/barray.c - ../src/helpers/tarray.c - ../src/it/xmeffect.c - ../src/it/readxm2.c - ../src/it/readxm.c - ../src/it/readstm2.c - ../src/it/readstm.c - ../src/it/reads3m2.c - ../src/it/reads3m.c - ../src/it/readriff.c - ../src/it/readptm.c - ../src/it/readpsm.c - ../src/it/readoldpsm.c - ../src/it/readokt2.c - ../src/it/readokt.c - ../src/it/readmtm.c - ../src/it/readmod2.c - ../src/it/readmod.c - ../src/it/readdsmf.c - ../src/it/readasy.c - ../src/it/readamf2.c - ../src/it/readamf.c - ../src/it/readam.c - ../src/it/read6692.c - ../src/it/read669.c - ../src/it/ptmeffect.c - ../src/it/loadxm2.c - ../src/it/loadxm.c - ../src/it/loadstm2.c - ../src/it/loadstm.c - ../src/it/loads3m2.c - ../src/it/loads3m.c - ../src/it/loadriff2.c - ../src/it/loadriff.c - ../src/it/loadptm2.c - ../src/it/loadptm.c - ../src/it/loadpsm2.c - ../src/it/loadpsm.c - ../src/it/loadoldpsm2.c - ../src/it/loadoldpsm.c - ../src/it/loadokt2.c - ../src/it/loadokt.c - ../src/it/loadmtm2.c - ../src/it/loadmtm.c - ../src/it/loadmod2.c - ../src/it/loadmod.c - ../src/it/loadasy2.c - ../src/it/loadasy.c - ../src/it/loadamf2.c - ../src/it/loadamf.c - ../src/it/load6692.c - ../src/it/load669.c - ../src/it/itunload.c - ../src/it/itrender.c - ../src/it/itread2.c - ../src/it/itread.c - ../src/it/itorder.c - ../src/it/itmisc.c - ../src/it/itload2.c - ../src/it/itload.c - ../src/it/readany.c - ../src/it/loadany2.c - ../src/it/loadany.c - ../src/it/readany2.c - ../src/helpers/resampler.c - ../src/helpers/lpc.c -) - -set(INSTALL_HEADERS - ../include/dumb.h -) - -add_library(dumb ${SOURCES}) -set_target_properties(dumb PROPERTIES DEBUG_POSTFIX d) - -# Make sure the dylib install name path is set on OSX so you can include dumb in app bundles -IF(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set_target_properties(dumb PROPERTIES INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) -ENDIF() - -INSTALL(FILES ${INSTALL_HEADERS} DESTINATION include/) -INSTALL(TARGETS dumb - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) diff --git a/libraries/dumb/cmake/readme.txt b/libraries/dumb/cmake/readme.txt deleted file mode 100644 index 32897c797..000000000 --- a/libraries/dumb/cmake/readme.txt +++ /dev/null @@ -1,30 +0,0 @@ -Howto build libdumb with cmake -============================== - -A quick example ---------------- - -In libdumb cmake directory (dumb/cmake/), run: -``` -mkdir -p build -cd build -cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_SHARED_LIBS:BOOL=ON .. -make -make install -``` - -Steps ------ - -1. Create a new temporary build directory and cd into it -2. Run libdumb cmake file with cmake (eg. `cmake -DCMAKE_INSTALL_PREFIX=/install/dir -DBUILD_SHARED_LIBS:BOOL=OFF -DCMAKE_BUILD_TYPE=Release path/to/dumb/cmake/dir`). -3. Run make (eg. just `make` or `mingw32-make` or something). -4. If needed, run make install. - -Flags ------ - -* CMAKE_INSTALL_PREFIX sets the installation path prefix -* CMAKE_BUILD_TYPE sets the build type (eg. Release, Debug, RelWithDebInfo, MinSizeRel). Debug libraries will be named libdumbd, release libraries libdumb. -* BUILD_SHARED_LIBS selects whether cmake should build dynamic or static library (On=shared, OFF=static) -* You may also need to tell cmake what kind of makefiles to create with the "-G" flag. Eg. for MSYS one would say something like `cmake -G "MSYS Makefiles" .`. diff --git a/libraries/dumb/include/dumb.h b/libraries/dumb/include/dumb.h deleted file mode 100644 index 8ac820229..000000000 --- a/libraries/dumb/include/dumb.h +++ /dev/null @@ -1,811 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * dumb.h - The user header file for DUMB. / / \ \ - * | < / \_ - * Include this file in any of your files in | \/ /\ / - * which you wish to use the DUMB functions \_ / > / - * and variables. | \ / / - * | ' / - * Allegro users, you will probably want aldumb.h. \__/ - */ - -#ifndef DUMB_H -#define DUMB_H - - -#include -#include - -#if defined(_DEBUG) && defined(_MSC_VER) -#ifndef _CRTDBG_MAP_ALLOC -//#define _CRTDBG_MAP_ALLOC -#endif -#include -#endif - -#ifdef __cplusplus - extern "C" { -#endif - - -#define DUMB_MAJOR_VERSION 1 -#define DUMB_MINOR_VERSION 0 -#define DUMB_REVISION_VERSION 0 - -#define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION) - -#define DUMB_VERSION_STR "1.0.0" - -#define DUMB_NAME "DUMB v" DUMB_VERSION_STR - -#define DUMB_YEAR 2015 -#define DUMB_MONTH 1 -#define DUMB_DAY 17 - -#define DUMB_YEAR_STR2 "15" -#define DUMB_YEAR_STR4 "2015" -#define DUMB_MONTH_STR1 "1" -#define DUMB_DAY_STR1 "17" - -#if DUMB_MONTH < 10 -#define DUMB_MONTH_STR2 "0" DUMB_MONTH_STR1 -#else -#define DUMB_MONTH_STR2 DUMB_MONTH_STR1 -#endif - -#if DUMB_DAY < 10 -#define DUMB_DAY_STR2 "0" DUMB_DAY_STR1 -#else -#define DUMB_DAY_STR2 DUMB_DAY_STR1 -#endif - - -/* WARNING: The month and day were inadvertently swapped in the v0.8 release. - * Please do not compare this constant against any date in 2002. In - * any case, DUMB_VERSION is probably more useful for this purpose. - */ -#define DUMB_DATE (DUMB_YEAR*10000 + DUMB_MONTH*100 + DUMB_DAY) - -#define DUMB_DATE_STR DUMB_DAY_STR1 "." DUMB_MONTH_STR1 "." DUMB_YEAR_STR4 - - -#undef MIN -#undef MAX -#undef MID - -#define MIN(x,y) (((x) < (y)) ? (x) : (y)) -#define MAX(x,y) (((x) > (y)) ? (x) : (y)) -#define MID(x,y,z) MAX((x), MIN((y), (z))) - -#undef ABS -#define ABS(x) (((x) >= 0) ? (x) : (-(x))) - - -#ifdef DEBUGMODE - -#ifndef ASSERT -#include -#define ASSERT(n) assert(n) -#endif -#ifndef TRACE -// it would be nice if this did actually trace ... -#define TRACE 1 ? (void)0 : (void)printf -#endif - -#else - -#ifndef ASSERT -#define ASSERT(n) -#endif -#ifndef TRACE -#define TRACE 1 ? (void)0 : (void)printf -#endif - -#endif - - -#define DUMB_ID(a,b,c,d) (((unsigned int)(a) << 24) | \ - ((unsigned int)(b) << 16) | \ - ((unsigned int)(c) << 8) | \ - ((unsigned int)(d) )) - - -#ifdef __DOS__ -typedef long int32; -typedef unsigned long uint32; -typedef signed long sint32; -#else -typedef int int32; -typedef unsigned int uint32; -typedef signed int sint32; -#endif - -#define CDECL -#ifndef LONG_LONG -#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__ -#define LONG_LONG long long -#elif defined _MSC_VER || defined __WATCOMC__ -#define LONG_LONG __int64 -#undef CDECL -#define CDECL __cdecl -#elif defined __sgi -#define LONG_LONG long long -#else -#error 64-bit integer type unknown -#endif -#endif - -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 301 /* GCC 3.1+ */ -#ifndef DUMB_DECLARE_DEPRECATED -#define DUMB_DECLARE_DEPRECATED -#endif -#define DUMB_DEPRECATED __attribute__((__deprecated__)) -#else -#define DUMB_DEPRECATED -#endif - -#define DUMBEXPORT CDECL -#define DUMBCALLBACK CDECL - -/* Basic Sample Type. Normal range is -0x800000 to 0x7FFFFF. */ - -typedef int sample_t; - - -/* Library Clean-up Management */ - -int dumb_atexit(void (*proc)(void)); - -void dumb_exit(void); - - -/* File Input Functions */ - -typedef struct DUMBFILE_SYSTEM -{ - void *(DUMBCALLBACK *open)(const char *filename); - int (DUMBCALLBACK *skip)(void *f, long n); - int (DUMBCALLBACK *getc)(void *f); - int32 (DUMBCALLBACK *getnc)(char *ptr, int32 n, void *f); - void (DUMBCALLBACK *close)(void *f); - int (DUMBCALLBACK *seek)(void *f, long n); - long (DUMBCALLBACK *get_size)(void *f); -} -DUMBFILE_SYSTEM; - -typedef struct DUMBFILE DUMBFILE; - -void DUMBEXPORT register_dumbfile_system(const DUMBFILE_SYSTEM *dfs); - -DUMBFILE *DUMBEXPORT dumbfile_open(const char *filename); -DUMBFILE *DUMBEXPORT dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs); - -int32 DUMBEXPORT dumbfile_pos(DUMBFILE *f); -int DUMBEXPORT dumbfile_skip(DUMBFILE *f, long n); - -#define DFS_SEEK_SET 0 -#define DFS_SEEK_CUR 1 -#define DFS_SEEK_END 2 - -int DUMBEXPORT dumbfile_seek(DUMBFILE *f, long n, int origin); - -int32 DUMBEXPORT dumbfile_get_size(DUMBFILE *f); - -int DUMBEXPORT dumbfile_getc(DUMBFILE *f); - -int DUMBEXPORT dumbfile_igetw(DUMBFILE *f); -int DUMBEXPORT dumbfile_mgetw(DUMBFILE *f); - -int32 DUMBEXPORT dumbfile_igetl(DUMBFILE *f); -int32 DUMBEXPORT dumbfile_mgetl(DUMBFILE *f); - -uint32 DUMBEXPORT dumbfile_cgetul(DUMBFILE *f); -sint32 DUMBEXPORT dumbfile_cgetsl(DUMBFILE *f); - -int32 DUMBEXPORT dumbfile_getnc(char *ptr, int32 n, DUMBFILE *f); - -int DUMBEXPORT dumbfile_error(DUMBFILE *f); -int DUMBEXPORT dumbfile_close(DUMBFILE *f); - - -/* stdio File Input Module */ - -void DUMBEXPORT dumb_register_stdfiles(void); - -DUMBFILE *DUMBEXPORT dumbfile_open_stdfile(FILE *p); - - -/* Memory File Input Module */ - -DUMBFILE *DUMBEXPORT dumbfile_open_memory(const char *data, int32 size); - - -/* DUH Management */ - -typedef struct DUH DUH; - -#define DUH_SIGNATURE DUMB_ID('D','U','H','!') - -void DUMBEXPORT unload_duh(DUH *duh); - -DUH *DUMBEXPORT load_duh(const char *filename); -DUH *DUMBEXPORT read_duh(DUMBFILE *f); - -int32 DUMBEXPORT duh_get_length(DUH *duh); - -const char *DUMBEXPORT duh_get_tag(DUH *duh, const char *key); - -/* Signal Rendering Functions */ - -typedef struct DUH_SIGRENDERER DUH_SIGRENDERER; - -DUH_SIGRENDERER *DUMBEXPORT duh_start_sigrenderer(DUH *duh, int sig, int n_channels, int32 pos); - -#ifdef DUMB_DECLARE_DEPRECATED -typedef void (*DUH_SIGRENDERER_CALLBACK)(void *data, sample_t **samples, int n_channels, int32 length); -/* This is deprecated, but is not marked as such because GCC tends to - * complain spuriously when the typedef is used later. See comments below. - */ - -void duh_sigrenderer_set_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_CALLBACK callback, void *data -) DUMB_DEPRECATED; -/* The 'callback' argument's type has changed for const-correctness. See the - * DUH_SIGRENDERER_CALLBACK definition just above. Also note that the samples - * in the buffer are now 256 times as large; the normal range is -0x800000 to - * 0x7FFFFF. The function has been renamed partly because its functionality - * has changed slightly and partly so that its name is more meaningful. The - * new one is duh_sigrenderer_set_analyser_callback(), and the typedef for - * the function pointer has also changed, from DUH_SIGRENDERER_CALLBACK to - * DUH_SIGRENDERER_ANALYSER_CALLBACK. (If you wanted to use this callback to - * apply a DSP effect, don't worry; there is a better way of doing this. It - * is undocumented, so contact me and I shall try to help. Contact details - * are in readme.txt.) - */ - -typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, int32 length); -/* This is deprecated, but is not marked as such because GCC tends to - * complain spuriously when the typedef is used later. See comments below. - */ - -void duh_sigrenderer_set_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data -) DUMB_DEPRECATED; -/* This is deprecated because the meaning of the 'samples' parameter in the - * callback needed to change. For stereo applications, the array used to be - * indexed with samples[channel][pos]. It is now indexed with - * samples[0][pos*2+channel]. Mono sample data are still indexed with - * samples[0][pos]. The array is still 2D because samples will probably only - * ever be interleaved in twos. In order to fix your code, adapt it to the - * new sample layout and then call - * duh_sigrenderer_set_sample_analyser_callback below instead of this - * function. - */ -#endif - -typedef void (*DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, int32 length); - -void duh_sigrenderer_set_sample_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data -); - -int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer); -int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer); - -void DUMBEXPORT duh_sigrenderer_set_sigparam(DUH_SIGRENDERER *sigrenderer, unsigned char id, int32 value); - -#ifdef DUMB_DECLARE_DEPRECATED -int32 duh_sigrenderer_get_samples( - DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - int32 size, sample_t **samples -) DUMB_DEPRECATED; -/* The sample format has changed, so if you were using this function, - * you should switch to duh_sigrenderer_generate_samples() and change - * how you interpret the samples array. See the comments for - * duh_sigrenderer_set_analyser_callback(). - */ -#endif - -int32 DUMBEXPORT duh_sigrenderer_generate_samples( - DUH_SIGRENDERER *sigrenderer, - double volume, double delta, - int32 size, sample_t **samples -); - -void DUMBEXPORT duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples); - -void DUMBEXPORT duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer); - - -/* DUH Rendering Functions */ - -int32 DUMBEXPORT duh_render( - DUH_SIGRENDERER *sigrenderer, - int bits, int unsign, - float volume, float delta, - int32 size, void *sptr -); - -#ifdef DUMB_DECLARE_DEPRECATED - -int32 duh_render_signal( - DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - int32 size, sample_t **samples -) DUMB_DEPRECATED; -/* Please use duh_sigrenderer_generate_samples(), and see the - * comments for the deprecated duh_sigrenderer_get_samples() too. - */ - -typedef DUH_SIGRENDERER DUH_RENDERER DUMB_DEPRECATED; -/* Please use DUH_SIGRENDERER instead of DUH_RENDERER. */ - -DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, int32 pos) DUMB_DEPRECATED; -/* Please use duh_start_sigrenderer() instead. Pass 0 for 'sig'. */ - -int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) DUMB_DEPRECATED; -int32 duh_renderer_get_position(DUH_SIGRENDERER *dr) DUMB_DEPRECATED; -/* Please use the duh_sigrenderer_*() equivalents of these two functions. */ - -void duh_end_renderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED; -/* Please use duh_end_sigrenderer() instead. */ - -DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) DUMB_DEPRECATED; -DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED; -DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) DUMB_DEPRECATED; -/* These functions have become no-ops that just return the parameter. - * So, for instance, replace - * duh_renderer_encapsulate_sigrenderer(my_sigrenderer) - * with - * my_sigrenderer - */ - -#endif - - -/* Impulse Tracker Support */ - -extern int dumb_it_max_to_mix; - -typedef struct DUMB_IT_SIGDATA DUMB_IT_SIGDATA; -typedef struct DUMB_IT_SIGRENDERER DUMB_IT_SIGRENDERER; - -DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh); -DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, int32 pos); -DUMB_IT_SIGRENDERER *DUMBEXPORT duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer); - -int DUMBEXPORT dumb_it_trim_silent_patterns(DUH * duh); - -typedef int (*dumb_scan_callback)(void *, int, int32); -int DUMBEXPORT dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void * callback_data); - -DUH_SIGRENDERER *DUMBEXPORT dumb_it_start_at_order(DUH *duh, int n_channels, int startorder); - -enum -{ - DUMB_IT_RAMP_NONE = 0, - DUMB_IT_RAMP_ONOFF_ONLY = 1, - DUMB_IT_RAMP_FULL = 2 -}; - -void DUMBEXPORT dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER * sigrenderer, int ramp_style); - -void DUMBEXPORT dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data); -void DUMBEXPORT dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data); -void DUMBEXPORT dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data, int channel, unsigned char midi_byte), void *data); -void DUMBEXPORT dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data); - -int DUMBCALLBACK dumb_it_callback_terminate(void *data); -int DUMBCALLBACK dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte); - -/* dumb_*_mod*: restrict_ |= 1-Don't read 15 sample files / 2-Use old pattern counting method */ - -DUH *DUMBEXPORT dumb_load_it(const char *filename); -DUH *DUMBEXPORT dumb_load_xm(const char *filename); -DUH *DUMBEXPORT dumb_load_s3m(const char *filename); -DUH *DUMBEXPORT dumb_load_stm(const char *filename); -DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict_); -DUH *DUMBEXPORT dumb_load_ptm(const char *filename); -DUH *DUMBEXPORT dumb_load_669(const char *filename); -DUH *DUMBEXPORT dumb_load_psm(const char *filename, int subsong); -DUH *DUMBEXPORT dumb_load_old_psm(const char * filename); -DUH *DUMBEXPORT dumb_load_mtm(const char *filename); -DUH *DUMBEXPORT dumb_load_riff(const char *filename); -DUH *DUMBEXPORT dumb_load_asy(const char *filename); -DUH *DUMBEXPORT dumb_load_amf(const char *filename); -DUH *DUMBEXPORT dumb_load_okt(const char *filename); - -DUH *DUMBEXPORT dumb_read_it(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_xm(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_s3m(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_stm(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict_); -DUH *DUMBEXPORT dumb_read_ptm(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_669(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_psm(DUMBFILE *f, int subsong); -DUH *DUMBEXPORT dumb_read_old_psm(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_mtm(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_riff(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_asy(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_amf(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f); - -DUH *DUMBEXPORT dumb_load_it_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_xm_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_s3m_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_stm_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict_); -DUH *DUMBEXPORT dumb_load_ptm_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_669_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_psm_quick(const char *filename, int subsong); -DUH *DUMBEXPORT dumb_load_old_psm_quick(const char * filename); -DUH *DUMBEXPORT dumb_load_mtm_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_riff_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_asy_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_amf_quick(const char *filename); -DUH *DUMBEXPORT dumb_load_okt_quick(const char *filename); - -DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_xm_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_s3m_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int restrict_); -DUH *DUMBEXPORT dumb_read_ptm_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_669_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong); -DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_riff_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_amf_quick(DUMBFILE *f); -DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f); - -DUH *DUMBEXPORT dumb_read_any_quick(DUMBFILE *f, int restrict_, int subsong); -DUH *DUMBEXPORT dumb_read_any(DUMBFILE *f, int restrict_, int subsong); - -DUH *DUMBEXPORT dumb_load_any_quick(const char *filename, int restrict_, int subsong); -DUH *DUMBEXPORT dumb_load_any(const char *filename, int restrict_, int subsong); - -int32 DUMBEXPORT dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder); -void DUMBEXPORT dumb_it_do_initial_runthrough(DUH *duh); - -int DUMBEXPORT dumb_get_psm_subsong_count(DUMBFILE *f); - -const unsigned char *DUMBEXPORT dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd); - -int DUMBEXPORT dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd); -int DUMBEXPORT dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd); -int DUMBEXPORT dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd); - -const unsigned char *DUMBEXPORT dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i); -const unsigned char *DUMBEXPORT dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i); -const unsigned char *DUMBEXPORT dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i); -const unsigned char *DUMBEXPORT dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i); - -int DUMBEXPORT dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd); -void DUMBEXPORT dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv); - -int DUMBEXPORT dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd); -void DUMBEXPORT dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv); - -int DUMBEXPORT dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd); -void DUMBEXPORT dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed); - -int DUMBEXPORT dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd); -void DUMBEXPORT dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo); - -int DUMBEXPORT dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel); -void DUMBEXPORT dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume); - -int DUMBEXPORT dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr); -int DUMBEXPORT dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr); - -int DUMBEXPORT dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr); -void DUMBEXPORT dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv); - -int DUMBEXPORT dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr); -void DUMBEXPORT dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo); - -int DUMBEXPORT dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr); -void DUMBEXPORT dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed); - -#define DUMB_IT_N_CHANNELS 64 -#define DUMB_IT_N_NNA_CHANNELS 192 -#define DUMB_IT_TOTAL_CHANNELS (DUMB_IT_N_CHANNELS + DUMB_IT_N_NNA_CHANNELS) - -/* Channels passed to any of these functions are 0-based */ -int DUMBEXPORT dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel); -void DUMBEXPORT dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume); - -int DUMBEXPORT dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel); -void DUMBEXPORT dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted); - -typedef struct DUMB_IT_CHANNEL_STATE DUMB_IT_CHANNEL_STATE; - -struct DUMB_IT_CHANNEL_STATE -{ - int channel; /* 0-based; meaningful for NNA channels */ - int sample; /* 1-based; 0 if nothing playing, then other fields undef */ - int freq; /* in Hz */ - float volume; /* 1.0 maximum; affected by ALL factors, inc. mixing vol */ - unsigned char pan; /* 0-64, 100 for surround */ - signed char subpan; /* use (pan + subpan/256.0f) or ((pan<<8)+subpan) */ - unsigned char filter_cutoff; /* 0-127 cutoff=127 AND resonance=0 */ - unsigned char filter_subcutoff; /* 0-255 -> no filters (subcutoff */ - unsigned char filter_resonance; /* 0-127 always 0 in this case) */ - /* subcutoff only changes from zero if filter envelopes are in use. The - * calculation (filter_cutoff + filter_subcutoff/256.0f) gives a more - * accurate filter cutoff measurement as a float. It would often be more - * useful to use a scaled int such as ((cutoff<<8) + subcutoff). - */ -}; - -/* Values of 64 or more will access NNA channels here. */ -void DUMBEXPORT dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state); - - -/* Signal Design Helper Values */ - -/* Use pow(DUMB_SEMITONE_BASE, n) to get the 'delta' value to transpose up by - * n semitones. To transpose down, use negative n. - */ -#define DUMB_SEMITONE_BASE 1.059463094359295309843105314939748495817 - -/* Use pow(DUMB_QUARTERTONE_BASE, n) to get the 'delta' value to transpose up - * by n quartertones. To transpose down, use negative n. - */ -#define DUMB_QUARTERTONE_BASE 1.029302236643492074463779317738953977823 - -/* Use pow(DUMB_PITCH_BASE, n) to get the 'delta' value to transpose up by n - * units. In this case, 256 units represent one semitone; 3072 units - * represent one octave. These units are used by the sequence signal (SEQU). - */ -#define DUMB_PITCH_BASE 1.000225659305069791926712241547647863626 - - -/* Signal Design Function Types */ - -typedef void sigdata_t; -typedef void sigrenderer_t; - -typedef sigdata_t *(*DUH_LOAD_SIGDATA)(DUH *duh, DUMBFILE *file); - -typedef sigrenderer_t *(*DUH_START_SIGRENDERER)( - DUH *duh, - sigdata_t *sigdata, - int n_channels, - int32 pos -); - -typedef void (*DUH_SIGRENDERER_SET_SIGPARAM)( - sigrenderer_t *sigrenderer, - unsigned char id, int32 value -); - -typedef int32 (*DUH_SIGRENDERER_GENERATE_SAMPLES)( - sigrenderer_t *sigrenderer, - double volume, double delta, - int32 size, sample_t **samples -); - -typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)( - sigrenderer_t *sigrenderer, - double volume, - sample_t *samples -); - -typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer); - -typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata); - - -/* Signal Design Function Registration */ - -typedef struct DUH_SIGTYPE_DESC -{ - int32 type; - DUH_LOAD_SIGDATA load_sigdata; - DUH_START_SIGRENDERER start_sigrenderer; - DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam; - DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples; - DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample; - DUH_END_SIGRENDERER end_sigrenderer; - DUH_UNLOAD_SIGDATA unload_sigdata; -} -DUH_SIGTYPE_DESC; - -void DUMBEXPORT dumb_register_sigtype(DUH_SIGTYPE_DESC *desc); - - -// Decide where to put these functions; new heading? - -sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type); - -DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, int32 pos); -sigrenderer_t *DUMBEXPORT duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type); - -int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata); - - -/* Standard Signal Types */ - -//void dumb_register_sigtype_sample(void); - - -/* Sample Buffer Allocation Helpers */ - -#ifdef DUMB_DECLARE_DEPRECATED -sample_t **create_sample_buffer(int n_channels, int32 length) DUMB_DEPRECATED; -/* DUMB has been changed to interleave stereo samples. Use - * allocate_sample_buffer() instead, and see the comments for - * duh_sigrenderer_set_analyser_callback(). - */ -#endif -sample_t **DUMBEXPORT allocate_sample_buffer(int n_channels, int32 length); -void DUMBEXPORT destroy_sample_buffer(sample_t **samples); - - -/* Silencing Helper */ - -void DUMBEXPORT dumb_silence(sample_t *samples, int32 length); - - -/* Click Removal Helpers */ - -typedef struct DUMB_CLICK_REMOVER DUMB_CLICK_REMOVER; - -DUMB_CLICK_REMOVER *DUMBEXPORT dumb_create_click_remover(void); -void DUMBEXPORT dumb_record_click(DUMB_CLICK_REMOVER *cr, int32 pos, sample_t step); -void DUMBEXPORT dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, int32 length, int step, double halflife); -sample_t DUMBEXPORT dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr); -void DUMBEXPORT dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr); - -DUMB_CLICK_REMOVER **DUMBEXPORT dumb_create_click_remover_array(int n); -void DUMBEXPORT dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step); -void DUMBEXPORT dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step); -void DUMBEXPORT dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, int32 length, double halflife); -void DUMBEXPORT dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset); -void DUMBEXPORT dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr); - - -/* Resampling Helpers */ - -#define DUMB_RQ_ALIASING 0 -#define DUMB_LQ_LINEAR 1 -#define DUMB_LQ_CUBIC 2 - -#define DUMB_RQ_BLEP 3 -#define DUMB_RQ_LINEAR 4 -#define DUMB_RQ_BLAM 5 -#define DUMB_RQ_CUBIC 6 -#define DUMB_RQ_FIR 7 -#define DUMB_RQ_N_LEVELS 8 - -/* Subtract quality above by this to convert to resampler.c's quality */ -#define DUMB_RESAMPLER_BASE 2 - -extern int dumb_resampling_quality; /* This specifies the default */ -void DUMBEXPORT dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality); /* This overrides it */ - -typedef struct DUMB_RESAMPLER DUMB_RESAMPLER; - -typedef struct DUMB_VOLUME_RAMP_INFO DUMB_VOLUME_RAMP_INFO; - -typedef void (*DUMB_RESAMPLE_PICKUP)(DUMB_RESAMPLER *resampler, void *data); - -struct DUMB_RESAMPLER -{ - void *src; - int32 pos; - int subpos; - int32 start, end; - int dir; - DUMB_RESAMPLE_PICKUP pickup; - void *pickup_data; - int quality; - /* Everything below this point is internal: do not use. */ - union { - sample_t x24[3*2]; - short x16[3*2]; - signed char x8[3*2]; - } x; - int overshot; - double fir_resampler_ratio; - void* fir_resampler[2]; -}; - -struct DUMB_VOLUME_RAMP_INFO -{ - float volume; - float delta; - float target; - float mix; - unsigned char declick_stage; -}; - -void dumb_reset_resampler(DUMB_RESAMPLER *resampler, sample_t *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -DUMB_RESAMPLER *dumb_start_resampler(sample_t *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -//int32 dumb_resample_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta); -int32 dumb_resample_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//int32 dumb_resample_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -int32 dumb_resample_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//void dumb_resample_get_current_sample_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst); -void dumb_resample_get_current_sample_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -//void dumb_resample_get_current_sample_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_resample_get_current_sample_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_end_resampler(DUMB_RESAMPLER *resampler); - -void dumb_reset_resampler_16(DUMB_RESAMPLER *resampler, short *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -DUMB_RESAMPLER *dumb_start_resampler_16(short *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -//int32 dumb_resample_16_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta); -int32 dumb_resample_16_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//int32 dumb_resample_16_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -int32 dumb_resample_16_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//void dumb_resample_get_current_sample_16_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst); -void dumb_resample_get_current_sample_16_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -//void dumb_resample_get_current_sample_16_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_resample_get_current_sample_16_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_end_resampler_16(DUMB_RESAMPLER *resampler); - -void dumb_reset_resampler_8(DUMB_RESAMPLER *resampler, signed char *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -DUMB_RESAMPLER *dumb_start_resampler_8(signed char *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -//int32 dumb_resample_8_1_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta); -int32 dumb_resample_8_1_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//int32 dumb_resample_8_2_1(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -int32 dumb_resample_8_2_2(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//void dumb_resample_get_current_sample_8_1_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst); -void dumb_resample_get_current_sample_8_1_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -//void dumb_resample_get_current_sample_8_2_1(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_resample_get_current_sample_8_2_2(DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_end_resampler_8(DUMB_RESAMPLER *resampler); - -void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, int32 pos, int32 start, int32 end, int quality); -//int32 dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta); -int32 dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//int32 dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -int32 dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta); -//void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst); -void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -//void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst); -void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler); - -/* This sets the default panning separation for hard panned formats, - or for formats with default panning information. This must be set - before using any readers or loaders, and is not really thread safe. */ - -extern int dumb_it_default_panning_separation; /* in percent, default 25 */ - -/* DUH Construction */ - -DUH *make_duh( - int32 length, - int n_tags, - const char *const tag[][2], - int n_signals, - DUH_SIGTYPE_DESC *desc[], - sigdata_t *sigdata[] -); - -void DUMBEXPORT duh_set_length(DUH *duh, int32 length); - - -#ifdef __cplusplus - } -#endif - - -#endif /* DUMB_H */ diff --git a/libraries/dumb/include/internal/aldumb.h b/libraries/dumb/include/internal/aldumb.h deleted file mode 100644 index a0c6d63c0..000000000 --- a/libraries/dumb/include/internal/aldumb.h +++ /dev/null @@ -1,27 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * internal/aldumb.h - The internal header file / / \ \ - * for DUMB with Allegro. | < / \_ - * | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#ifndef INTERNAL_ALDUMB_H -#define INTERNAL_ALDUMB_H - - -void _dat_unload_duh(void *duh); - - -#endif /* INTERNAL_DUMB_H */ diff --git a/libraries/dumb/include/internal/barray.h b/libraries/dumb/include/internal/barray.h deleted file mode 100644 index de9fab70c..000000000 --- a/libraries/dumb/include/internal/barray.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _B_ARRAY_H_ -#define _B_ARRAY_H_ - -#include - -#ifdef BARRAY_DECORATE -#define PASTE(a,b) a ## b -#define EVALUATE(a,b) PASTE(a,b) -#define bit_array_create EVALUATE(BARRAY_DECORATE,_bit_array_create) -#define bit_array_destroy EVALUATE(BARRAY_DECORATE,_bit_array_destroy) -#define bit_array_dup EVALUATE(BARRAY_DECORATE,_bit_array_dup) -#define bit_array_reset EVALUATE(BARRAY_DECORATE,_bit_array_reset) -#define bit_array_set EVALUATE(BARRAY_DECORATE,_bit_array_set) -#define bit_array_set_range EVALUATE(BARRAY_DECORATE,_bit_array_set_range) -#define bit_array_test EVALUATE(BARRAY_DECORATE,_bit_array_test) -#define bit_array_test_range EVALUATE(BARRAY_DECORATE,_bit_array_test_range) -#define bit_array_clear EVALUATE(BARRAY_DECORATE,_bit_array_clear) -#define bit_array_clear_range EVALUATE(BARRAY_DECORATE,_bit_array_clear_range) -#define bit_array_merge EVALUATE(BARRAY_DECORATE,_bit_array_merge) -#define bit_array_mask EVALUATE(BARRAY_DECORATE,_bit_array_mask) -#endif - -void * bit_array_create(size_t size); -void bit_array_destroy(void * array); -void * bit_array_dup(void * array); - -void bit_array_reset(void * array); - -void bit_array_set(void * array, size_t bit); -void bit_array_set_range(void * array, size_t bit, size_t count); - -int bit_array_test(void * array, size_t bit); -int bit_array_test_range(void * array, size_t bit, size_t count); - -void bit_array_clear(void * array, size_t bit); -void bit_array_clear_range(void * array, size_t bit, size_t count); - -void bit_array_merge(void * array, void * source, size_t offset); -void bit_array_mask(void * array, void * source, size_t offset); - -#endif diff --git a/libraries/dumb/include/internal/dumb.h b/libraries/dumb/include/internal/dumb.h deleted file mode 100644 index bb2fe5c1c..000000000 --- a/libraries/dumb/include/internal/dumb.h +++ /dev/null @@ -1,61 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * internal/dumb.h - DUMB's internal declarations. / / \ \ - * | < / \_ - * This header file provides access to the | \/ /\ / - * internal structure of DUMB, and is liable \_ / > / - * to change, mutate or cease to exist at any | \ / / - * moment. Include it at your own peril. | ' / - * \__/ - * ... - * - * Seriously. You don't need access to anything in this file. All right, you - * probably do actually. But if you use it, you will be relying on a specific - * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please - * contact the authors so that we can provide a public API for what you need. - */ - -#ifndef INTERNAL_DUMB_H -#define INTERNAL_DUMB_H - - -typedef struct DUH_SIGTYPE_DESC_LINK -{ - struct DUH_SIGTYPE_DESC_LINK *next; - DUH_SIGTYPE_DESC *desc; -} -DUH_SIGTYPE_DESC_LINK; - - -typedef struct DUH_SIGNAL -{ - sigdata_t *sigdata; - DUH_SIGTYPE_DESC *desc; -} -DUH_SIGNAL; - - -struct DUH -{ - int32 length; - - int n_tags; - char *(*tag)[2]; - - int n_signals; - DUH_SIGNAL **signal; -}; - - -DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(int32 type); - - -#endif /* INTERNAL_DUMB_H */ diff --git a/libraries/dumb/include/internal/dumbfile.h b/libraries/dumb/include/internal/dumbfile.h deleted file mode 100644 index c83cc9a00..000000000 --- a/libraries/dumb/include/internal/dumbfile.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef DUMBFILE_H -#define DUMBFILE_H - -#include "../dumb.h" - -struct DUMBFILE -{ - const DUMBFILE_SYSTEM *dfs; - void *file; - long pos; -}; - -#endif // DUMBFILE_H diff --git a/libraries/dumb/include/internal/it.h b/libraries/dumb/include/internal/it.h deleted file mode 100644 index b5806223b..000000000 --- a/libraries/dumb/include/internal/it.h +++ /dev/null @@ -1,914 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * internal/it.h - Internal stuff for IT playback / / \ \ - * and MOD/XM/S3M conversion. | < / \_ - * | \/ /\ / - * This header file provides access to the \_ / > / - * internal structure of DUMB, and is liable | \ / / - * to change, mutate or cease to exist at any | ' / - * moment. Include it at your own peril. \__/ - * - * ... - * - * Seriously. You don't need access to anything in this file. All right, you - * probably do actually. But if you use it, you will be relying on a specific - * version of DUMB, so please check DUMB_VERSION defined in dumb.h. Please - * contact the authors so that we can provide a public API for what you need. - */ - -#ifndef INTERNAL_IT_H -#define INTERNAL_IT_H - - -#define BIT_ARRAY_BULLSHIT - -#include - -#include "barray.h" - - -/** TO DO: THINK ABOUT THE FOLLOWING: - -sigdata->flags & IT_COMPATIBLE_GXX - - Bit 5: On = Link Effect G's memory with Effect E/F. Also - Gxx with an instrument present will cause the - envelopes to be retriggered. If you change a - sample on a row with Gxx, it'll adjust the - frequency of the current note according to: - - NewFrequency = OldFrequency * NewC5 / OldC5; -*/ - - - -/* These #defines are TEMPORARY. They are used to write alternative code to - * handle ambiguities in the format specification. The correct code in each - * case will be determined most likely by experimentation. - */ -//#define STEREO_SAMPLES_COUNT_AS_TWO -#define INVALID_ORDERS_END_SONG -#define SUSTAIN_LOOP_OVERRIDES_NORMAL_LOOP -#define VOLUME_OUT_OF_RANGE_SETS_MAXIMUM - - - -#define SIGTYPE_IT DUMB_ID('I', 'T', ' ', ' ') - -#define IT_SIGNATURE DUMB_ID('I', 'M', 'P', 'M') -#define IT_INSTRUMENT_SIGNATURE DUMB_ID('I', 'M', 'P', 'I') -#define IT_SAMPLE_SIGNATURE DUMB_ID('I', 'M', 'P', 'S') - -// olivier sux -#define IT_MPTX_SIGNATURE DUMB_ID('X', 'T', 'P', 'M') -#define IT_INSM_SIGNATURE DUMB_ID('M', 'S', 'N', 'I') - - -/* This is divided by the tempo times 256 to get the interval between ticks. - */ -#define TICK_TIME_DIVIDEND (65536 * 5 * 128) - - - -/* I'm not going to try to explain this, because I didn't derive it very - * formally ;) - */ -/* #define AMIGA_DIVISOR ((float)(4.0 * 14317056.0)) */ -/* I believe the following one to be more accurate. */ -//#define AMIGA_DIVISOR ((float)(8.0 * 7159090.5)) -#define AMIGA_CLOCK 3546895 -#define AMIGA_DIVISOR ((float)(16.0 * AMIGA_CLOCK)) - - - -typedef struct IT_MIDI IT_MIDI; -typedef struct IT_FILTER_STATE IT_FILTER_STATE; -typedef struct IT_ENVELOPE IT_ENVELOPE; -typedef struct IT_INSTRUMENT IT_INSTRUMENT; -typedef struct IT_SAMPLE IT_SAMPLE; -typedef struct IT_ENTRY IT_ENTRY; -typedef struct IT_PATTERN IT_PATTERN; -typedef struct IT_PLAYING_ENVELOPE IT_PLAYING_ENVELOPE; -typedef struct IT_PLAYING IT_PLAYING; -typedef struct IT_CHANNEL IT_CHANNEL; -typedef struct IT_CHECKPOINT IT_CHECKPOINT; -typedef struct IT_CALLBACKS IT_CALLBACKS; - - - -struct IT_MIDI -{ - unsigned char SFmacro[16][16]; // read these from 0x120 - unsigned char SFmacrolen[16]; - unsigned short SFmacroz[16]; /* Bitfield; bit 0 set = z in first position */ - unsigned char Zmacro[128][16]; // read these from 0x320 - unsigned char Zmacrolen[128]; -}; - - - -struct IT_FILTER_STATE -{ - sample_t currsample, prevsample; -}; - - - -#define IT_ENVELOPE_ON 1 -#define IT_ENVELOPE_LOOP_ON 2 -#define IT_ENVELOPE_SUSTAIN_LOOP 4 -#define IT_ENVELOPE_CARRY 8 -#define IT_ENVELOPE_PITCH_IS_FILTER 128 - -struct IT_ENVELOPE -{ - unsigned char flags; - unsigned char n_nodes; - unsigned char loop_start; - unsigned char loop_end; - unsigned char sus_loop_start; - unsigned char sus_loop_end; - signed char node_y[25]; - unsigned short node_t[25]; -}; - - - -#define NNA_NOTE_CUT 0 -#define NNA_NOTE_CONTINUE 1 -#define NNA_NOTE_OFF 2 -#define NNA_NOTE_FADE 3 - -#define DCT_OFF 0 -#define DCT_NOTE 1 -#define DCT_SAMPLE 2 -#define DCT_INSTRUMENT 3 - -#define DCA_NOTE_CUT 0 -#define DCA_NOTE_OFF 1 -#define DCA_NOTE_FADE 2 - -struct IT_INSTRUMENT -{ - unsigned char name[27]; - unsigned char filename[14]; - - int fadeout; - - IT_ENVELOPE volume_envelope; - IT_ENVELOPE pan_envelope; - IT_ENVELOPE pitch_envelope; - - unsigned char new_note_action; - unsigned char dup_check_type; - unsigned char dup_check_action; - signed char pp_separation; - unsigned char pp_centre; - unsigned char global_volume; - unsigned char default_pan; - unsigned char random_volume; - unsigned char random_pan; - - unsigned char filter_cutoff; - unsigned char filter_resonance; - - unsigned char map_note[120]; - unsigned short map_sample[120]; - - //int output; -}; - - - -#define IT_SAMPLE_EXISTS 1 -#define IT_SAMPLE_16BIT 2 -#define IT_SAMPLE_STEREO 4 -#define IT_SAMPLE_LOOP 16 -#define IT_SAMPLE_SUS_LOOP 32 -#define IT_SAMPLE_PINGPONG_LOOP 64 -#define IT_SAMPLE_PINGPONG_SUS_LOOP 128 - -#define IT_VIBRATO_SINE 0 -#define IT_VIBRATO_SAWTOOTH 1 -#define IT_VIBRATO_SQUARE 2 -#define IT_VIBRATO_RANDOM 3 -#define IT_VIBRATO_XM_SQUARE 4 -#define IT_VIBRATO_RAMP_DOWN 5 -#define IT_VIBRATO_RAMP_UP 6 - -struct IT_SAMPLE -{ - unsigned char name[35]; - unsigned char filename[15]; - unsigned char flags; - unsigned char global_volume; - unsigned char default_volume; - unsigned char default_pan; - /* default_pan: - * 0-255 for XM - * ignored for MOD - * otherwise, 0-64, and add 128 to enable - */ - - int32 length; - int32 loop_start; - int32 loop_end; - int32 C5_speed; - int32 sus_loop_start; - int32 sus_loop_end; - - unsigned char vibrato_speed; - unsigned char vibrato_depth; - unsigned char vibrato_rate; - unsigned char vibrato_waveform; - - signed short finetune; - - void *data; - - int max_resampling_quality; -}; - - - -#define IT_ENTRY_NOTE 1 -#define IT_ENTRY_INSTRUMENT 2 -#define IT_ENTRY_VOLPAN 4 -#define IT_ENTRY_EFFECT 8 - -#define IT_SET_END_ROW(entry) ((entry)->channel = 255) -#define IT_IS_END_ROW(entry) ((entry)->channel >= DUMB_IT_N_CHANNELS) - -#define IT_NOTE_OFF 255 -#define IT_NOTE_CUT 254 - -#define IT_ENVELOPE_SHIFT 8 - -#define IT_SURROUND 100 -#define IT_IS_SURROUND(pan) ((pan) > 64) -#define IT_IS_SURROUND_SHIFTED(pan) ((pan) > 64 << IT_ENVELOPE_SHIFT) - -#define IT_SET_SPEED 1 -#define IT_JUMP_TO_ORDER 2 -#define IT_BREAK_TO_ROW 3 -#define IT_VOLUME_SLIDE 4 -#define IT_PORTAMENTO_DOWN 5 -#define IT_PORTAMENTO_UP 6 -#define IT_TONE_PORTAMENTO 7 -#define IT_VIBRATO 8 -#define IT_TREMOR 9 -#define IT_ARPEGGIO 10 -#define IT_VOLSLIDE_VIBRATO 11 -#define IT_VOLSLIDE_TONEPORTA 12 -#define IT_SET_CHANNEL_VOLUME 13 -#define IT_CHANNEL_VOLUME_SLIDE 14 -#define IT_SET_SAMPLE_OFFSET 15 -#define IT_PANNING_SLIDE 16 -#define IT_RETRIGGER_NOTE 17 -#define IT_TREMOLO 18 -#define IT_S 19 -#define IT_SET_SONG_TEMPO 20 -#define IT_FINE_VIBRATO 21 -#define IT_SET_GLOBAL_VOLUME 22 -#define IT_GLOBAL_VOLUME_SLIDE 23 -#define IT_SET_PANNING 24 -#define IT_PANBRELLO 25 -#define IT_MIDI_MACRO 26 //see MIDI.TXT - -/* Some effects needed for XM compatibility */ -#define IT_XM_PORTAMENTO_DOWN 27 -#define IT_XM_PORTAMENTO_UP 28 -#define IT_XM_FINE_VOLSLIDE_DOWN 29 -#define IT_XM_FINE_VOLSLIDE_UP 30 -#define IT_XM_RETRIGGER_NOTE 31 -#define IT_XM_KEY_OFF 32 -#define IT_XM_SET_ENVELOPE_POSITION 33 - -/* More effects needed for PTM compatibility */ -#define IT_PTM_NOTE_SLIDE_DOWN 34 -#define IT_PTM_NOTE_SLIDE_UP 35 -#define IT_PTM_NOTE_SLIDE_DOWN_RETRIG 36 -#define IT_PTM_NOTE_SLIDE_UP_RETRIG 37 - -/* More effects needed for OKT compatibility */ -#define IT_OKT_NOTE_SLIDE_DOWN 38 -#define IT_OKT_NOTE_SLIDE_DOWN_ROW 39 -#define IT_OKT_NOTE_SLIDE_UP 40 -#define IT_OKT_NOTE_SLIDE_UP_ROW 41 -#define IT_OKT_ARPEGGIO_3 42 -#define IT_OKT_ARPEGGIO_4 43 -#define IT_OKT_ARPEGGIO_5 44 -#define IT_OKT_VOLUME_SLIDE_DOWN 45 -#define IT_OKT_VOLUME_SLIDE_UP 46 - -#define IT_N_EFFECTS 47 - -/* These represent the top nibble of the command value. */ -#define IT_S_SET_FILTER 0 /* Greyed out in IT... */ -#define IT_S_SET_GLISSANDO_CONTROL 1 /* Greyed out in IT... */ -#define IT_S_FINETUNE 2 /* Greyed out in IT... */ -#define IT_S_SET_VIBRATO_WAVEFORM 3 -#define IT_S_SET_TREMOLO_WAVEFORM 4 -#define IT_S_SET_PANBRELLO_WAVEFORM 5 -#define IT_S_FINE_PATTERN_DELAY 6 -#define IT_S7 7 -#define IT_S_SET_PAN 8 -#define IT_S_SET_SURROUND_SOUND 9 -#define IT_S_SET_HIGH_OFFSET 10 -#define IT_S_PATTERN_LOOP 11 -#define IT_S_DELAYED_NOTE_CUT 12 -#define IT_S_NOTE_DELAY 13 -#define IT_S_PATTERN_DELAY 14 -#define IT_S_SET_MIDI_MACRO 15 - -/* -S0x Set filter -S1x Set glissando control -S2x Set finetune - - -S3x Set vibrato waveform to type x -S4x Set tremelo waveform to type x -S5x Set panbrello waveform to type x - Waveforms for commands S3x, S4x and S5x: - 0: Sine wave - 1: Ramp down - 2: Square wave - 3: Random wave -S6x Pattern delay for x ticks -S70 Past note cut -S71 Past note off -S72 Past note fade -S73 Set NNA to note cut -S74 Set NNA to continue -S75 Set NNA to note off -S76 Set NNA to note fade -S77 Turn off volume envelope -S78 Turn on volume envelope -S79 Turn off panning envelope -S7A Turn on panning envelope -S7B Turn off pitch envelope -S7C Turn on pitch envelope -S8x Set panning position -S91 Set surround sound -SAy Set high value of sample offset yxx00h -SB0 Set loopback point -SBx Loop x times to loopback point -SCx Note cut after x ticks -SDx Note delay for x ticks -SEx Pattern delay for x rows -SFx Set parameterised MIDI Macro -*/ - -struct IT_ENTRY -{ - unsigned char channel; /* End of row if channel >= DUMB_IT_N_CHANNELS */ - unsigned char mask; - unsigned char note; - unsigned char instrument; - unsigned char volpan; - unsigned char effect; - unsigned char effectvalue; -}; - - - -struct IT_PATTERN -{ - int n_rows; - int n_entries; - IT_ENTRY *entry; -}; - - - -#define IT_STEREO 1 -#define IT_USE_INSTRUMENTS 4 -#define IT_LINEAR_SLIDES 8 /* If not set, use Amiga slides */ -#define IT_OLD_EFFECTS 16 -#define IT_COMPATIBLE_GXX 32 - -/* Make sure IT_WAS_AN_XM and IT_WAS_A_MOD aren't set accidentally */ -#define IT_REAL_FLAGS 63 - -#define IT_WAS_AN_XM 64 /* Set for both XMs and MODs */ -#define IT_WAS_A_MOD 128 - -#define IT_WAS_AN_S3M 256 - -#define IT_WAS_A_PTM 512 - -#define IT_WAS_A_669 1024 - -#define IT_WAS_AN_OKT 2048 - -#define IT_WAS_AN_STM 4096 - -#define IT_WAS_PROCESSED 8192 /* Will be set the first time a sigdata passes through a sigrenderer */ - -#define IT_ORDER_END 255 -#define IT_ORDER_SKIP 254 - -struct DUMB_IT_SIGDATA -{ - unsigned char name[65]; - - unsigned char *song_message; - - int n_orders; - int n_instruments; - int n_samples; - int n_patterns; - int n_pchannels; - - int flags; - - int global_volume; - int mixing_volume; - int speed; - int tempo; - int pan_separation; - - unsigned char channel_pan[DUMB_IT_N_CHANNELS]; - unsigned char channel_volume[DUMB_IT_N_CHANNELS]; - - unsigned char *order; - unsigned char restart_position; /* for XM compatiblity */ - - IT_INSTRUMENT *instrument; - IT_SAMPLE *sample; - IT_PATTERN *pattern; - - IT_MIDI *midi; - - IT_CHECKPOINT *checkpoint; -}; - - - -struct IT_PLAYING_ENVELOPE -{ - int next_node; - int tick; - int value; -}; - - - -#define IT_PLAYING_BACKGROUND 1 -#define IT_PLAYING_SUSTAINOFF 2 -#define IT_PLAYING_FADING 4 -#define IT_PLAYING_DEAD 8 -#define IT_PLAYING_REVERSE 16 - -struct IT_PLAYING -{ - int flags; - - int resampling_quality; - - IT_CHANNEL *channel; - IT_SAMPLE *sample; - IT_INSTRUMENT *instrument; - IT_INSTRUMENT *env_instrument; - - unsigned short sampnum; - unsigned char instnum; - - unsigned char declick_stage; - - float float_volume[2]; - float ramp_volume[2]; - float ramp_delta[2]; - - unsigned char channel_volume; - - unsigned char volume; - unsigned short pan; - - signed char volume_offset, panning_offset; - - unsigned char note; - - unsigned char enabled_envelopes; - - unsigned char filter_cutoff; - unsigned char filter_resonance; - - unsigned short true_filter_cutoff; /* These incorporate the filter envelope, and will not */ - unsigned char true_filter_resonance; /* be changed if they would be set to 127<<8 and 0. */ - - unsigned char vibrato_speed; - unsigned char vibrato_depth; - unsigned char vibrato_n; /* May be specified twice: volpan & effect. */ - unsigned char vibrato_time; - unsigned char vibrato_waveform; - - unsigned char tremolo_speed; - unsigned char tremolo_depth; - unsigned char tremolo_time; - unsigned char tremolo_waveform; - - unsigned char panbrello_speed; - unsigned char panbrello_depth; - unsigned char panbrello_time; - unsigned char panbrello_waveform; - signed char panbrello_random; - - unsigned char sample_vibrato_time; - unsigned char sample_vibrato_waveform; - int sample_vibrato_depth; /* Starts at rate?0:depth, increases by rate */ - - int slide; - float delta; - int finetune; - - IT_PLAYING_ENVELOPE volume_envelope; - IT_PLAYING_ENVELOPE pan_envelope; - IT_PLAYING_ENVELOPE pitch_envelope; - - int fadeoutcount; - - IT_FILTER_STATE filter_state[2]; /* Left and right */ - - DUMB_RESAMPLER resampler; - - /* time_lost is used to emulate Impulse Tracker's sample looping - * characteristics. When time_lost is added to pos, the result represents - * the position in the theoretical version of the sample where all loops - * have been expanded. If this is stored, the resampling helpers will - * safely convert it for use with new loop boundaries. The situation is - * slightly more complicated if dir == -1 when the change takes place; we - * must reflect pos off the loop end point and set dir to 1 before - * proceeding. - */ - int32 time_lost; - - //int output; - - IT_PLAYING *next; -}; - - - -#define IT_CHANNEL_MUTED 1 - -#define IT_ENV_VOLUME 1 -#define IT_ENV_PANNING 2 -#define IT_ENV_PITCH 4 - -struct IT_CHANNEL -{ - int flags; - - unsigned char volume; - signed char volslide; - signed char xm_volslide; - signed char panslide; - - /* xm_volslide is used for volume slides done in the volume column in an - * XM file, since it seems the volume column slide is applied first, - * followed by clamping, followed by the effects column slide. IT does - * not exhibit this behaviour, so xm_volslide is maintained at zero. - */ - - unsigned char pan; - unsigned short truepan; - - unsigned char channelvolume; - signed char channelvolslide; - - unsigned char instrument; - unsigned char note; - - unsigned char SFmacro; - - unsigned char filter_cutoff; - unsigned char filter_resonance; - - unsigned char key_off_count; - unsigned char note_cut_count; - unsigned char note_delay_count; - IT_ENTRY *note_delay_entry; - - unsigned char new_note_action; - - unsigned char const* arpeggio_table; - signed char arpeggio_offsets[3]; - - int arpeggio_shift; - unsigned char retrig; - unsigned char xm_retrig; - int retrig_tick; - - unsigned char tremor; - unsigned char tremor_time; /* Bit 6 set if note on; bit 7 set if tremor active. */ - - unsigned char vibrato_waveform; - unsigned char tremolo_waveform; - unsigned char panbrello_waveform; - - int portamento; - int toneporta; - int toneslide; - unsigned char toneslide_tick, last_toneslide_tick, ptm_toneslide, ptm_last_toneslide, okt_toneslide; - unsigned char destnote; - unsigned char toneslide_retrig; - - unsigned char glissando; - - /** WARNING - for neatness, should one or both of these be in the IT_PLAYING struct? */ - unsigned short sample; - unsigned char truenote; - - unsigned char midi_state; - - signed char lastvolslide; - unsigned char lastDKL; - unsigned char lastEF; /* Doubles as last portamento up for XM files */ - unsigned char lastG; - unsigned char lastHspeed; - unsigned char lastHdepth; - unsigned char lastRspeed; - unsigned char lastRdepth; - unsigned char lastYspeed; - unsigned char lastYdepth; - unsigned char lastI; - unsigned char lastJ; /* Doubles as last portamento down for XM files */ - unsigned char lastN; - unsigned char lastO; - unsigned char high_offset; - unsigned char lastP; - unsigned char lastQ; - unsigned char lastS; - unsigned char pat_loop_row; - unsigned char pat_loop_count; - unsigned char pat_loop_end_row; /* Used to catch infinite pattern loops */ - unsigned char lastW; - - unsigned char xm_lastE1; - unsigned char xm_lastE2; - unsigned char xm_lastEA; - unsigned char xm_lastEB; - unsigned char xm_lastX1; - unsigned char xm_lastX2; - - unsigned char inv_loop_delay; - unsigned char inv_loop_speed; - int inv_loop_offset; - - IT_PLAYING *playing; - -#ifdef BIT_ARRAY_BULLSHIT - void * played_patjump; - int played_patjump_order; -#endif - - //int output; -}; - - - -struct DUMB_IT_SIGRENDERER -{ - DUMB_IT_SIGDATA *sigdata; - - int n_channels; - - int resampling_quality; - - unsigned char globalvolume; - signed char globalvolslide; - - int tempo; - signed char temposlide; - - IT_CHANNEL channel[DUMB_IT_N_CHANNELS]; - - IT_PLAYING *playing[DUMB_IT_N_NNA_CHANNELS]; - - int tick; - int speed; - int rowcount; - - int order; /* Set to -1 if the song is terminated by a callback. */ - int row; - int processorder; - int processrow; - int breakrow; - - int restart_position; - - int n_rows; - - IT_ENTRY *entry_start; - IT_ENTRY *entry; - IT_ENTRY *entry_end; - - int32 time_left; /* Time before the next tick is processed */ - int sub_time_left; - - DUMB_CLICK_REMOVER **click_remover; - - IT_CALLBACKS *callbacks; - -#ifdef BIT_ARRAY_BULLSHIT - /* bit array, which rows are played, only checked by pattern break or loop commands */ - void * played; -#endif - - int32 gvz_time; - int gvz_sub_time; - - int ramp_style; - - //int max_output; - - IT_PLAYING *free_playing; -}; - - - -struct IT_CHECKPOINT -{ - IT_CHECKPOINT *next; - int32 time; - DUMB_IT_SIGRENDERER *sigrenderer; -}; - - - -struct IT_CALLBACKS -{ - int (DUMBCALLBACK *loop)(void *data); - void *loop_data; - /* Return 1 to prevent looping; the music will terminate abruptly. If you - * want to make the music stop but allow samples to fade (beware, as they - * might not fade at all!), use dumb_it_sr_set_speed() and set the speed - * to 0. Note that xm_speed_zero() will not be called if you set the - * speed manually, and also that this will work for IT and S3M files even - * though the music can't stop in this way by itself. - */ - - int (DUMBCALLBACK *xm_speed_zero)(void *data); - void *xm_speed_zero_data; - /* Return 1 to terminate the mod, without letting samples fade. */ - - int (DUMBCALLBACK *midi)(void *data, int channel, unsigned char byte); - void *midi_data; - /* Return 1 to prevent DUMB from subsequently interpreting the MIDI bytes - * itself. In other words, return 1 if the Zxx macros in an IT file are - * controlling filters and shouldn't be. - */ - - int (DUMBCALLBACK *global_volume_zero)(void *data); - void *global_volume_zero_data; - /* Return 1 to terminate the module when global volume is set to zero. */ -}; - - - -void _dumb_it_end_sigrenderer(sigrenderer_t *sigrenderer); -void _dumb_it_unload_sigdata(sigdata_t *vsigdata); - -extern DUH_SIGTYPE_DESC _dumb_sigtype_it; - - - -#define XM_APPREGIO 0 -#define XM_PORTAMENTO_UP 1 -#define XM_PORTAMENTO_DOWN 2 -#define XM_TONE_PORTAMENTO 3 -#define XM_VIBRATO 4 -#define XM_VOLSLIDE_TONEPORTA 5 -#define XM_VOLSLIDE_VIBRATO 6 -#define XM_TREMOLO 7 -#define XM_SET_PANNING 8 -#define XM_SAMPLE_OFFSET 9 -#define XM_VOLUME_SLIDE 10 /* A */ -#define XM_POSITION_JUMP 11 /* B */ -#define XM_SET_CHANNEL_VOLUME 12 /* C */ -#define XM_PATTERN_BREAK 13 /* D */ -#define XM_E 14 /* E */ -#define XM_SET_TEMPO_BPM 15 /* F */ -#define XM_SET_GLOBAL_VOLUME 16 /* G */ -#define XM_GLOBAL_VOLUME_SLIDE 17 /* H */ -#define XM_KEY_OFF 20 /* K (undocumented) */ -#define XM_SET_ENVELOPE_POSITION 21 /* L */ -#define XM_PANNING_SLIDE 25 /* P */ -#define XM_MULTI_RETRIG 27 /* R */ -#define XM_TREMOR 29 /* T */ -#define XM_X 33 /* X */ -#define XM_N_EFFECTS (10+26) - -#define XM_E_SET_FILTER 0x0 -#define XM_E_FINE_PORTA_UP 0x1 -#define XM_E_FINE_PORTA_DOWN 0x2 -#define XM_E_SET_GLISSANDO_CONTROL 0x3 -#define XM_E_SET_VIBRATO_CONTROL 0x4 -#define XM_E_SET_FINETUNE 0x5 -#define XM_E_SET_LOOP 0x6 -#define XM_E_SET_TREMOLO_CONTROL 0x7 -#define XM_E_SET_PANNING 0x8 -#define XM_E_RETRIG_NOTE 0x9 -#define XM_E_FINE_VOLSLIDE_UP 0xA -#define XM_E_FINE_VOLSLIDE_DOWN 0xB -#define XM_E_NOTE_CUT 0xC -#define XM_E_NOTE_DELAY 0xD -#define XM_E_PATTERN_DELAY 0xE -#define XM_E_SET_MIDI_MACRO 0xF - -#define XM_X_EXTRAFINE_PORTA_UP 1 -#define XM_X_EXTRAFINE_PORTA_DOWN 2 - -/* To make my life a bit simpler during conversion, effect E:xy is converted - * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That - * way, these effects can be manipulated like regular effects. - */ -#define EBASE (XM_N_EFFECTS) -#define XBASE (EBASE+16) -#define SBASE (IT_N_EFFECTS) - -#define EFFECT_VALUE(x, y) (((x)<<4)|(y)) -#define HIGH(v) ((v)>>4) -#define LOW(v) ((v)&0x0F) -#define SET_HIGH(v, x) v = (((x)<<4)|((v)&0x0F)) -#define SET_LOW(v, y) v = (((v)&0xF0)|(y)) -#define BCD_TO_NORMAL(v) (HIGH(v)*10+LOW(v)) - - - -#if 0 -unsigned char **_dumb_malloc2(int w, int h); -void _dumb_free2(unsigned char **line); -#endif - -void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod); -int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata); - - -#define PTM_APPREGIO 0 -#define PTM_PORTAMENTO_UP 1 -#define PTM_PORTAMENTO_DOWN 2 -#define PTM_TONE_PORTAMENTO 3 -#define PTM_VIBRATO 4 -#define PTM_VOLSLIDE_TONEPORTA 5 -#define PTM_VOLSLIDE_VIBRATO 6 -#define PTM_TREMOLO 7 -#define PTM_SAMPLE_OFFSET 9 -#define PTM_VOLUME_SLIDE 10 /* A */ -#define PTM_POSITION_JUMP 11 /* B */ -#define PTM_SET_CHANNEL_VOLUME 12 /* C */ -#define PTM_PATTERN_BREAK 13 /* D */ -#define PTM_E 14 /* E */ -#define PTM_SET_TEMPO_BPM 15 /* F */ -#define PTM_SET_GLOBAL_VOLUME 16 /* G */ -#define PTM_RETRIGGER 17 /* H */ -#define PTM_FINE_VIBRATO 18 /* I */ -#define PTM_NOTE_SLIDE_UP 19 /* J */ -#define PTM_NOTE_SLIDE_DOWN 20 /* K */ -#define PTM_NOTE_SLIDE_UP_RETRIG 21 /* L */ -#define PTM_NOTE_SLIDE_DOWN_RETRIG 22 /* M */ -#define PTM_N_EFFECTS 23 - -#define PTM_E_FINE_PORTA_DOWN 0x1 -#define PTM_E_FINE_PORTA_UP 0x2 -#define PTM_E_SET_VIBRATO_CONTROL 0x4 -#define PTM_E_SET_FINETUNE 0x5 -#define PTM_E_SET_LOOP 0x6 -#define PTM_E_SET_TREMOLO_CONTROL 0x7 -#define PTM_E_SET_PANNING 0x8 -#define PTM_E_RETRIG_NOTE 0x9 -#define PTM_E_FINE_VOLSLIDE_UP 0xA -#define PTM_E_FINE_VOLSLIDE_DOWN 0xB -#define PTM_E_NOTE_CUT 0xC -#define PTM_E_NOTE_DELAY 0xD -#define PTM_E_PATTERN_DELAY 0xE - -/* To make my life a bit simpler during conversion, effect E:xy is converted - * to effect number EBASE+x:y. The same applies to effect X, and IT's S. That - * way, these effects can be manipulated like regular effects. - */ -#define PTM_EBASE (PTM_N_EFFECTS) - -void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry); - -int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f); - -void _dumb_it_interleave_stereo_sample(IT_SAMPLE *sample); - -/* Calling either of these is optional */ -void _dumb_init_cubic(); -#ifdef _USE_SSE -void _dumb_init_sse(); -#endif - -#endif /* INTERNAL_IT_H */ diff --git a/libraries/dumb/include/internal/lpc.h b/libraries/dumb/include/internal/lpc.h deleted file mode 100644 index 47fb03334..000000000 --- a/libraries/dumb/include/internal/lpc.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: LPC low level routines - last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $ - - ********************************************************************/ - -#ifndef _V_LPC_H_ -#define _V_LPC_H_ - -/* simple linear scale LPC code */ -extern float vorbis_lpc_from_data(float *data,float *lpc,int n,int m); - -extern void vorbis_lpc_predict(float *coeff,float *prime,int m, - float *data,long n); - -struct DUMB_IT_SIGDATA; -extern void dumb_it_add_lpc(struct DUMB_IT_SIGDATA *sigdata); - -#endif diff --git a/libraries/dumb/include/internal/mulsc.h b/libraries/dumb/include/internal/mulsc.h deleted file mode 100644 index 57d6ec291..000000000 --- a/libraries/dumb/include/internal/mulsc.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef INTERNAL_MULSC_H -#define INTERNAL_MULSC_H - -#if !defined(_MSC_VER) || !defined(_M_IX86) || _MSC_VER >= 1800 -//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16)) -//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14) -#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32)) -#define MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (b) >> 32)) -#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32)) -#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32)) -#else -/* VC++ calls __allmull and __allshr for the above math. I don't know why. - * [Need to check if this still applies to recent versions of the compiler.] */ -static __forceinline unsigned long long MULLL(int a, int b) -{ - __asm mov eax,a - __asm imul b -} -static __forceinline int MULSCV (int a, int b) -{ -#ifndef _DEBUG - union { unsigned long long q; struct { int l, h; }; } val; - val.q = MULLL(a,b); - return val.h; -#else - __asm mov eax,a - __asm imul b - __asm mov eax,edx -#endif -} -#define MULSCA(a, b) MULSCV((a) << 4, b) -#define MULSC(a, b) MULSCV((a) << 4, (b) << 12) -#define MULSC16(a, b) MULSCV((a) << 12, (b) << 12) -#endif - -#endif /* INTERNAL_MULSC_H */ \ No newline at end of file diff --git a/libraries/dumb/include/internal/resampler.h b/libraries/dumb/include/internal/resampler.h deleted file mode 100644 index 0050ebf1a..000000000 --- a/libraries/dumb/include/internal/resampler.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _RESAMPLER_H_ -#define _RESAMPLER_H_ - -// Ugglay -#ifdef RESAMPLER_DECORATE -#define PASTE(a,b) a ## b -#define EVALUATE(a,b) PASTE(a,b) -#define resampler_init EVALUATE(RESAMPLER_DECORATE,_resampler_init) -#define resampler_create EVALUATE(RESAMPLER_DECORATE,_resampler_create) -#define resampler_delete EVALUATE(RESAMPLER_DECORATE,_resampler_delete) -#define resampler_dup EVALUATE(RESAMPLER_DECORATE,_resampler_dup) -#define resampler_dup_inplace EVALUATE(RESAMPLER_DECORATE,_resampler_dup_inplace) -#define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality) -#define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count) -#define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample) -#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed) -#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate) -#define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready) -#define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear) -#define resampler_get_sample_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_count) -#define resampler_get_sample EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample) -#define resampler_get_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_float) -#define resampler_remove_sample EVALUATE(RESAMPLER_DECORATE,_resampler_remove_sample) -#endif - -void resampler_init(void); - -void * resampler_create(void); -void resampler_delete(void *); -void * resampler_dup(const void *); -void resampler_dup_inplace(void *, const void *); - -enum -{ - RESAMPLER_QUALITY_MIN = 0, - RESAMPLER_QUALITY_ZOH = 0, - RESAMPLER_QUALITY_BLEP = 1, - RESAMPLER_QUALITY_LINEAR = 2, - RESAMPLER_QUALITY_BLAM = 3, - RESAMPLER_QUALITY_CUBIC = 4, - RESAMPLER_QUALITY_SINC = 5, - RESAMPLER_QUALITY_MAX = 5 -}; - -void resampler_set_quality(void *, int quality); - -int resampler_get_free_count(void *); -void resampler_write_sample(void *, short sample); -void resampler_write_sample_fixed(void *, int sample, unsigned char depth); -void resampler_set_rate( void *, double new_factor ); -int resampler_ready(void *); -void resampler_clear(void *); -int resampler_get_sample_count(void *); -int resampler_get_sample(void *); -float resampler_get_sample_float(void *); -void resampler_remove_sample(void *, int decay); - -#endif diff --git a/libraries/dumb/include/internal/riff.h b/libraries/dumb/include/internal/riff.h deleted file mode 100644 index 54c87c47c..000000000 --- a/libraries/dumb/include/internal/riff.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef RIFF_H -#define RIFF_H - -struct riff; - -struct riff_chunk -{ - unsigned type; - int32 offset; - unsigned size; - struct riff * nested; -}; - -struct riff -{ - unsigned type; - unsigned chunk_count; - struct riff_chunk * chunks; -}; - -struct riff * riff_parse( DUMBFILE * f, int32 offset, int32 size, unsigned proper ); -void riff_free( struct riff * ); - -#endif diff --git a/libraries/dumb/include/internal/stack_alloc.h b/libraries/dumb/include/internal/stack_alloc.h deleted file mode 100644 index 4cab5b9c6..000000000 --- a/libraries/dumb/include/internal/stack_alloc.h +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (C) 2002 Jean-Marc Valin */ -/** - @file stack_alloc.h - @brief Temporary memory allocation on stack -*/ -/* - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - Neither the name of the Xiph.org Foundation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef STACK_ALLOC_H -#define STACK_ALLOC_H - -#ifdef _WIN32 -# include -#else -# ifdef HAVE_ALLOCA_H -# include -# else -# include -# endif -#endif - -/** - * @def ALIGN(stack, size) - * - * Aligns the stack to a 'size' boundary - * - * @param stack Stack - * @param size New size boundary - */ - -/** - * @def PUSH(stack, size, type) - * - * Allocates 'size' elements of type 'type' on the stack - * - * @param stack Stack - * @param size Number of elements - * @param type Type of element - */ - -/** - * @def VARDECL(var) - * - * Declare variable on stack - * - * @param var Variable to declare - */ - -/** - * @def ALLOC(var, size, type) - * - * Allocate 'size' elements of 'type' on stack - * - * @param var Name of variable to allocate - * @param size Number of elements - * @param type Type of element - */ - -#ifdef ENABLE_VALGRIND - -#include - -#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) - -#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) - -#else - -#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) - -#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) - -#endif - -#if defined(VAR_ARRAYS) -#define VARDECL(var) -#define ALLOC(var, size, type) type var[size] -#elif defined(USE_ALLOCA) -#define VARDECL(var) var -#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size)) -#else -#define VARDECL(var) var -#define ALLOC(var, size, type) var = PUSH(stack, size, type) -#endif - - -#endif diff --git a/libraries/dumb/licence.txt b/libraries/dumb/licence.txt deleted file mode 100644 index 961fe4ef8..000000000 --- a/libraries/dumb/licence.txt +++ /dev/null @@ -1,87 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * licence.txt - Conditions for use of DUMB. / / \ \ - * | < / \_ - * If you do not agree to these terms, please | \/ /\ / - * do not use DUMB. \_ / > / - * | \ / / - * Information in [brackets] is provided to aid | ' / - * interpretation of the licence. \__/ - */ - - -Dynamic Universal Music Bibliotheque, Version 0.9.3 - -Copyright (C) 2001-2005 Ben Davis, Robert J Ohannessian and Julien Cugniere - -This software is provided 'as-is', without any express or implied warranty. -In no event shall the authors be held liable for any damages arising from the -use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim - that you wrote the original software. If you use this software in a - product, you are requested to acknowledge its use in the product - documentation, along with details on where to get an unmodified version of - this software, but this is not a strict requirement. - - [Note that the above point asks for a link to DUMB, not just a mention. - Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".] - - [The link was originally strictly required. This was changed for two - reasons. Firstly, if many projects request an acknowledgement, the list of - acknowledgements can become quite unmanageable. Secondly, DUMB was placing - a restriction on the code using it, preventing people from using the GNU - General Public Licence which disallows any such restrictions. See - http://www.gnu.org/philosophy/bsd.html for more information on this - subject. However, if DUMB plays a significant part in your project, we do - urge you to acknowledge its use.] - -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - -3. This notice may not be removed from or altered in any source distribution. - -4. If you are using the Program in someone else's bedroom on any Monday at - 3:05 pm, you are not allowed to modify the Program for ten minutes. [This - clause provided by Inphernic; every licence should contain at least one - clause, the reasoning behind which is far from obvious.] - -5. Users who wish to use DUMB for the specific purpose of playing music are - required to feed their dog on every full moon (if deemed appropriate). - [This clause provided by Allefant, who couldn't remember what Inphernic's - clause was.] - -6. No clause in this licence shall prevent this software from being depended - upon by a product licensed under the GNU General Public Licence. If such a - clause is deemed to exist, Debian, then it shall be respected in spirit as - far as possible and all other clauses shall continue to apply in full - force. - -8. Take the number stated as introducing this clause. Multiply it by two, - then subtract four. Now insert a '+' between the two digits and evaluate - the resulting sum. Call the result 'x'. If you have not yet concluded that - every numbered clause in this licence whose ordinal number is strictly - greater than 'x' (with the exception of the present clause) is null and - void, Debian, then you are hereby informed that laughter is good for one's - health and you are warmly suggested to do it. By the way, Clauses 4, 5 and - 6 are null and void. Incidentally, I like Kubuntu. The work you guys do is - awesome. (Lawyers, on the other hand ...) - -We regret that we cannot provide any warranty, not even the implied warranty -of merchantability or fitness for a particular purpose. - -Some files generated or copied by automake, autoconf and friends are -available in an extra download. These fall under separate licences but are -all free to distribute. Please check their licences as necessary. diff --git a/libraries/dumb/prj/.gitignore b/libraries/dumb/prj/.gitignore deleted file mode 100644 index 36d588baa..000000000 --- a/libraries/dumb/prj/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -dumb-build-Desktop-Release -dumb-build-Desktop-Debug -*.user diff --git a/libraries/dumb/prj/dumb/dumb.pro b/libraries/dumb/prj/dumb/dumb.pro deleted file mode 100644 index 9244ce4bd..000000000 --- a/libraries/dumb/prj/dumb/dumb.pro +++ /dev/null @@ -1,128 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2012-12-22T16:33:53 -# -#------------------------------------------------- - -QT -= core gui - -TARGET = dumb -TEMPLATE = lib -CONFIG += staticlib - -DEFINES += _USE_SSE - -INCLUDEPATH += ../../include - -QMAKE_CFLAGS += -msse - -SOURCES += \ - ../../src/core/unload.c \ - ../../src/core/rendsig.c \ - ../../src/core/rendduh.c \ - ../../src/core/register.c \ - ../../src/core/readduh.c \ - ../../src/core/rawsig.c \ - ../../src/core/makeduh.c \ - ../../src/core/loadduh.c \ - ../../src/core/dumbfile.c \ - ../../src/core/duhtag.c \ - ../../src/core/duhlen.c \ - ../../src/core/atexit.c \ - ../../src/helpers/stdfile.c \ - ../../src/helpers/silence.c \ - ../../src/helpers/sampbuf.c \ - ../../src/helpers/riff.c \ - ../../src/helpers/resample.c \ - ../../src/helpers/memfile.c \ - ../../src/helpers/clickrem.c \ - ../../src/helpers/barray.c \ - ../../src/it/xmeffect.c \ - ../../src/it/readxm2.c \ - ../../src/it/readxm.c \ - ../../src/it/readstm2.c \ - ../../src/it/readstm.c \ - ../../src/it/reads3m2.c \ - ../../src/it/reads3m.c \ - ../../src/it/readriff.c \ - ../../src/it/readptm.c \ - ../../src/it/readpsm.c \ - ../../src/it/readoldpsm.c \ - ../../src/it/readokt2.c \ - ../../src/it/readokt.c \ - ../../src/it/readmtm.c \ - ../../src/it/readmod2.c \ - ../../src/it/readmod.c \ - ../../src/it/readdsmf.c \ - ../../src/it/readasy.c \ - ../../src/it/readamf2.c \ - ../../src/it/readamf.c \ - ../../src/it/readam.c \ - ../../src/it/read6692.c \ - ../../src/it/read669.c \ - ../../src/it/ptmeffect.c \ - ../../src/it/loadxm2.c \ - ../../src/it/loadxm.c \ - ../../src/it/loadstm2.c \ - ../../src/it/loadstm.c \ - ../../src/it/loads3m2.c \ - ../../src/it/loads3m.c \ - ../../src/it/loadriff2.c \ - ../../src/it/loadriff.c \ - ../../src/it/loadptm2.c \ - ../../src/it/loadptm.c \ - ../../src/it/loadpsm2.c \ - ../../src/it/loadpsm.c \ - ../../src/it/loadoldpsm2.c \ - ../../src/it/loadoldpsm.c \ - ../../src/it/loadokt2.c \ - ../../src/it/loadokt.c \ - ../../src/it/loadmtm2.c \ - ../../src/it/loadmtm.c \ - ../../src/it/loadmod2.c \ - ../../src/it/loadmod.c \ - ../../src/it/loadasy2.c \ - ../../src/it/loadasy.c \ - ../../src/it/loadamf2.c \ - ../../src/it/loadamf.c \ - ../../src/it/load6692.c \ - ../../src/it/load669.c \ - ../../src/it/itunload.c \ - ../../src/it/itrender.c \ - ../../src/it/itread2.c \ - ../../src/it/itread.c \ - ../../src/it/itorder.c \ - ../../src/it/itmisc.c \ - ../../src/it/itload2.c \ - ../../src/it/itload.c \ - ../../src/it/readany.c \ - ../../src/it/loadany2.c \ - ../../src/it/loadany.c \ - ../../src/it/readany2.c \ - ../../src/helpers/sinc_resampler.c \ - ../../src/helpers/lpc.c - -HEADERS += \ - ../../include/dumb.h \ - ../../include/internal/riff.h \ - ../../include/internal/it.h \ - ../../include/internal/dumb.h \ - ../../include/internal/barray.h \ - ../../include/internal/aldumb.h \ - ../../include/internal/sinc_resampler.h \ - ../../include/internal/stack_alloc.h \ - ../../include/internal/lpc.h \ - ../../include/internal/dumbfile.h -unix:!symbian { - maemo5 { - target.path = /opt/usr/lib - } else { - target.path = /usr/lib - } - INSTALLS += target -} - -OTHER_FILES += \ - ../../src/helpers/resample.inc \ - ../../src/helpers/resamp3.inc \ - ../../src/helpers/resamp2.inc diff --git a/libraries/dumb/readme.txt b/libraries/dumb/readme.txt deleted file mode 100644 index e86af048a..000000000 --- a/libraries/dumb/readme.txt +++ /dev/null @@ -1,541 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readme.txt - General information on DUMB. / / \ \ - * | < / \_ - * | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -******************** -*** Introduction *** -******************** - - -Thank you for downloading DUMB v0.9.3! You should have the following -documentation: - - readme.txt - This file - licence.txt - Conditions for the use of this software - release.txt - Release notes and changes for this and past releases - docs/ - howto.txt - Step-by-step instructions on adding DUMB to your project - faq.txt - Frequently asked questions and answers to them - dumb.txt - DUMB library reference - deprec.txt - Information about deprecated parts of the API - ptr.txt - Quick introduction to pointers for those who need it - fnptr.txt - Explanation of function pointers for those who need it - modplug.txt - Our official position regarding ModPlug Tracker - -This file will help you get DUMB set up. If you have not yet done so, please -read licence.txt and release.txt before proceeding. After you've got DUMB set -up, please refer to the files in the docs/ directory at your convenience. I -recommend you start with howto.txt. - - -**************** -*** Features *** -**************** - - -Here is the statutory feature list: - -- Freeware - -- Supports playback of IT, XM, S3M and MOD files - -- Faithful to the original trackers, especially IT; if it plays your module - wrongly, please tell me so I can fix the bug! (But please don't complain - about differences between DUMB and ModPlug Tracker; see docs/modplug.txt) - -- Accurate support for low-pass resonant filters for IT files - -- Very accurate timing and pitching; completely deterministic playback - -- Click removal - -- Facility to embed music files in other files (e.g. Allegro datafiles) - -- Three resampling quality settings: aliasing, linear interpolation and cubic - interpolation - -- Number of samples playing at once can be limited to reduce processor usage, - but samples will come back in when other louder ones stop - -- All notes will be present and correct even if you start a piece of music in - the middle - -- Option to take longer loading but seek fast to any point before the music - first loops (seeking time increases beyond this point) - -- Audio generated can be used in any way; DUMB does not necessarily send it - straight to a sound output system - -- Can be used with Allegro, can be used without (if you'd like to help make - DUMB more approachable to people who aren't using Allegro, please contact - me) - -- Makefile provided for DJGPP, MinGW, Linux, BeOS and Mac OS X - -- Project files provided for MSVC 6 - -- Autotools-based configure script available as a separate download for - masochists - -- Code should port anywhere that has a 32-bit C compiler; instructions on - compiling it manually are available further down - - -********************* -*** What you need *** -********************* - - -To use DUMB, you need a 32-bit C compiler (GCC and MSVC are fine). If you -have Allegro, DUMB can integrate with its audio streams and datafiles, making -your life easier. If you do not wish to use Allegro, you will have to do some -work to get music playing back. The 'dumbplay' example program requires -Allegro. - - Allegro - http://alleg.sf.net/ - - -********************************************** -*** How to set DUMB up with DJGPP or MinGW *** -********************************************** - - -You should have got the .zip version. If for some reason you got the .tar.gz -version instead, you may have to convert make/config.bat to DOS text file -format. WinZip does this automatically by default. Otherwise, loading it into -MS EDIT and saving it again should do the trick (but do not do this to the -Makefiles as it destroys tabs). You will have to do the same for any files -you want to view in Windows Notepad. If you have problems, just go and -download the .zip instead. - -Make sure you preserved the directory structure when you extracted DUMB from -the archive. Most unzipping programs will do this by default, but pkunzip -requires you to pass -d. If not, please delete DUMB and extract it again -properly. - -If you are using Windows, open an MS-DOS Prompt or a Windows Command Line. -Change to the directory into which you unzipped DUMB. - -If you are using MinGW (and you haven't renamed 'mingw32-make'), type: - - mingw32-make - -Otherwise, type the following: - - make - -DUMB will ask you whether you wish to compile for DJGPP or MinGW. Then it -will ask you whether you want support for Allegro. (You have to have made and -installed Allegro's optimised library for this to work.) Finally, it will -compile optimised and debugging builds of DUMB, along with the example -programs. When it has finished, run one of the following to install the -libraries: - - make install - mingw32-make install - -All done! If you ever need the configuration again (e.g. if you compiled for -DJGPP before and you want to compile for MinGW now), run one of the -following: - - make config - mingw32-make config - -See the comments in the Makefile for other targets. - -Note: the Makefile will only work properly if you have COMSPEC or ComSpec set -to point to command.com or cmd.exe. If you set it to point to a Unix-style -shell, the Makefile won't work. - -Please let me know if you have any trouble. - -As an alternative, MSYS users may attempt to use the configure script, -available in dumb-0.9.3-autotools.tar.gz. This has been found to work without -Allegro, and is untested with Allegro. I should appreciate feedback from -anyone else who tries this. I do not recommend its use, partly because it -creates dynamically linked libraries and I don't know how to stop it from -doing that (see the section on compiling DUMB manually), and partly because -autotools are plain evil. - -Scroll down for information on the example programs. Refer to docs/howto.txt -when you are ready to start programming with DUMB. If you use DUMB in a game, -let me know - I might decide to place a link to your game on DUMB's website! - - -****************************************************** -*** How to set DUMB up with Microsoft Visual C++ 6 *** -****************************************************** - - -If you have a newer version of Microsoft Visual C++ or Visual Something that -supports C++, please try these instructions and let me know if it works. - -You should have got the .zip version. If for some reason you got the .tar.gz -version instead, you may have to convert some files to DOS text file format. -WinZip does this automatically by default. Otherwise, loading such files into -MS EDIT and saving them again should do the trick. You will have to do this -for any files you want to view in Windows Notepad. If you have problems, just -go and download the .zip instead. - -Make sure you preserved the directory structure when you extracted DUMB from -the archive. Most unzipping programs will do this by default, but pkunzip -requires you to pass -d. If not, please delete DUMB and extract it again -properly. - -DUMB comes with a workspace Microsoft Visual C++ 6, containing projects for -the DUMB core, the Allegro interface library and each of the examples. The -first thing you might want to do is load the workspace up and have a look -around. You will find it in the dumb\vc6 directory under the name dumb.dsw. -Note that the aldumb and dumbplay projects require Allegro, so they won't -work if you don't have Allegro. Nevertheless, dumbplay is the best-commented -of the examples, so do have a look. - -When you are ready to add DUMB to your project, follow these instructions: - -1. Open your project in VC++. -2. Select Project|Insert Project into Workspace... -3. Navigate to the dumb\vc6\dumb directory and select dumb.dsp. - Alternatively, if you know that you are statically linking with a library - that uses the statically linked multithreaded runtime (/MT), you may wish - to select dumb_static.dsp in the dumb_static subdirectory instead. -4. Select Build|Set Active Configuration..., and reselect one of your - project's configurations. -5. Select Project|Dependencies... and ensure your project is dependent on - DUMB. -6. Select Project|Settings..., Settings for: All Configurations, C/C++ tab, - Preprocessor category. Add the DUMB include directory to the Additional - Include Directories box. -7. Ensure that for all the projects in the workspace (or more likely just all - the projects in a particular dependency chain) the run-time libraries are - the same. That's in Project|Settings, C/C++ tab, Code generation category, - Use run-time library dropdown. The settings for Release and Debug are - separate, so you'll have to change them one at a time. Exactly which run- - time library you use will depend on what you need; it doesn't appear that - DUMB has any particular requirements, so set it to whatever you're using - now. (It will have to be /MD, the multithreaded DLL library, if you are - statically linking with Allegro. If you are dynamically linking with - Allegro than it doesn't matter.) -8. If you are using Allegro, do some or all of the above for the aldumb.dsp - project in the aldumb directory too. - -Good thing you only have to do all that once ... or twice ... - -If you have the Intel compiler installed, it will - well, should - be used to -compile DUMB. The only setting I [Tom Seddon] added is /QxiM. This allows the -compiler to use PPro and MMX instructions, and so when compiling with Intel -the resultant EXE will require a Pentium II or greater. I don't think this is -unreasonable. After all, it is 2003 :) - -[Note from Ben: the Intel compiler is evil! It makes AMD processors look bad! -Patch it or boycott it or something!] - -If you don't have the Intel compiler, VC will compile DUMB as normal. - -This project file and these instructions were provided by Tom Seddon (I hope -I got his name right; I had to guess it from his e-mail address!). Chad -Austin has since changed the project files around, and I've just attempted to -hack them to incorporate new source files. I've also tried to update the -instructions using guesswork and some knowledge of Visual J++ (you heard me). -The instructions and the project files are to this day untested by me. If you -have problems, check the download page at http://dumb.sf.net/ to see if they -are addressed; failing that, direct queries to me and I'll try to figure them -out. - -If you have any comments at all on how the VC6 projects are laid out, or how -the instructions could be improved, I should be really grateful to hear them. -I am a perfectionist, after all. :) - -Scroll down for information on the example programs. When you are ready to -start using DUMB, refer to docs/howto.txt. If you use DUMB in a game, let me -know - I might decide to place a link to your game on DUMB's website! - - -****************************************************** -*** How to set DUMB up on Linux, BeOS and Mac OS X *** -****************************************************** - - -You should have got the .tar.gz version. If for some reason you got the .zip -version instead, you may have to strip all characters with ASCII code 13 from -some of the text files. If you have problems, just go and download the -.tar.gz instead. - -You have two options. There is a Makefile which should cope with most -systems. The first option is to use this default Makefile, and the procedure -is explained below. The second option is to download -dumb-0.9.3-autotools.tar.gz, extract it over the installation, run -./configure and use the generated Makefile. Users who choose to do this are -left to their own devices but advised to read the information at the end of -this section. I strongly recommend the first option. - -If you are not using the configure script, the procedure is as follows. - -First, run the following command as a normal user: - - make - -You will be asked whether you want Allegro support. Then, unless you are on -BeOS, you will be asked where you'd like DUMB to install its headers, -libraries and examples (which will go in the include/, lib/ and bin/ -subdirectories of the prefix you specify). BeOS has fixed locations for these -files. You may use shell variables here, e.g. $HOME or ${HOME}, but ~ will -not work. Once you have specified these pieces of information, the optimised -and debugging builds of DUMB will be compiled, along with the examples. When -it has finished, you can install them with: - - make install - -You may need to be root for this to work. It depends on the prefix you chose. - -Note: the Makefile will only work if COMSPEC and ComSpec are both undefined. -If either of these is defined, the Makefile will try to build for a Windows -system, and will fail. - -Please let me know if you have any trouble. - -Scroll down for information on the example programs. Refer to docs/howto.txt -when you are ready to start programming with DUMB. If you use DUMB in a game, -let me know - I might decide to place a link to your game on DUMB's website! - -Important information for users of the configure script follows. - -The Makefile generated by the configure script creates dynamically linked -libraries, and I don't know how to stop it from doing so. See the section -below on building DUMB manually for why I recommend linking DUMB statically. -However, if you choose to use the configure script, note the following. - -The default Makefile is a copy of Makefile.rdy (short for 'ready'), and it -must exist with the name Makefile.rdy in order to work. The configure script -will overwrite Makefile, so if you want the default Makefile back, just run: - - cp Makefile.rdy Makefile - -Do not use a symlink, as that would result in Makefile.rdy getting -overwritten next time the configure script is run! - -You can also access the usual build system by passing '-f Makefile.rdy' to -Make. - - -******************************************************** -*** How to build DUMB manually if nothing else works *** -******************************************************** - - -Those porting to platforms without floating point support should be aware -that DUMB does use floating point operations but not in the inner loops. They -are used for volume and note pitch calculations, and they are used when -initialising the filter algorithm for given cut-off and resonance values. -Please let me know if this is a problem for you. If there is enough demand, I -may be able to eliminate one or both of these cases. - -All of the library source code may be found in the src/ subdirectory. There -are headers in the include/ subdirectory, and src/helpers/resample.c also -#includes some .inc files in its own directory. - -There are four subdirectories under src/. For projects not using Allegro, you -will need all the files in src/core/, src/helpers/ and src/it/. If you are -using Allegro, you will want the src/allegro/ subdirectory too. For -consistency with the other build systems, the contents of src/allegro/ should -be compiled into a separate library. - -I recommend static-linking DUMB, since the version information is done via -macros and the API has a tendency to change. If you static-link, then once -your program is in binary form, you can be sure that changes to the installed -version of DUMB won't cause it to malfuction. It is my fault that the API has -been so unstable. Sorry! - -Compile each .c file separately. As mentioned above, you will need to specify -two places to look for #include files: the include/ directory and the source -file's own directory. You will also need to define the symbol -DUMB_DECLARE_DEPRECATED on the command line. - -Do not compile the .inc files separately. - -You may need to edit dumb.h and add your own definition for LONG_LONG. It -should be a 64-bit integer. If you do this, please see if you can add a check -for your compiler so that it still works with other compilers. - -DUMB has two build modes. If you define the symbol DEBUGMODE, some checks for -programmer error will be incorporated into the library. Otherwise it will be -built without any such checks. (DUMB will however always thoroughly check the -validity of files it is loading. If you ever find a module file that crashes -DUMB, please let me know!) - -I recommend building two versions of the library, one with DEBUGMODE defined -and debugging information included, and the other with compiler optimisation -enabled. If you can install DUMB system-wide so that your projects, and other -people's, can simply #include or and link with libraries -by simple name with no path, then that is ideal. - -If you successfully port DUMB to a new platform, please let me know! - - -**************************** -*** The example programs *** -**************************** - - -Three example programs are provided. On DOS and Windows, you can find them in -the examples subdirectory. On other systems they will be installed system- -wide. - -dumbplay - This program will only be built if you have Allegro. Pass it the filename - of an IT, XM, S3M or MOD file, and it will play it. It's not a polished - player with real-time threading or anything - so don't complain about it - stuttering while you use other programs - but it does show DUMB's fidelity - nicely. You can control the playback quality by editing dumb.ini, which - must be in the current working directory. (This is a flaw for systems - where the program is installed system-wide, but it is non-fatal.) Have a - look at the examples/dumb.ini file for further information. - -dumbout - This program does not need Allegro. You can use it to stream an IT, XM, - S3M or MOD file to raw PCM. This can be used as input to an encoder like - oggenc (with appropriate command-line options), or it can be sent to a - .pcm file which can be read by any respectable waveform editor. This - program is also convenient for timing DUMB. Compare the time it takes to - render a module with the module's playing time! dumbout doesn't try to - read any configuration file; the options are set on the command line. - -dumb2wav - This program is much the same as dumbout, but it writes a .wav file with - the appropriate header. Thanks go to Chad Austin for this useful tool. - - -********************************************* -*** Downloading music or writing your own *** -********************************************* - - -If you would like to compose your own music modules, then this section should -help get you started. - -The best programs for the job are the trackers that pioneered the file -formats: - - Impulse Tracker - IT files - http://www.lim.com.au/ImpulseTracker/ - Fast Tracker II - XM files - http://www.fasttracker2.com/ - Scream Tracker 3 - S3M files - No official site known, please use Google - -MOD files come from the Amiga; I do not know what PC tracker to recommend for -editing these. If you know of one, let me know! In the meantime, I would -recommend using a more advanced file format. However, don't convert your -existing MODs just for the sake of it. - -Fast Tracker II is Shareware. It offers a very flashy interface and has a -game embedded, but the IT file format is more powerful and better defined. By -all means try them both and see which you prefer; it is largely a matter of -taste (and, in some cases, religion). Impulse Tracker and Scream Tracker 3 -are Freeware, although you can donate to Impulse Tracker and receive a -slightly upgraded version. DUMB is likely to be at its best with IT files. - -These editors are DOS programs. Users of DOS-incapable operating systems may -like to try ModPlug Tracker, but should read docs/modplug.txt before using it -for any serious work. If you use a different operating system, or if you know -of any module editors for Windows that are more faithful to the original -trackers' playback, please give me some links so I can put them here! - - ModPlug Tracker - http://www.modplug.com/ - -If you have an x86 Linux system with VGA-compatible hardware (which covers -all PC graphics cards I've ever seen), you should be able to get Impulse -Tracker running with DOSEMU. You will have to give it access to the VGA ports -and run it in a true console, as it will not work with the X-based VGA -emulation. I personally added the SB16 emulation to DOSEMU, so you can even -use filters! However, it corrupts samples alarmingly often when saving on my -system - probably a DOSEMU issue. If you set this up, I am curious to know -whether it works for you. - - DOSEMU - http://www.dosemu.org/ - -BEWARE OF WINAMP! Although it's excellent for MP3s, it is notorious for being -one of the worst module players in existence; very many modules play wrongly -with it. There are plug-ins available to improve Winamp's module support, for -example WSP. - - Winamp - http://www.winamp.com/ - WSP - http://www.spytech.cz/index.php?sec=demo - -(There is a Winamp plug-in that uses DUMB, but it is unreliable. If anyone -would like to work on it, please get in touch.) - -While I am at it I should also point out that Winamp is notorious for -containing security flaws. Install it at your own risk, and if it is your -work computer, check with your boss first! - -Samples and instruments are the building blocks of music modules. You can -download samples at - - http://www.tump.net/ - -If you would like to download module files composed by other people, check -the following sites: - - http://www.modarchive.com/ - http://www.scene.org/ - http://www.tump.net/ - http://www.homemusic.cc/main.php - http://www.modplug.com/ - -Once again, if you know of more sites where samples or module files are -available for download, please let me know. - -If you wish to use someone's music in your game, please respect the -composer's wishes. In general, you should ask the composer. Music that has -been placed in the Public Domain can be used by anyone for anything, but it -wouldn't do any harm to ask anyway if you know who the author is. In many -cases the author will be thrilled, so don't hesitate! - -A note about converting modules from one format to another, or converting -from MIDI: don't do it, unless you are a musician and are prepared to go -through the file and make sure everything sounds the way it should! The -module formats are all slightly different, and MIDI is very different; -converting from one format to another will usually do some damage. - -Instead, it is recommended that you allow DUMB to interpret the original file -as it sees fit. DUMB may make mistakes (it does a lot of conversion on -loading), but future versions of DUMB will be able to rectify these mistakes. -On the other hand, if you convert the file, the damage is permanent. - - -*********************** -*** Contact details *** -*********************** - - -If you have trouble with DUMB, or want to contact me for any other reason, my -e-mail address is given below. Please do get in touch, even if I appear to -have disappeared! - -If you wish to chat online about something, perhaps on IRC, that can most -likely be arranged. Send me an e-mail. - - -****************** -*** Conclusion *** -****************** - - -This is the conclusion. - - -Ben Davis -entheh@users.sf.net diff --git a/libraries/dumb/release.txt b/libraries/dumb/release.txt deleted file mode 100644 index 527d44933..000000000 --- a/libraries/dumb/release.txt +++ /dev/null @@ -1,561 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * release.txt - Release notes for DUMB. / / \ \ - * | < / \_ - * | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - -******************************************* -*** DUMB v0.9.3, released 7 August 2005 *** -******************************************* - -Hello! Welcome to a long-awaited-or-probably-just-given-up-on-by-everybody -release! New to this release are lower memory usage, faster mixing loops, -loading of text fields in the module files, and faster load functions for -projects that don't need to seek within the module or know its length. -Additionally, Chad Austin has contributed a dumb2wav tool for converting -modules to .wav files and updated the Visual Studio 6 project files to -compile all the examples as well as the library. Users of Unix-like systems -will be pleased to know that on Chad's suggestion I have made the build -system cope with variables such as $HOME or ${HOME} in the prefix. - -Chad has also contributed an Autotools build system, but neither of us -recommends its use. The Autotools are an evil black box, we haven't quite -managed to get it right, and goodness help you if it happens not to work for -you. The files are available in a separate download if you absolutely need -them. Notice that that download is almost twice as large as the rest of DUMB! - -Maybe we'll do SCons next time. - -Thanks to Chad for all his work. Chad is the author of Audiere, a portable -sound library which has started using DUMB for its module playback! Wahoo! - - http://audiere.sf.net/ - -There are three main optimisations that went into the mixing loops. - -First, I downloaded ModPlugXMMS and had a peek at the mixing code, which is -Public Domain. It uses look-up tables for the cubic mixing. I pinched the -idea, and that sped DUMB's cubic (best quality) resamplers up by a factor of -two or three. - -Secondly, the samples loaded from the file are now kept in 8-bit or 16-bit -format, whereas previously they were being converted to 24-bit-in-32-bit on -loading. This means the samples occupy a half or a quarter of the memory they -used to occupy. It also had the side-effect of speeding up the mixing loops, -but it meant I had to duplicate the resampling code. (It is all done with -macros in the source code, but it becomes two copies on the binary level.) - -Secondly, stereo samples and stereo mixing buffers are now kept in -interleaved format, where previously the two channels were done separately to -keep the code simpler. This change has made the library quite a bit bigger, -but has made the code run almost twice as fast for stereo output (tested for -modules whose samples are mostly mono)! - -DUMB is now as fast as ModPlugXMMS on my system. - -Some people have also commented that DUMB seems to take a long time loading -files. This is because immediately upon loading the file it runs the playback -engine over it up as far as the point of first loop, taking snapshots at 30- -second intervals to be used as references for fast seeking and finally -storing the playback time. Of course, most games don't need this. You can now -skip it by calling the _quick versions of the dumb_load_*(), dumb_read_*() or -dumb_register_dat_*() functions. Should you need the data later, you can call -dumb_it_do_initial_runthrough() to calculate it. Please note that this cannot -currently be done safely from a concurrent thread while the music is playing. - -As mentioned, DUMB loads the text fields in module files now. You can -retrieve the song title with duh_get_tag(). Sample names and file names and -instrument names and filenames, and the song message for IT files, are -available with a call to duh_get_it_sigdata() and various dumb_it_sd_*() -functions. Please note that text fields added as extensions by ModPlug -Tracker are not supported. - -DUMB's timing is ever so slightly more accurate. This is hardly noticeable, -but it has meant that the length computed will increase very slightly. - -There are many small playback fixes in this release: - -* The Lxx effect in XM files (set envelope position) is now supported. - -* Pattern looping is now correct for XM files. Bizarrely, an ordinary pattern - loop whose start point isn't the first row seems to cause the next pattern - to start at the row corresponding to the loop start point. That must have - been a headache for people creating XM files! Nevertheless, DUMB now - emulates this behaviour. If you have an XM file that was written in a - tracker other than Fast Tracker II and breaks in DUMB, you can get around - it by putting a D00 effect (break to row 0) right at the end of the pattern - containing the loop. - -* XM pattern looping can be infinite. DUMB should detect this and call the - loop callback when it happens. Specifically, it has a loop counter for each - channel, so each time it sets or decrements that counter, it remembers the - loop end point for that channel. When the loop terminates, the loop end - point is reset to 0. If the loop end point ever decreases during a loop, - the loop callback is called. If anyone manages to get around this check and - prevent DUMB from calling the callback, please let me know and send me an - illustrative XM file! - -* For IT files, notes are now removed from channels if they have faded out, - even if they are still in the foreground. After this has happened, a row - with a note and Gxx (tone portamento) specified will cause a new note to - start playing, which is what Impulse Tracker does in this scenario. - (Normally, Gxx prevents the new note from playing and instead causes the - old note to start sliding towards the new note.) - -* If a tone portamento command occurred when no note was playing, the effect - value wasn't stored. This has been fixed. Thanks to Maim from #trax on - EFnet for discovering this bug. - -* DUMB now treats the parameter to the undocumented XM key off effect Kxx as - a delay, consistent with Fast Tracker II's behaviour. It has also been made - not to clear the note, so a subsequent volume command will restore it, as - in Fast Tracker II. - -* DUMB used to process the first row when you created the - DUMB_IT_SIGRENDERER. This happened before you had a chance to install any - callbacks. If an F00 effect occurred on the first row, the music would stop - immediately and the xm_speed_zero callback would be called if it were - present. Unfortunately, it wasn't present, and the algorithm for - calculating the length subsequently went into an endless loop while waiting - for it. Worse still, the same algorithm accumulated data for fast seeking, - and never stopped, so it pretty quickly consumed all the resources. DUMB - will now not process the first row until you first request some samples, - provided you pass zero for pos. Of course, any MOD or XM file with F00 in - the very first row won't do much anyway, but such files won't crash the - library now. - -* There was a subtle bug that affected a few XM files. For instruments with - no associated samples, the array mapping notes to samples is uninitialised. - This became a problem if such instruments were then used, which does happen - sometimes. On many systems, memory is initialised to zero when first given - to a program (for security reasons), so the problem didn't come up most of - the time. However, on platforms like DOS where memory isn't initialised, or - in programs that reuse memory later on (this includes the XMMS plug-in with - which I discovered the bug), a rogue note would occasionally play. This has - now been fixed. - -* DUMB's envelope handling for IT files was subtly wrong. Upon note off, it - stopped obeying the sustain loop points one tick too early. Notes were - often shorter than they should have been, and in pathological cases a whole - extra iteration of the sustain loop section might have been skipped. The - envelope code has now been rewritten. Thanks go to Allefant for Valgrinding - the new code! - -Finally, there were two build problems in the last version, which were fixed -in the download marked with -fixed. They are of course correct in this -version. For the record: - -* The make/config.bat file, responsible for generating make/config.txt, wrote - a crucial line to the wrong place, causing it to be left out of the file. - As a result, the makefile would fail to install everything for Allegro - users, and enter infinite recursion for other users. This applied to people - using DJGPP and MinGW. - -* DUMB's Makefile was supposed to install the example programs on Unix-based - platforms, but it wasn't doing. The fix was to edit Makefile and change the - one occurrence of $COMSPEC to $(COMSPEC). - -That's it! I hope you enjoy this long-awaited-or-probably-just-given-up-on- -by-everybody release of DUMB! - - -****************************************** -*** DUMB v0.9.2, released 2 April 2003 *** -****************************************** - -Yes, there really has been a release. This is not a day-late April fools' -joke. - -DUMB's full name has changed! The old "Dedicated Universal Music -Bastardisation" was rather silly, and not much more than a forced attempt at -finding words beginning with D, U, M and B. I spent weeks and weeks browsing -dictionaries and hopelessly asking others for bright ideas, until the -brilliant Chris "Kitty Cat" Robinson came up with "Dynamic". I decided to -keep the U as Universal, since a DUH struct can hold digital music in any -format. Now all that remained was the B, but it didn't take me long to come -up with Bibliotheque, which, despite looking French, is indeed considered an -English word by Oxford English Dictionary Online, to which my university has -a subscription. So there you have it - the name now makes sense. - -The two most significant additions to the project would have to be the new -thread safety (with an important restriction, detailed in docs/dumb.txt), and -the new build system. The silly 'makeall' and 'makecore' scripts are gone. If -you are a GCC user, all you need do now is run 'make' and 'make install', as -for other projects. You don't even have to run a 'fix' script any more! There -are some caveats, which are covered in readme.txt. If you use Microsoft -Visual C++ 6, you no longer need to obtain GCC and GNU Make - there is a -project file just for you. - -Huge thanks go to Steve Terry for testing on Windows XP - about five times - -and to lillo for testing on BeOS and Mac OS X. Thanks also to X-G for testing -on a Windows system that has consistently posed problems for DUMB's old -makefiles. - -There was a bug whereby al_poll_duh() would sometimes cause the music to -resume playing if you called it after al_pause_duh(). Whether this was DUMB's -fault for misusing Allegro's API, or a bug in Allegro, is unclear, but this -release makes it work. - -In one of my projects, I found that my AL_DUH_PLAYER stopped playing when -there were lots of other sound effects. In order to fix this, I programmed -DUMB to set the priority of the stream's voice to 255, the maximum. I also -added al_duh_set_priority(), so you can set the priority yourself if you need -to. - -The resampling code has undergone a transformation. The bad news is that the -linear average code is no longer in use. The good news is that where DUMB's -resamplers used to require three extra samples' worth of memory to be -allocated and initialised, it now copes with just the sample data. And it -does a very good job at bouncing off loop points and otherwise hurtling -around the sample. The resampling code is considerably more complicated, but -the code that uses the resamplers is considerably simpler - and if you -noticed a slight click in some bidirectionally looping samples, you'll be -pleased to know that that click is gone! - -I have also devoted some effort to optimisation. It seemed hopeless for a -while, but then I actually figured out a way of making it faster AND more -accurate at the same time! DUMB is now quite a bit faster than it was, and it -mixes not with 16-bit precision, but with 24-bit precision. (It used 32-bit -integers all along, but the difference is that it now makes use of 256 times -as much of the integer's range.) - -There have been the usual improvements to playback. The last release occurred -rather too soon after I had fixed the XM effect memories; EAx and EBx, fine -volume ramps, had been neglected. These are now handled properly. - -In previous versions of DUMB, muted channels in IT were actually played with -surround sound panning (where the right-hand channel is inverted). This has -been fixed, so muted channels will really be muted now. - -There were also some subtle problems with the way DUMB handled New Note -Actions for IT files. It turned out that, in all releases of DUMB so far, -pitch, filter and panning envelopes and sample vibrato were not being -processed for any note that was forced into the background by a new note on -the same channel! This only affected IT files. Not only has this been fixed, -but envelope interpolation is much more accurate. Long trailing envelope- -driven fade-outs sound a lot better now! - -Since panning and filter envelopes are more precise, extra fields have been -added to the DUMB_IT_CHANNEL_STATE struct, used by -dumb_it_sr_get_channel_state(). These fields hold the 'decimal' parts of the -pan and filter cut-off. See dumb.txt for details. - -Mxx (set channel volume) now correctly only modifies the last note played on -the channel, not any previous notes that have been forced into the background -by New Note Actions, and filter effect processing is now closer to what -Impulse Tracker does. - -The XM loader was slightly flawed and could crash on files containing samples -with out-of-range loop points. One such file was given to me. This has been -fixed. - -Finally, the legal stuff. Julien Cugniere has been added to the list of -copyright owners. He deserves it, for all the work he did on the XM support! -And the licence has been changed. You are no longer required to include a -link to DUMB in a project that uses DUMB; the reasons for this relaxation are -explained in licence.txt. However, the request is still there ... - -As usual, enjoy! - - -********************************************** -*** DUMB v0.9.1, released 19 December 2002 *** -********************************************** - -Hi again! Lots to say this time, so I shall cut right to the chase. - -DUMB now supports Impulse Tracker's low-pass resonant filters! Huge thanks go -to Jeffrey Lim, author of Impulse Tracker, for giving me what information he -still had regarding the algorithm; to cut a long story short, modifying -ModPlug Tracker's source code (which is in the Public Domain) led to an -algorithm whose output matched Impulse Tracker's perfectly. - -Please note that ModPlug Tracker's filters as they stand do not match Impulse -Tracker's, and I have no interest in supporting ModPlug Tracker's variant -(especially not the integer rounding problems). Please see docs/modplug.txt, -new in this release, for details. - -Thanks also go to Fatso Huuskonen for motivating me to add filter support, -and providing me with several great IT files to test it with! - -The other important feature added for this release is click removal. Up until -now, DUMB has generated clicks when cutting notes, starting samples in the -middle, and so on. This version of DUMB will remove any such clicks. Note -that DUMB does not use volume ramps to accomplish this; the algorithm will -not take the bite out of the music! - -In other news, DUMB now supports sample vibrato for IT files, and instrument -vibrato for XM files. A slight bug in New Note Action handling for IT files -has been fixed; Note Fade will not break the sustain loops of the sample and -envelope, as it did before. Tremor handling (Ixy) had a strange bug in it, -which has been fixed. - -Support for XM files has been greatly enhanced. The XM envelope handling new -in the last release contained a huge bug, resulting in notes seeming not to -stop when they should; this has been fixed. Some XM files crashed DUMB, while -others failed to load; these problems have been solved. Effect memories now -work properly for XM and MOD files, to the best of my knowledge. Some other -differences between IT and XM have been accounted for, most notably the -Retrigger Note effects, Rxy and E9x. - -DUMB's sound quality and accuracy are not the only areas that have been -enhanced. The API has been expanded, at last. You can now detect when a -module loops, or make it play through just once. You can ask DUMB to inform -you every time it generates some samples; this is useful for visualisation. -For IT files, you can intercept the MIDI messages generated by Zxx macros, -enabling you to synchronise your game with the music to some extent. (There -is no such method for XM, S3M or MOD files yet; sorry. Also note that the -function will be called before you actually hear the sound; I cannot improve -this until DUMB has its own sound drivers, which won't be for a while.) You -can query the current order and row. Finally, operations like changing the -speed and tempo are now possible, and you can query the playback state on -each channel. - -Some parts of DUMB's API have been deprecated. Simple programs that use -Allegro will be unaffected, but if you get some compiler warnings or errors, -please review docs/deprec.txt. This file explains why those parts of the API -were deprecated, and tells you how to adapt your code; the changes you need -to make are straightforward. Sorry for the inconvenience. - -For various reasons, I have made DUMB's makefiles use different compiler -flags depending on your GCC version (unless you are using MSVC). There is no -elegant way of getting the makefiles to detect when GCC is upgraded. If you -upgrade GCC, you should execute 'make clean' in order to make DUMB detect the -GCC version again. Otherwise you may get some annoying error messages. (It is -wise to do this in any case, so that all the object files are built with the -same GCC version.) - -DUMB's example players have been unified into a single player called -'dumbplay'. The player has been enhanced to display messages when the music -loops, and when XM and MOD files freeze (effect F00; more information on this -in docs/howto.txt). - -Finally, as noted on DUMB's website, the release notes from the last release -were inaccurate. It has been verified that DUMBOGG v0.5 does still work with -that release, and still works with this release. The esoteric DUMBOGG v0.6 -has not been created yet, since DUMBOGG v0.5 still works. - -Please scroll down and read through the indented paragraphs in the notes for -the last release; they are relevant for this release too. - -That's all folks! Until next time. - - -******************************************* -*** DUMB v0.9, released 16 October 2002 *** -******************************************* - -MOD support is here! DUMB now supports all four of the common module formats. -As usual, there have also been some improvements to the way modules are -played back. Most notably, handling of tone portamento in IT files has been -improved a lot, and XM envelopes are now processed correctly. - -The other major change is that DUMB now does a dummy run through each module -on loading. It stores the playback state at thirty-second intervals. It stops -when the module first loops, and then stores the playback time. This results -in a slightly longer load time and a greater memory overhead, but seeking is -faster (to any point before the module first loops) and the length is -calculated! duh_get_length() will return this and is now documented in -docs/howto.txt and docs/dumb.txt. - -DUMB's build process has been changed to use 'mingw' wherever it used -'mingw32' before; some directories have been renamed, and the 'fix' command -you had to run for MinGW has been changed from 'fix mingw32' to 'fix mingw'. - -Last time, I directed you to scroll down and read the notes from a past -release, but ignore this point, and that point applies to something else, and -so on. Did anyone do so? Well, if you're reading this at all, you probably -did. Nevertheless, this time I shall be much less confusing and restate any -relevant information. So the least you can do is read it! - -- If your program ever aborts with exit code 37 while loading an IT file, - PLEASE LET ME KNOW! The IT file in question has a stereo compressed sample - in it, and the format is unspecified for this case (Impulse Tracker itself - doesn't use stereo samples at all). I will need the IT file in question, - and any information you can give me about how the IT file was created (e.g. - what program). (If you don't get to see an exit code, let me know anyway.) - -- If your program ever outputs a line resembling "Inst 01 Env: 0,64 8,32 - 15,48" to stderr while loading an IT file, PLEASE LET ME KNOW! You have an - old IT file (saved by an Impulse Tracker version older than 2.00), and - support for such files is STILL untested. - -- Not all parts of DUMB's API are documented yet. You will find some - functions in dumb.h which are not listed in docs/dumb.txt; the reason is - that these functions still need work and will probably change. If you - really, really want to use them, talk to me first (IRC EFnet #dumb is a - good place for this; see readme.txt for details on using IRC). I intend to - finalise and document the whole of DUMB's API for Version 1.0. - -There have been some changes to the naming conventions in DUMB's undocumented -API. DUMBOGG v0.5 will not work with this and subsequent releases of DUMB; -please upgrade to DUMBOGG v0.6. These changes should not break anything in -your own code, since you didn't use those parts of the API, did you ;) - -There is still a great deal of work to be done before DUMB's API can be -finalised, and thus it will be a while before DUMB v1.0 comes out. It should -be worth the wait. In the meantime, there will be 0.9.x releases with -additional functionality, improved playback, and possibly support for some -extra file formats. - -Finally I should like to offer an apology; there is a strong possibility that -some of DUMB's official API will change in the near future. There will not be -any drastic changes, and the corresponding changes to your source code will -be simple enough. If I didn't make these changes, DUMB's API would start to -become limited, or messy, or both, so it's for the better. I apologise in -advance for this. - -Now scroll down and read the notes for the first r... oh wait, we already did -that. I guess that's it then. You can stop reading now. - -Right after you've read this. - -And this. - -Off you go. - -Bye. - - -******************************************** -*** DUMB v0.8.1, released 11 August 2002 *** -******************************************** - -This is a minor release that fixes a few bugs. One of these bugs, however, -was pretty serious. dumb_register_dat_xm() was never coded! It was prototyped -in aldumb.h, so code would compile, but there would be an unresolved symbol -at the linking stage. This has been fixed. - -Platforms other than Unix did not have a working 'make veryclean' target; -this has been fixed. In addition, the makefiles now use 'xcopy' instead of -'copy', since on some systems GNU Make seems to have trouble calling commands -built in to the shell. - -Contrary to the errata that was on the DUMB website, the makeall.sh and -makecore.sh scripts actually DID install in /usr. This has now been -corrected, and regardless of whether you use these scripts or call make -directly, the files will now be installed to /usr/local by default. - -The XM loader used to treat stereo samples as mono samples with the data for -the right channel positioned after the data for the left channel. This -generally resulted in an unwanted echo effect. This has been fixed. - -When playing XM files, specifying an invalid instrument would cause an old -note on that channel to come back (roughly speaking). Fast Tracker 2 does not -exhibit this behaviour. This has been fixed. - -The GCC makefiles used -mpentium, which is deprecated in gcc 3.x. This was -generating warnings, and has now been fixed. - -In XM files, the length of a sample is stored in bytes. DUMB was assuming -that the length of a 16-bit sample would be even. I had two XM files where -this was not the case, and DUMB was unable to load them. This has been fixed. - -In order to accommodate the extra part of the version number, -DUMB_REVISION_VERSION has been added. DUMB_VERSION has also been added in -order to facilitate checking if the version of DUMB installed is sufficient. -See docs/dumb.txt for details. - -As a last-minute fix, the XM "Break to row" effect is now loaded properly. It -was necessary to convert from binary-coded decimal to hexadecimal (those who -have experience with Fast Tracker 2 will know what I mean). In short, this -means the effect will now work properly when breaking to row 10 or greater. - -DUMB v0.8 had faulty release date constants; DUMB_MONTH and DUMB_DAY were -swapped! For this reason, DUMB_DATE should not be compared against any date -in 2002. This note has been added to docs/dumb.txt and also to dumb.h. - -Please scroll to the end and read the release notes for the first version, -DUMB v0.7. Most of them apply equally to this release. However, the -non-portable code was rewritten for DUMB v0.8, so that point does not apply. -The point about length not being calculated also applies to XM files. - -Enjoy :) - - -**************************************** -*** DUMB v0.8, released 14 June 2002 *** -**************************************** - -Welcome to the second release of DUMB! - -In addition to these notes, please read below the release notes for the -previous version, DUMB v0.7. Most of them apply equally to this release. -However, the non-portable code has been rewritten; DUMB should now port to -big-endian platforms. - -The main improvement in this release of DUMB is the support for XM files. -Enormous thanks go to Julien Cugniere for working on this while I had to -revise for my exams! - -There was a mistake in the makefiles in the last release. The debugging -Allegro interface library was mistakenly named libaldmbd.a instead of -libaldmd.a, meaning you had to compile with -laldmbd, contrary to what the -docs said. Apologies to everyone who lost sleep trying to work out what was -wrong! The reason for using libaldmd.a is to maintain compatibility with -plain DOS, where filenames are limited to eight characters (plus a three- -letter extension). The makefiles have now been changed to match the -information in the docs, so you may have to alter your project files -accordingly. - -The example programs were faulty, and crashed on Windows if they were unable -to load the file. It was also difficult to work out how to exit them (you had -to click the taskbar button that didn't have a window, then press a key). -They have been improved in both these respects. - -I have now added a docs/faq.txt file (Frequently Asked Questions), which is -based on problems and misconceptions people have had with the first release. -Please refer to it before contacting me with problems. - -Thanks to networm for touching up the Unix makefile and writing the -instructions on using it. - -Incidentally, today (Friday 14 June) is the Robinson College May Ball at -Cambridge Uni. God knows why it's called a May Ball if it's in June. I'm not -going myself (72 GBP, and I'd have to wear a suit, ugh), but with all the -noise outside I shall enjoy pumping up the speakers tonight! - - -**************************************** -*** DUMB v0.7, released 2 March 2002 *** -**************************************** - -This is the first release of DUMB, and parts of the library are not -crystallised. Don't let this put you off! Provided you don't try to use any -features that aren't documented in docs/dumb.txt, the library should be rock -solid and you should be able to upgrade more or less without problems. - -Here are some notes on this release: - -- There is some non-portable code in this release of DUMB. It is likely that - the library will fail to load IT files with compressed samples on - big-endian machines such as the Apple Macintosh. - -- If your program ever aborts with exit code 37 while loading an IT file, - PLEASE LET ME KNOW! The IT file in question has a stereo compressed sample - in it, and the format is unspecified for this case (Impulse Tracker itself - doesn't use stereo samples at all). I will need the IT file in question, - and any information you can give me about how the IT file was created (e.g. - what program). (If you don't get to see an exit code, let me know anyway.) - -- If your program ever outputs a line resembling "Inst 01 Env: 0,64 8,32 - 15,48" to stderr while loading an IT file, PLEASE LET ME KNOW! You have an - old IT file (saved by an Impulse Tracker version older than 2.00), and - support for such files is untested. - -- The length of IT and S3M files is not currently calculated. It is just set - to ten minutes. diff --git a/libraries/dumb/src/core/atexit.c b/libraries/dumb/src/core/atexit.c deleted file mode 100644 index 16c6abdb2..000000000 --- a/libraries/dumb/src/core/atexit.c +++ /dev/null @@ -1,71 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * atexit.c - Library Clean-up Management. / / \ \ - * | < / \_ - * By entheh. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -typedef struct DUMB_ATEXIT_PROC -{ - struct DUMB_ATEXIT_PROC *next; - void (*proc)(void); -} -DUMB_ATEXIT_PROC; - - - -static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL; - - - -int dumb_atexit(void (*proc)(void)) -{ - DUMB_ATEXIT_PROC *dap = dumb_atexit_proc; - - while (dap) { - if (dap->proc == proc) return 0; - dap = dap->next; - } - - dap = malloc(sizeof(*dap)); - - if (!dap) - return -1; - - dap->next = dumb_atexit_proc; - dap->proc = proc; - dumb_atexit_proc = dap; - - return 0; -} - - - -void dumb_exit(void) -{ - while (dumb_atexit_proc) { - DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next; - (*dumb_atexit_proc->proc)(); - free(dumb_atexit_proc); - dumb_atexit_proc = next; - } -} diff --git a/libraries/dumb/src/core/duhlen.c b/libraries/dumb/src/core/duhlen.c deleted file mode 100644 index 4570f1508..000000000 --- a/libraries/dumb/src/core/duhlen.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * duhlen.c - Functions to set and return the / / \ \ - * length of a DUH. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * Note that the length of a DUH is a constant | ' / - * stored in the DUH struct and in the DUH disk \__/ - * format. It will be calculated on loading for - * other formats in which the length is not explicitly stored. Also note that - * it does not necessarily correspond to the length of time for which the DUH - * will generate samples. Rather it represents a suitable point for a player - * such as Winamp to stop, and in any good DUH it will allow for any final - * flourish to fade out and be appreciated. - */ - -#include "dumb.h" -#include "internal/dumb.h" - - - -int32 DUMBEXPORT duh_get_length(DUH *duh) -{ - return duh ? duh->length : 0; -} - - - -void DUMBEXPORT duh_set_length(DUH *duh, int32 length) -{ - if (duh) - duh->length = length; -} diff --git a/libraries/dumb/src/core/duhtag.c b/libraries/dumb/src/core/duhtag.c deleted file mode 100644 index 95664d58b..000000000 --- a/libraries/dumb/src/core/duhtag.c +++ /dev/null @@ -1,38 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * duhtag.c - Function to return the tags stored / / \ \ - * in a DUH struct (typically author | < / \_ - * information). | \/ /\ / - * \_ / > / - * By entheh. | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -const char *DUMBEXPORT duh_get_tag(DUH *duh, const char *key) -{ - int i; - ASSERT(key); - if (!duh || !duh->tag) return NULL; - - for (i = 0; i < duh->n_tags; i++) - if (strcmp(key, duh->tag[i][0]) == 0) - return duh->tag[i][1]; - - return NULL; -} diff --git a/libraries/dumb/src/core/dumbfile.c b/libraries/dumb/src/core/dumbfile.c deleted file mode 100644 index f0876b752..000000000 --- a/libraries/dumb/src/core/dumbfile.c +++ /dev/null @@ -1,418 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * dumbfile.c - Hookable, strictly sequential / / \ \ - * file input functions. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" - - - -static const DUMBFILE_SYSTEM *the_dfs = NULL; - - - -void DUMBEXPORT register_dumbfile_system(const DUMBFILE_SYSTEM *dfs) -{ - ASSERT(dfs); - ASSERT(dfs->open); - ASSERT(dfs->getc); - ASSERT(dfs->close); - ASSERT(dfs->seek); - ASSERT(dfs->get_size); - the_dfs = dfs; -} - - - -#include "internal/dumbfile.h" - - - -DUMBFILE *DUMBEXPORT dumbfile_open(const char *filename) -{ - DUMBFILE *f; - - ASSERT(the_dfs); - - f = (DUMBFILE *) malloc(sizeof(*f)); - - if (!f) - return NULL; - - f->dfs = the_dfs; - - f->file = (*the_dfs->open)(filename); - - if (!f->file) { - free(f); - return NULL; - } - - f->pos = 0; - - return f; -} - - - -DUMBFILE *DUMBEXPORT dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs) -{ - DUMBFILE *f; - - ASSERT(dfs); - ASSERT(dfs->getc); - ASSERT(file); - - f = (DUMBFILE *) malloc(sizeof(*f)); - - if (!f) { - if (dfs->close) - (*dfs->close)(file); - return NULL; - } - - f->dfs = dfs; - f->file = file; - - f->pos = 0; - - return f; -} - - - -int32 DUMBEXPORT dumbfile_pos(DUMBFILE *f) -{ - ASSERT(f); - - return f->pos; -} - - - -int DUMBEXPORT dumbfile_skip(DUMBFILE *f, long n) -{ - int rv; - - ASSERT(f); - ASSERT(n >= 0); - - if (f->pos < 0) - return -1; - - f->pos += n; - - if (f->dfs->skip) { - rv = (*f->dfs->skip)(f->file, n); - if (rv) { - f->pos = -1; - return rv; - } - } else { - while (n) { - rv = (*f->dfs->getc)(f->file); - if (rv < 0) { - f->pos = -1; - return rv; - } - n--; - } - } - - return 0; -} - - - -int DUMBEXPORT dumbfile_getc(DUMBFILE *f) -{ - int rv; - - ASSERT(f); - - if (f->pos < 0) - return -1; - - rv = (*f->dfs->getc)(f->file); - - if (rv < 0) { - f->pos = -1; - return rv; - } - - f->pos++; - - return rv; -} - - - -int DUMBEXPORT dumbfile_igetw(DUMBFILE *f) -{ - int l, h; - - ASSERT(f); - - if (f->pos < 0) - return -1; - - l = (*f->dfs->getc)(f->file); - if (l < 0) { - f->pos = -1; - return l; - } - - h = (*f->dfs->getc)(f->file); - if (h < 0) { - f->pos = -1; - return h; - } - - f->pos += 2; - - return l | (h << 8); -} - - - -int DUMBEXPORT dumbfile_mgetw(DUMBFILE *f) -{ - int l, h; - - ASSERT(f); - - if (f->pos < 0) - return -1; - - h = (*f->dfs->getc)(f->file); - if (h < 0) { - f->pos = -1; - return h; - } - - l = (*f->dfs->getc)(f->file); - if (l < 0) { - f->pos = -1; - return l; - } - - f->pos += 2; - - return l | (h << 8); -} - - - -int32 DUMBEXPORT dumbfile_igetl(DUMBFILE *f) -{ - uint32 rv, b; - - ASSERT(f); - - if (f->pos < 0) - return -1; - - rv = (*f->dfs->getc)(f->file); - if ((sint32)rv < 0) { - f->pos = -1; - return rv; - } - - b = (*f->dfs->getc)(f->file); - if ((sint32)b < 0) { - f->pos = -1; - return b; - } - rv |= b << 8; - - b = (*f->dfs->getc)(f->file); - if ((sint32)b < 0) { - f->pos = -1; - return b; - } - rv |= b << 16; - - b = (*f->dfs->getc)(f->file); - if ((sint32)b < 0) { - f->pos = -1; - return b; - } - rv |= b << 24; - - f->pos += 4; - - return rv; -} - - - -int32 DUMBEXPORT dumbfile_mgetl(DUMBFILE *f) -{ - uint32 rv, b; - - ASSERT(f); - - if (f->pos < 0) - return -1; - - rv = (*f->dfs->getc)(f->file); - if ((sint32)rv < 0) { - f->pos = -1; - return rv; - } - rv <<= 24; - - b = (*f->dfs->getc)(f->file); - if ((sint32)b < 0) { - f->pos = -1; - return b; - } - rv |= b << 16; - - b = (*f->dfs->getc)(f->file); - if ((sint32)b < 0) { - f->pos = -1; - return b; - } - rv |= b << 8; - - b = (*f->dfs->getc)(f->file); - if ((sint32)b < 0) { - f->pos = -1; - return b; - } - rv |= b; - - f->pos += 4; - - return rv; -} - - - -uint32 DUMBEXPORT dumbfile_cgetul(DUMBFILE *f) -{ - uint32 rv = 0; - int v; - - do { - v = dumbfile_getc(f); - - if (v < 0) - return v; - - rv <<= 7; - rv |= v & 0x7F; - } while (v & 0x80); - - return rv; -} - - - -sint32 DUMBEXPORT dumbfile_cgetsl(DUMBFILE *f) -{ - uint32 rv = dumbfile_cgetul(f); - - if (f->pos < 0) - return rv; - - return (rv >> 1) | (rv << 31); -} - - - -int32 DUMBEXPORT dumbfile_getnc(char *ptr, int32 n, DUMBFILE *f) -{ - int32 rv; - - ASSERT(f); - ASSERT(n >= 0); - - if (f->pos < 0) - return -1; - - if (f->dfs->getnc) { - rv = (*f->dfs->getnc)(ptr, n, f->file); - if (rv < n) { - f->pos = -1; - return MAX(rv, 0); - } - } else { - for (rv = 0; rv < n; rv++) { - int c = (*f->dfs->getc)(f->file); - if (c < 0) { - f->pos = -1; - return rv; - } - *ptr++ = c; - } - } - - f->pos += rv; - - return rv; -} - - - -int DUMBEXPORT dumbfile_seek(DUMBFILE *f, long n, int origin) -{ - switch ( origin ) - { - case DFS_SEEK_CUR: n += f->pos; break; - case DFS_SEEK_END: n += (*f->dfs->get_size)(f->file); break; - } - f->pos = n; - return (*f->dfs->seek)(f->file, n); -} - - - -int32 DUMBEXPORT dumbfile_get_size(DUMBFILE *f) -{ - return (*f->dfs->get_size)(f->file); -} - - - -int DUMBEXPORT dumbfile_error(DUMBFILE *f) -{ - ASSERT(f); - - return f->pos < 0; -} - - - -int DUMBEXPORT dumbfile_close(DUMBFILE *f) -{ - int rv; - - ASSERT(f); - - rv = f->pos < 0; - - if (f->dfs->close) - (*f->dfs->close)(f->file); - - free(f); - - return rv; -} diff --git a/libraries/dumb/src/core/loadduh.c b/libraries/dumb/src/core/loadduh.c deleted file mode 100644 index 2891298f9..000000000 --- a/libraries/dumb/src/core/loadduh.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadduh.c - Code to read a DUH from a file, / / \ \ - * opening and closing the file for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/dumb.h" - - - -/* load_duh(): loads a .duh file, returning a pointer to a DUH struct. - * When you have finished with it, you must pass the pointer to unload_duh() - * so that the memory can be freed. - */ -DUH *DUMBEXPORT load_duh(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = read_duh(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/core/makeduh.c b/libraries/dumb/src/core/makeduh.c deleted file mode 100644 index 1c2695cfb..000000000 --- a/libraries/dumb/src/core/makeduh.c +++ /dev/null @@ -1,151 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * makeduh.c - Function to construct a DUH from / / \ \ - * its components. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata) -{ - DUH_SIGNAL *signal; - - ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer)); - ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample); - - signal = malloc(sizeof(*signal)); - - if (!signal) { - if (desc->unload_sigdata) - if (sigdata) - (*desc->unload_sigdata)(sigdata); - return NULL; - } - - signal->desc = desc; - signal->sigdata = sigdata; - - return signal; -} - - - -DUH *make_duh( - int32 length, - int n_tags, - const char *const tags[][2], - int n_signals, - DUH_SIGTYPE_DESC *desc[], - sigdata_t *sigdata[] -) -{ - DUH *duh = malloc(sizeof(*duh)); - int i; - int fail; - - if (duh) { - duh->n_signals = n_signals; - - duh->signal = malloc(n_signals * sizeof(*duh->signal)); - - if (!duh->signal) { - free(duh); - duh = NULL; - } - } - - if (!duh) { - for (i = 0; i < n_signals; i++) - if (desc[i]->unload_sigdata) - if (sigdata[i]) - (*desc[i]->unload_sigdata)(sigdata[i]); - return NULL; - } - - duh->n_tags = 0; - duh->tag = NULL; - - fail = 0; - - for (i = 0; i < n_signals; i++) { - duh->signal[i] = make_signal(desc[i], sigdata[i]); - if (!duh->signal[i]) - fail = 1; - } - - if (fail) { - unload_duh(duh); - return NULL; - } - - duh->length = length; - - { - int mem = n_tags * 2; /* account for NUL terminators here */ - char *ptr; - - for (i = 0; i < n_tags; i++) - mem += (int)(strlen(tags[i][0]) + strlen(tags[i][1])); - - if (mem <= 0) return duh; - - duh->tag = malloc(n_tags * sizeof(*duh->tag)); - if (!duh->tag) return duh; - duh->tag[0][0] = malloc(mem); - if (!duh->tag[0][0]) { - free(duh->tag); - duh->tag = NULL; - return duh; - } - duh->n_tags = n_tags; - ptr = duh->tag[0][0]; - for (i = 0; i < n_tags; i++) { - duh->tag[i][0] = ptr; - strcpy(ptr, tags[i][0]); - ptr += strlen(tags[i][0]) + 1; - duh->tag[i][1] = ptr; - strcpy(ptr, tags[i][1]); - ptr += strlen(tags[i][1]) + 1; - } - } - - return duh; -} - -int DUMBEXPORT duh_add_signal(DUH *duh, DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata) -{ - DUH_SIGNAL **signal; - - if ( !duh || !desc || !sigdata ) return -1; - - signal = ( DUH_SIGNAL ** ) realloc( duh->signal, ( duh->n_signals + 1 ) * sizeof( *duh->signal ) ); - if ( !signal ) return -1; - duh->signal = signal; - - memmove( signal + 1, signal, duh->n_signals * sizeof( *signal ) ); - duh->n_signals++; - - signal[ 0 ] = make_signal( desc, sigdata ); - if ( !signal[ 0 ] ) return -1; - - return 0; -} diff --git a/libraries/dumb/src/core/rawsig.c b/libraries/dumb/src/core/rawsig.c deleted file mode 100644 index 1651d06bc..000000000 --- a/libraries/dumb/src/core/rawsig.c +++ /dev/null @@ -1,58 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * rawsig.c - Function to retrieve raw signal / / \ \ - * data from a DUH provided you know | < / \_ - * what type of signal it is. | \/ /\ / - * \_ / > / - * By entheh. | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -/* You have to specify the type of sigdata, proving you know what to do with - * the pointer. If you get it wrong, you can expect NULL back. - */ -sigdata_t *DUMBEXPORT duh_get_raw_sigdata(DUH *duh, int sig, int32 type) -{ - int i; - DUH_SIGNAL *signal; - - if (!duh) return NULL; - - if ( sig >= 0 ) - { - if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL; - - signal = duh->signal[sig]; - - if (signal && signal->desc->type == type) - return signal->sigdata; - } - else - { - for ( i = 0; i < duh->n_signals; i++ ) - { - signal = duh->signal[i]; - - if (signal && signal->desc->type == type) - return signal->sigdata; - } - } - - return NULL; -} diff --git a/libraries/dumb/src/core/readduh.c b/libraries/dumb/src/core/readduh.c deleted file mode 100644 index 4c40c98e9..000000000 --- a/libraries/dumb/src/core/readduh.c +++ /dev/null @@ -1,107 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readduh.c - Code to read a DUH from an open / / \ \ - * file. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f) -{ - DUH_SIGNAL *signal; - int32 type; - - signal = malloc(sizeof(*signal)); - - if (!signal) - return NULL; - - type = dumbfile_mgetl(f); - if (dumbfile_error(f)) { - free(signal); - return NULL; - } - - signal->desc = _dumb_get_sigtype_desc(type); - if (!signal->desc) { - free(signal); - return NULL; - } - - if (signal->desc->load_sigdata) { - signal->sigdata = (*signal->desc->load_sigdata)(duh, f); - if (!signal->sigdata) { - free(signal); - return NULL; - } - } else - signal->sigdata = NULL; - - return signal; -} - - - -/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its - * pointer, or null on error. The file is not closed. - */ -DUH *DUMBEXPORT read_duh(DUMBFILE *f) -{ - DUH *duh; - int i; - - if (dumbfile_mgetl(f) != DUH_SIGNATURE) - return NULL; - - duh = malloc(sizeof(*duh)); - if (!duh) - return NULL; - - duh->length = dumbfile_igetl(f); - if (dumbfile_error(f) || duh->length <= 0) { - free(duh); - return NULL; - } - - duh->n_signals = dumbfile_igetl(f); - if (dumbfile_error(f) || duh->n_signals <= 0) { - free(duh); - return NULL; - } - - duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals); - if (!duh->signal) { - free(duh); - return NULL; - } - - for (i = 0; i < duh->n_signals; i++) - duh->signal[i] = NULL; - - for (i = 0; i < duh->n_signals; i++) { - if (!(duh->signal[i] = read_signal(duh, f))) { - unload_duh(duh); - return NULL; - } - } - - return duh; -} diff --git a/libraries/dumb/src/core/register.c b/libraries/dumb/src/core/register.c deleted file mode 100644 index 7d7cce533..000000000 --- a/libraries/dumb/src/core/register.c +++ /dev/null @@ -1,104 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * register.c - Signal type registration. / / \ \ - * | < / \_ - * By entheh. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL; -static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc; - - - -/* destroy_sigtypes(): frees all memory allocated while registering signal - * types. This function is set up to be called by dumb_exit(). - */ -static void destroy_sigtypes(void) -{ - DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next; - sigtype_desc = NULL; - sigtype_desc_tail = &sigtype_desc; - - while (desc_link) { - next = desc_link->next; - free(desc_link); - desc_link = next; - } -} - - - -/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal - * type is identified by a four-character string (e.g. "WAVE"), which you can - * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The - * signal's behaviour is defined by four functions, whose pointers you pass - * here. See the documentation for details. - * - * If a DUH tries to use a signal that has not been registered using this - * function, then the library will fail to load the DUH. - */ -void DUMBEXPORT dumb_register_sigtype(DUH_SIGTYPE_DESC *desc) -{ - DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc; - - ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata)); - ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer)); - ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample); - - if (desc_link) { - do { - if (desc_link->desc->type == desc->type) { - desc_link->desc = desc; - return; - } - desc_link = desc_link->next; - } while (desc_link); - } else - dumb_atexit(&destroy_sigtypes); - - desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK)); - - if (!desc_link) - return; - - desc_link->next = NULL; - sigtype_desc_tail = &desc_link->next; - - desc_link->desc = desc; -} - - - -/* _dumb_get_sigtype_desc(): searches the registered functions for a signal - * type matching the parameter. If such a sigtype is found, it returns a - * pointer to a sigtype descriptor containing the necessary functions to - * manage the signal. If none is found, it returns NULL. - */ -DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(int32 type) -{ - DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc; - - while (desc_link && desc_link->desc->type != type) - desc_link = desc_link->next; - - return desc_link ? desc_link->desc : NULL; -} diff --git a/libraries/dumb/src/core/rendduh.c b/libraries/dumb/src/core/rendduh.c deleted file mode 100644 index 71f6201d2..000000000 --- a/libraries/dumb/src/core/rendduh.c +++ /dev/null @@ -1,184 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * rendduh.c - Functions for rendering a DUH into / / \ \ - * an end-user sample format. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -/* On the x86, we can use some tricks to speed stuff up */ -#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__) -// Can't we detect Linux and other x86 platforms here? :/ - -#define FAST_MID(var, min, max) { \ - var -= (min); \ - var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \ - var += (min); \ - var -= (max); \ - var &= var >> (sizeof(var) * CHAR_BIT - 1); \ - var += (max); \ -} - -#define CONVERT8(src, pos, signconv) { \ - signed int f = (src + 0x8000) >> 16; \ - FAST_MID(f, -128, 127); \ - ((char*)sptr)[pos] = (char)f ^ signconv; \ -} - -#define CONVERT16(src, pos, signconv) { \ - signed int f = (src + 0x80) >> 8; \ - FAST_MID(f, -32768, 32767); \ - ((short*)sptr)[pos] = (short)(f ^ signconv); \ -} - -#else - -#define CONVERT8(src, pos, signconv) \ -{ \ - signed int f = (src + 0x8000) >> 16; \ - f = MID(-128, f, 127); \ - ((char *)sptr)[pos] = (char)f ^ signconv; \ -} - - - -#define CONVERT16(src, pos, signconv) \ -{ \ - signed int f = (src + 0x80) >> 8; \ - f = MID(-32768, f, 32767); \ - ((short *)sptr)[pos] = (short)(f ^ signconv); \ -} - -#endif - - - -/* DEPRECATED */ -DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, int32 pos) -{ - return duh_start_sigrenderer(duh, 0, n_channels, pos); -} - - - -int32 DUMBEXPORT duh_render( - DUH_SIGRENDERER *sigrenderer, - int bits, int unsign, - float volume, float delta, - int32 size, void *sptr -) -{ - int32 n; - - sample_t **sampptr; - - int n_channels; - - ASSERT(bits == 8 || bits == 16); - ASSERT(sptr); - - if (!sigrenderer) - return 0; - - n_channels = duh_sigrenderer_get_n_channels(sigrenderer); - - ASSERT(n_channels > 0); - /* This restriction will be removed when need be. At the moment, tightly - * optimised loops exist for exactly one or two channels. - */ - ASSERT(n_channels <= 2); - - sampptr = allocate_sample_buffer(n_channels, size); - - if (!sampptr) - return 0; - - dumb_silence(sampptr[0], n_channels * size); - - size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr); - - if (bits == 16) { - int signconv = unsign ? 0x8000 : 0x0000; - - for (n = 0; n < size * n_channels; n++) { - CONVERT16(sampptr[0][n], n, signconv); - } - } else { - char signconv = unsign ? 0x80 : 0x00; - - for (n = 0; n < size * n_channels; n++) { - CONVERT8(sampptr[0][n], n, signconv); - } - } - - destroy_sample_buffer(sampptr); - - return size; -} - - - -/* DEPRECATED */ -int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) -{ - return duh_sigrenderer_get_n_channels(dr); -} - - - -/* DEPRECATED */ -int32 duh_renderer_get_position(DUH_SIGRENDERER *dr) -{ - return duh_sigrenderer_get_position(dr); -} - - - -/* DEPRECATED */ -void duh_end_renderer(DUH_SIGRENDERER *dr) -{ - duh_end_sigrenderer(dr); -} - - - -/* DEPRECATED */ -DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) -{ - return sigrenderer; -} - - - -/* DEPRECATED */ -DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) -{ - return dr; -} - - - -/* DEPRECATED */ -DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) -{ - return dr; -} diff --git a/libraries/dumb/src/core/rendsig.c b/libraries/dumb/src/core/rendsig.c deleted file mode 100644 index 1e6fa1f88..000000000 --- a/libraries/dumb/src/core/rendsig.c +++ /dev/null @@ -1,348 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * rendsig.c - Wrappers to render samples from / / \ \ - * the signals in a DUH. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -struct DUH_SIGRENDERER -{ - DUH_SIGTYPE_DESC *desc; - - sigrenderer_t *sigrenderer; - - int n_channels; - - int32 pos; - int subpos; - - DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback; - void *callback_data; -}; - - - -DUH_SIGRENDERER *DUMBEXPORT duh_start_sigrenderer(DUH *duh, int sig, int n_channels, int32 pos) -{ - DUH_SIGRENDERER *sigrenderer; - - DUH_SIGNAL *signal; - DUH_START_SIGRENDERER proc; - - /* [RH] Mono destination mixers are disabled. */ - if (n_channels != 2) - return NULL; - - if (!duh) - return NULL; - - if ((unsigned int)sig >= (unsigned int)duh->n_signals) - return NULL; - - signal = duh->signal[sig]; - if (!signal) - return NULL; - - sigrenderer = malloc(sizeof(*sigrenderer)); - if (!sigrenderer) - return NULL; - - sigrenderer->desc = signal->desc; - - proc = sigrenderer->desc->start_sigrenderer; - - if (proc) { - duh->signal[sig] = NULL; - sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos); - duh->signal[sig] = signal; - - if (!sigrenderer->sigrenderer) { - free(sigrenderer); - return NULL; - } - } else - sigrenderer->sigrenderer = NULL; - - sigrenderer->n_channels = n_channels; - - sigrenderer->pos = pos; - sigrenderer->subpos = 0; - - sigrenderer->callback = NULL; - - return sigrenderer; -} - - -#ifdef DUMB_DECLARE_DEPRECATED -#include -void duh_sigrenderer_set_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_CALLBACK callback, void *data -) -{ - (void)sigrenderer; - (void)callback; - (void)data; - /*fprintf(stderr, - "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n" - "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/ -} - - - -void duh_sigrenderer_set_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data -) -{ - (void)sigrenderer; - (void)callback; - (void)data; - fprintf(stderr, - "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n" - "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n"); -} -#endif - - -void duh_sigrenderer_set_sample_analyser_callback( - DUH_SIGRENDERER *sigrenderer, - DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data -) -{ - if (sigrenderer) { - sigrenderer->callback = callback; - sigrenderer->callback_data = data; - } -} - - - -int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer) -{ - return sigrenderer ? sigrenderer->n_channels : 0; -} - - - -int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer) -{ - return sigrenderer ? sigrenderer->pos : -1; -} - - - -void DUMBEXPORT duh_sigrenderer_set_sigparam( - DUH_SIGRENDERER *sigrenderer, - unsigned char id, int32 value -) -{ - DUH_SIGRENDERER_SET_SIGPARAM proc; - - if (!sigrenderer) return; - - proc = sigrenderer->desc->sigrenderer_set_sigparam; - if (proc) - (*proc)(sigrenderer->sigrenderer, id, value); - else - TRACE("Parameter #%d = %d for signal %c%c%c%c, which does not take parameters.\n", - (int)id, - value, - (int)(sigrenderer->desc->type >> 24), - (int)(sigrenderer->desc->type >> 16), - (int)(sigrenderer->desc->type >> 8), - (int)(sigrenderer->desc->type)); -} - - - -int32 DUMBEXPORT duh_sigrenderer_generate_samples( - DUH_SIGRENDERER *sigrenderer, - double volume, double delta, - int32 size, sample_t **samples -) -{ - int32 rendered; - LONG_LONG t; - - if (!sigrenderer) return 0; - - rendered = (*sigrenderer->desc->sigrenderer_generate_samples) - (sigrenderer->sigrenderer, volume, delta, size, samples); - - if (rendered) { - if (sigrenderer->callback) - (*sigrenderer->callback)(sigrenderer->callback_data, - (const sample_t *const *)samples, sigrenderer->n_channels, rendered); - - t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered; - - sigrenderer->pos += (int32)(t >> 16); - sigrenderer->subpos = (int)t & 65535; - } - - return rendered; -} - - - -/* DEPRECATED */ -int32 duh_sigrenderer_get_samples( - DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - int32 size, sample_t **samples -) -{ - sample_t **s; - int32 rendered; - int32 i; - int j; - if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL); - s = allocate_sample_buffer(sigrenderer->n_channels, size); - if (!s) return 0; - dumb_silence(s[0], sigrenderer->n_channels * size); - rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s); - for (j = 0; j < sigrenderer->n_channels; j++) - for (i = 0; i < rendered; i++) - samples[j][i] += s[0][i*sigrenderer->n_channels+j]; - destroy_sample_buffer(s); - return rendered; -} - - - -/* DEPRECATED */ -int32 duh_render_signal( - DUH_SIGRENDERER *sigrenderer, - float volume, float delta, - int32 size, sample_t **samples -) -{ - sample_t **s; - int32 rendered; - int32 i; - int j; - if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL); - s = allocate_sample_buffer(sigrenderer->n_channels, size); - if (!s) return 0; - dumb_silence(s[0], sigrenderer->n_channels * size); - rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s); - for (j = 0; j < sigrenderer->n_channels; j++) - for (i = 0; i < rendered; i++) - samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8; - destroy_sample_buffer(s); - return rendered; -} - - - -void DUMBEXPORT duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples) -{ - if (sigrenderer) - (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples); -} - - - -void DUMBEXPORT duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer) -{ - if (sigrenderer) { - if (sigrenderer->desc->end_sigrenderer) - if (sigrenderer->sigrenderer) - (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer); - - free(sigrenderer); - } -} - - - -DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, int32 pos) -{ - DUH_SIGRENDERER *sigrenderer; - - if (desc->start_sigrenderer && !vsigrenderer) return NULL; - - sigrenderer = malloc(sizeof(*sigrenderer)); - if (!sigrenderer) { - if (desc->end_sigrenderer) - if (vsigrenderer) - (*desc->end_sigrenderer)(vsigrenderer); - return NULL; - } - - sigrenderer->desc = desc; - sigrenderer->sigrenderer = vsigrenderer; - - sigrenderer->n_channels = n_channels; - - sigrenderer->pos = pos; - sigrenderer->subpos = 0; - - sigrenderer->callback = NULL; - - return sigrenderer; -} - - - -sigrenderer_t *DUMBEXPORT duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type) -{ - if (sigrenderer && sigrenderer->desc->type == type) - return sigrenderer->sigrenderer; - - return NULL; -} - - - -#if 0 -// This function is disabled because we don't know whether we want to destroy -// the sigrenderer if the type doesn't match. We don't even know if we need -// the function at all. Who would want to keep an IT_SIGRENDERER (for -// instance) without keeping the DUH_SIGRENDERER? -sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, int32 type) -{ - if (sigrenderer && sigrenderer->desc->type == type) { - - - - if (sigrenderer) { - if (sigrenderer->desc->end_sigrenderer) - if (sigrenderer->sigrenderer) - (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer); - - free(sigrenderer); - } - - - - - - - return sigrenderer->sigrenderer; - } - - return NULL; -} -#endif diff --git a/libraries/dumb/src/core/unload.c b/libraries/dumb/src/core/unload.c deleted file mode 100644 index 6495ab1f4..000000000 --- a/libraries/dumb/src/core/unload.c +++ /dev/null @@ -1,64 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * unload.c - Code to free a DUH from memory. / / \ \ - * | < / \_ - * By entheh. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/dumb.h" - - - -static void destroy_signal(DUH_SIGNAL *signal) -{ - if (signal) { - if (signal->desc) - if (signal->desc->unload_sigdata) - if (signal->sigdata) - (*signal->desc->unload_sigdata)(signal->sigdata); - - free(signal); - } -} - - - -/* unload_duh(): destroys a DUH struct. You must call this for every DUH - * struct created, when you've finished with it. - */ -void DUMBEXPORT unload_duh(DUH *duh) -{ - int i; - - if (duh) { - if (duh->signal) { - for (i = 0; i < duh->n_signals; i++) - destroy_signal(duh->signal[i]); - - free(duh->signal); - } - - if (duh->tag) { - if (duh->tag[0][0]) - free(duh->tag[0][0]); - free(duh->tag); - } - - free(duh); - } -} diff --git a/libraries/dumb/src/helpers/barray.c b/libraries/dumb/src/helpers/barray.c deleted file mode 100644 index 71e8dc352..000000000 --- a/libraries/dumb/src/helpers/barray.c +++ /dev/null @@ -1,189 +0,0 @@ -#include "internal/barray.h" - -#include - - -void * bit_array_create(size_t size) -{ - size_t bsize = ((size + 7) >> 3) + sizeof(size_t); - void * ret = calloc(1, bsize); - if (ret) *(size_t *)ret = size; - return ret; -} - -void bit_array_destroy(void * array) -{ - if (array) free(array); -} - -void * bit_array_dup(void * array) -{ - if (array) - { - size_t * size = (size_t *) array; - size_t bsize = ((*size + 7) >> 3) + sizeof(*size); - void * ret = malloc(bsize); - if (ret) memcpy(ret, array, bsize); - return ret; - } - return NULL; -} - -void bit_array_reset(void * array) -{ - if (array) - { - size_t * size = (size_t *) array; - size_t bsize = (*size + 7) >> 3; - memset(size + 1, 0, bsize); - } -} - - -void bit_array_set(void * array, size_t bit) -{ - if (array) - { - size_t * size = (size_t *) array; - if (bit < *size) - { - unsigned char * ptr = (unsigned char *)(size + 1); - ptr[bit >> 3] |= (1U << (bit & 7)); - } - } -} - -void bit_array_set_range(void * array, size_t bit, size_t count) -{ - if (array && count) - { - size_t * size = (size_t *) array; - if (bit < *size) - { - unsigned char * ptr = (unsigned char *)(size + 1); - size_t i; - for (i = bit; i < *size && i < bit + count; ++i) - ptr[i >> 3] |= (1U << (i & 7)); - } - } -} - -int bit_array_test(void * array, size_t bit) -{ - if (array) - { - size_t * size = (size_t *) array; - if (bit < *size) - { - unsigned char * ptr = (unsigned char *)(size + 1); - if (ptr[bit >> 3] & (1U << (bit & 7))) - { - return 1; - } - } - } - return 0; -} - -int bit_array_test_range(void * array, size_t bit, size_t count) -{ - if (array) - { - size_t * size = (size_t *) array; - if (bit < *size) - { - unsigned char * ptr = (unsigned char *)(size + 1); - if ((bit & 7) && (count > 8)) - { - while ((bit < *size) && count && (bit & 7)) - { - if (ptr[bit >> 3] & (1U << (bit & 7))) return 1; - bit++; - count--; - } - } - if (!(bit & 7)) - { - while (((*size - bit) >= 8) && (count >= 8)) - { - if (ptr[bit >> 3]) return 1; - bit += 8; - count -= 8; - } - } - while ((bit < *size) && count) - { - if (ptr[bit >> 3] & (1U << (bit & 7))) return 1; - bit++; - count--; - } - } - } - return 0; -} - -void bit_array_clear(void * array, size_t bit) -{ - if (array) - { - size_t * size = (size_t *) array; - if (bit < *size) - { - unsigned char * ptr = (unsigned char *)(size + 1); - ptr[bit >> 3] &= ~(1U << (bit & 7)); - } - } -} - -void bit_array_clear_range(void * array, size_t bit, size_t count) -{ - if (array && count) - { - size_t * size = (size_t *) array; - if (bit < *size) - { - unsigned char * ptr = (unsigned char *)(size + 1); - size_t i; - for (i = bit; i < *size && i < bit + count; ++i) - ptr[i >> 3] &= ~(1U << (i & 7)); - } - } -} - -void bit_array_merge(void * dest, void * source, size_t offset) -{ - if (dest && source) - { - size_t * dsize = (size_t *) dest; - size_t * ssize = (size_t *) source; - size_t soffset = 0; - while (offset < *dsize && soffset < *ssize) - { - if (bit_array_test(source, soffset)) - { - bit_array_set(dest, offset); - } - soffset++; - offset++; - } - } -} - -void bit_array_mask(void * dest, void * source, size_t offset) -{ - if (dest && source) - { - size_t * dsize = (size_t *) dest; - size_t * ssize = (size_t *) source; - size_t soffset = 0; - while (offset < *dsize && soffset < *ssize) - { - if (bit_array_test(source, soffset)) - { - bit_array_clear(dest, offset); - } - soffset++; - offset++; - } - } -} diff --git a/libraries/dumb/src/helpers/clickrem.c b/libraries/dumb/src/helpers/clickrem.c deleted file mode 100644 index e1db4a663..000000000 --- a/libraries/dumb/src/helpers/clickrem.c +++ /dev/null @@ -1,306 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * clickrem.c - Click removal helpers. / / \ \ - * | < / \_ - * By entheh. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include "dumb.h" - - - -typedef struct DUMB_CLICK DUMB_CLICK; - - -struct DUMB_CLICK_REMOVER -{ - DUMB_CLICK *click; - int n_clicks; - - int offset; - - DUMB_CLICK *free_clicks; -}; - - -struct DUMB_CLICK -{ - DUMB_CLICK *next; - int32 pos; - sample_t step; -}; - - -static DUMB_CLICK *alloc_click(DUMB_CLICK_REMOVER *cr) -{ - if (cr->free_clicks != NULL) - { - DUMB_CLICK *click = cr->free_clicks; - cr->free_clicks = click->next; - return click; - } - return malloc(sizeof(DUMB_CLICK)); -} - -static void free_click(DUMB_CLICK_REMOVER *cr, DUMB_CLICK *cl) -{ - cl->next = cr->free_clicks; - cr->free_clicks = cl; -} - -DUMB_CLICK_REMOVER *DUMBEXPORT dumb_create_click_remover(void) -{ - DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr)); - if (!cr) return NULL; - - cr->click = NULL; - cr->n_clicks = 0; - - cr->offset = 0; - cr->free_clicks = NULL; - - return cr; -} - - - -void DUMBEXPORT dumb_record_click(DUMB_CLICK_REMOVER *cr, int32 pos, sample_t step) -{ - DUMB_CLICK *click; - - ASSERT(pos >= 0); - - if (!cr || !step) return; - - if (pos == 0) { - cr->offset -= step; - return; - } - - click = alloc_click(cr); - if (!click) return; - - click->pos = pos; - click->step = step; - - click->next = cr->click; - cr->click = click; - cr->n_clicks++; -} - - - -static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks) -{ - int i; - DUMB_CLICK *c1, *c2, **cp; - - if (n_clicks <= 1) return click; - - /* Split the list into two */ - c1 = click; - cp = &c1; - for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next; - c2 = *cp; - *cp = NULL; - - /* Sort the sublists */ - c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1); - c2 = dumb_click_mergesort(c2, n_clicks >> 1); - - /* Merge them */ - cp = &click; - while (c1 && c2) { - if (c1->pos > c2->pos) { - *cp = c2; - c2 = c2->next; - } else { - *cp = c1; - c1 = c1->next; - } - cp = &(*cp)->next; - } - if (c2) - *cp = c2; - else - *cp = c1; - - return click; -} - - - -void DUMBEXPORT dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, int32 length, int step, double halflife) -{ - DUMB_CLICK *click; - int32 pos = 0; - int offset; - int factor; - - if (!cr) return; - - factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31)); - - click = dumb_click_mergesort(cr->click, cr->n_clicks); - cr->click = NULL; - cr->n_clicks = 0; - - length *= step; - - while (click) { - DUMB_CLICK *next = click->next; - int end = click->pos * step; - ASSERT(end <= length); - offset = cr->offset; - if (offset < 0) { - offset = -offset; - while (pos < end) { - samples[pos] -= offset; - offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32); - pos += step; - } - offset = -offset; - } else { - while (pos < end) { - samples[pos] += offset; - offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32); - pos += step; - } - } - cr->offset = offset - click->step; - free_click(cr, click); - click = next; - } - - offset = cr->offset; - if (offset < 0) { - offset = -offset; - while (pos < length) { - samples[pos] -= offset; - offset = (int)((LONG_LONG)(offset << 1) * factor >> 32); - pos += step; - } - offset = -offset; - } else { - while (pos < length) { - samples[pos] += offset; - offset = (int)((LONG_LONG)(offset << 1) * factor >> 32); - pos += step; - } - } - cr->offset = offset; -} - - - -sample_t DUMBEXPORT dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr) -{ - return cr ? cr->offset : 0; -} - - - -void DUMBEXPORT dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr) -{ - if (cr) { - DUMB_CLICK *click = cr->click; - while (click) { - DUMB_CLICK *next = click->next; - free(click); - click = next; - } - click = cr->free_clicks; - while (click) { - DUMB_CLICK *next = click->next; - free(click); - click = next; - } - free(cr); - } -} - - - -DUMB_CLICK_REMOVER **DUMBEXPORT dumb_create_click_remover_array(int n) -{ - int i; - DUMB_CLICK_REMOVER **cr; - if (n <= 0) return NULL; - cr = malloc(n * sizeof(*cr)); - if (!cr) return NULL; - for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover(); - return cr; -} - - - -void DUMBEXPORT dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step) -{ - if (cr) { - int i; - for (i = 0; i < n; i++) - dumb_record_click(cr[i], pos, step[i]); - } -} - - - -void DUMBEXPORT dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, int32 pos, sample_t *step) -{ - if (cr) { - int i; - for (i = 0; i < n; i++) - dumb_record_click(cr[i], pos, -step[i]); - } -} - - - -void DUMBEXPORT dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, int32 length, double halflife) -{ - if (cr) { - int i; - for (i = 0; i < n >> 1; i++) { - dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife); - dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife); - } - if (n & 1) - dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife); - } -} - - - -void DUMBEXPORT dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset) -{ - if (cr) { - int i; - for (i = 0; i < n; i++) - if (cr[i]) offset[i] += cr[i]->offset; - } -} - - - -void DUMBEXPORT dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr) -{ - if (cr) { - int i; - for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]); - free(cr); - } -} diff --git a/libraries/dumb/src/helpers/lpc.c b/libraries/dumb/src/helpers/lpc.c deleted file mode 100644 index c77516892..000000000 --- a/libraries/dumb/src/helpers/lpc.c +++ /dev/null @@ -1,320 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: LPC low level routines - last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $ - - ********************************************************************/ - -/* Some of these routines (autocorrelator, LPC coefficient estimator) - are derived from code written by Jutta Degener and Carsten Bormann; - thus we include their copyright below. The entirety of this file - is freely redistributable on the condition that both of these - copyright notices are preserved without modification. */ - -/* Preserved Copyright: *********************************************/ - -/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, -Technische Universita"t Berlin - -Any use of this software is permitted provided that this notice is not -removed and that neither the authors nor the Technische Universita"t -Berlin are deemed to have made any representations as to the -suitability of this software for any purpose nor are held responsible -for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR -THIS SOFTWARE. - -As a matter of courtesy, the authors request to be informed about uses -this software has found, about bugs in this software, and about any -improvements that may be of general interest. - -Berlin, 28.11.1994 -Jutta Degener -Carsten Bormann - -*********************************************************************/ - -#include -#include -#include -#include "internal/stack_alloc.h" -#include "internal/lpc.h" - -/* Autocorrelation LPC coeff generation algorithm invented by - N. Levinson in 1947, modified by J. Durbin in 1959. */ - -/* Input : n elements of time doamin data - Output: m lpc coefficients, excitation energy */ - -float vorbis_lpc_from_data(float *data,float *lpci,int n,int m){ - double *aut=alloca(sizeof(*aut)*(m+1)); - double *lpc=alloca(sizeof(*lpc)*(m)); - double error; - double epsilon; - int i,j; - - /* autocorrelation, p+1 lag coefficients */ - j=m+1; - while(j--){ - double d=0; /* double needed for accumulator depth */ - for(i=j;in_samples; n++ ) { - IT_SAMPLE * sample = sigdata->sample + n; - if ( ( sample->flags & ( IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP) ) == IT_SAMPLE_EXISTS ) { - /* If we have enough sample data to train the filter, use the filter to generate the padding */ - if ( sample->length >= lpc_order ) { - lpc_samples = sample->length; - if (lpc_samples > lpc_max) lpc_samples = lpc_max; - offset = sample->length - lpc_samples; - - if ( sample->flags & IT_SAMPLE_STEREO ) - { - if ( sample->flags & IT_SAMPLE_16BIT ) - { - s16 = ( signed short * ) sample->data; - s16 += offset * 2; - for ( o = 0; o < lpc_samples; o++ ) - { - lpc_input[ o ] = s16[ o * 2 + 0 ]; - lpc_input[ o + lpc_max ] = s16[ o * 2 + 1 ]; - } - } - else - { - s8 = ( signed char * ) sample->data; - s8 += offset * 2; - for ( o = 0; o < lpc_samples; o++ ) - { - lpc_input[ o ] = s8[ o * 2 + 0 ]; - lpc_input[ o + lpc_max ] = s8[ o * 2 + 1 ]; - } - } - - vorbis_lpc_from_data( lpc_input, lpc, lpc_samples, lpc_order ); - vorbis_lpc_from_data( lpc_input + lpc_max, lpc + lpc_order, lpc_samples, lpc_order ); - - vorbis_lpc_predict( lpc, lpc_input + lpc_samples - lpc_order, lpc_order, lpc_output, lpc_extra ); - vorbis_lpc_predict( lpc + lpc_order, lpc_input + lpc_max + lpc_samples - lpc_order, lpc_order, lpc_output + lpc_extra, lpc_extra ); - - if ( sample->flags & IT_SAMPLE_16BIT ) - { - s16 = ( signed short * ) realloc( sample->data, ( sample->length + lpc_extra ) * 2 * sizeof(short) ); - sample->data = s16; - - s16 += sample->length * 2; - sample->length += lpc_extra; - - for ( o = 0; o < lpc_extra; o++ ) - { - s16[ o * 2 + 0 ] = (signed short)lpc_output[ o ]; - s16[ o * 2 + 1 ] = (signed short)lpc_output[ o + lpc_extra ]; - } - } - else - { - s8 = ( signed char * ) realloc( sample->data, ( sample->length + lpc_extra ) * 2 ); - sample->data = s8; - - s8 += sample->length * 2; - sample->length += lpc_extra; - - for ( o = 0; o < lpc_extra; o++ ) - { - s8[ o * 2 + 0 ] = (signed char)lpc_output[ o ]; - s8[ o * 2 + 1 ] = (signed char)lpc_output[ o + lpc_extra ]; - } - } - } - else - { - if ( sample->flags & IT_SAMPLE_16BIT ) - { - s16 = ( signed short * ) sample->data; - s16 += offset; - for ( o = 0; o < lpc_samples; o++ ) - { - lpc_input[ o ] = s16[ o ]; - } - } - else - { - s8 = ( signed char * ) sample->data; - s8 += offset; - for ( o = 0; o < lpc_samples; o++ ) - { - lpc_input[ o ] = s8[ o ]; - } - } - - vorbis_lpc_from_data( lpc_input, lpc, lpc_samples, lpc_order ); - - vorbis_lpc_predict( lpc, lpc_input + lpc_samples - lpc_order, lpc_order, lpc_output, lpc_extra ); - - if ( sample->flags & IT_SAMPLE_16BIT ) - { - s16 = ( signed short * ) realloc( sample->data, ( sample->length + lpc_extra ) * sizeof(short) ); - sample->data = s16; - - s16 += sample->length; - sample->length += lpc_extra; - - for ( o = 0; o < lpc_extra; o++ ) - { - s16[ o ] = (signed short)lpc_output[ o ]; - } - } - else - { - s8 = ( signed char * ) realloc( sample->data, sample->length + lpc_extra ); - sample->data = s8; - - s8 += sample->length; - sample->length += lpc_extra; - - for ( o = 0; o < lpc_extra; o++ ) - { - s8[ o ] = (signed char)lpc_output[ o ]; - } - } - } - } - else - /* Otherwise, pad with silence. */ - { - offset = sample->length; - lpc_samples = lpc_extra; - - sample->length += lpc_samples; - - n = 1; - if ( sample->flags & IT_SAMPLE_STEREO ) n *= 2; - if ( sample->flags & IT_SAMPLE_16BIT ) n *= 2; - - offset *= n; - lpc_samples *= n; - - sample->data = realloc( sample->data, offset + lpc_samples ); - memset( (char*)sample->data + offset, 0, lpc_samples ); - } - } - } -} diff --git a/libraries/dumb/src/helpers/memfile.c b/libraries/dumb/src/helpers/memfile.c deleted file mode 100644 index 476683944..000000000 --- a/libraries/dumb/src/helpers/memfile.c +++ /dev/null @@ -1,117 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * memfile.c - Module for reading data from / / \ \ - * memory using a DUMBFILE. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" - - - -typedef struct MEMFILE MEMFILE; - -struct MEMFILE -{ - const char *ptr, *ptr_begin; - long left, size; -}; - - - -static int DUMBCALLBACK dumb_memfile_skip(void *f, long n) -{ - MEMFILE *m = f; - if (n > m->left) return -1; - m->ptr += n; - m->left -= n; - return 0; -} - - - -static int DUMBCALLBACK dumb_memfile_getc(void *f) -{ - MEMFILE *m = f; - if (m->left <= 0) return -1; - m->left--; - return *(const unsigned char *)m->ptr++; -} - - - -static int32 DUMBCALLBACK dumb_memfile_getnc(char *ptr, int32 n, void *f) -{ - MEMFILE *m = f; - if (n > m->left) n = m->left; - memcpy(ptr, m->ptr, n); - m->ptr += n; - m->left -= n; - return n; -} - - - -static void DUMBCALLBACK dumb_memfile_close(void *f) -{ - free(f); -} - - -static int DUMBCALLBACK dumb_memfile_seek(void *f, long n) -{ - MEMFILE *m = f; - - m->ptr = m->ptr_begin + n; - m->left = m->size - n; - - return 0; -} - - -static long DUMBCALLBACK dumb_memfile_get_size(void *f) -{ - MEMFILE *m = f; - return m->size; -} - - -static const DUMBFILE_SYSTEM memfile_dfs = { - NULL, - &dumb_memfile_skip, - &dumb_memfile_getc, - &dumb_memfile_getnc, - &dumb_memfile_close, - &dumb_memfile_seek, - &dumb_memfile_get_size -}; - - - -DUMBFILE *DUMBEXPORT dumbfile_open_memory(const char *data, int32 size) -{ - MEMFILE *m = malloc(sizeof(*m)); - if (!m) return NULL; - - m->ptr_begin = data; - m->ptr = data; - m->left = size; - m->size = size; - - return dumbfile_open_ex(m, &memfile_dfs); -} diff --git a/libraries/dumb/src/helpers/resamp2.inc b/libraries/dumb/src/helpers/resamp2.inc deleted file mode 100644 index 63b59e94e..000000000 --- a/libraries/dumb/src/helpers/resamp2.inc +++ /dev/null @@ -1,174 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * resamp2.inc - Resampling helper template. / / \ \ - * | < / \_ - * By Bob and entheh. | \/ /\ / - * \_ / > / - * In order to find a good trade-off between | \ / / - * speed and accuracy in this code, some tests | ' / - * were carried out regarding the behaviour of \__/ - * long long ints with gcc. The following code - * was tested: - * - * int a, b, c; - * c = ((long long)a * b) >> 16; - * - * DJGPP GCC Version 3.0.3 generated the following assembly language code for - * the multiplication and scaling, leaving the 32-bit result in EAX. - * - * movl -8(%ebp), %eax ; read one int into EAX - * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX - * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX - * - * Note that a 32*32->64 multiplication is performed, allowing for high - * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally), - * so it is a minor concern when four multiplications are being performed - * (the cubic resampler). On the Pentium MMX and earlier, it takes four or - * more cycles, so this method is unsuitable for use in the low-quality - * resamplers. - * - * Since "long long" is a gcc-specific extension, we use LONG_LONG instead, - * defined in dumb.h. We may investigate later what code MSVC generates, but - * if it seems too slow then we suggest you use a good compiler. - * - * FIXME: these comments are somewhat out of date now. - */ - - - -#define SUFFIX3 _2 - -/* For convenience, returns nonzero on stop. */ -static int process_pickup(DUMB_RESAMPLER *resampler) -{ - if (resampler->overshot < 0) { - resampler->overshot = 0; - dumb_resample(resampler, NULL, 2, MONO_DEST_VOLUME_ZEROS, 1.0f); /* Doesn't matter which SUFFIX3. */ - COPYSRC(resampler->X, 0, resampler->X, 1); - } - - for (;;) { - SRCTYPE *src = resampler->src; - - if (resampler->dir < 0) { - if (resampler->overshot >= 3 && resampler->pos+3 >= resampler->start) COPYSRC(resampler->X, 0, src, resampler->pos+3); - if (resampler->overshot >= 2 && resampler->pos+2 >= resampler->start) COPYSRC(resampler->X, 1, src, resampler->pos+2); - if (resampler->overshot >= 1 && resampler->pos+1 >= resampler->start) COPYSRC(resampler->X, 2, src, resampler->pos+1); - resampler->overshot = resampler->start - resampler->pos - 1; - } else { - if (resampler->overshot >= 3 && resampler->pos-3 < resampler->end) COPYSRC(resampler->X, 0, src, resampler->pos-3); - if (resampler->overshot >= 2 && resampler->pos-2 < resampler->end) COPYSRC(resampler->X, 1, src, resampler->pos-2); - if (resampler->overshot >= 1 && resampler->pos-1 < resampler->end) COPYSRC(resampler->X, 2, src, resampler->pos-1); - resampler->overshot = resampler->pos - resampler->end; - } - - if (resampler->overshot < 0) { - resampler->overshot = 0; - return 0; - } - - if (!resampler->pickup) { - resampler->dir = 0; - return 1; - } - (*resampler->pickup)(resampler, resampler->pickup_data); - if (resampler->dir == 0) return 1; - ASSERT(resampler->dir == -1 || resampler->dir == 1); - } -} - - - -/* Create mono destination resampler. */ -/* SUFFIX3 was set above. */ -#if 0 -#define VOLUME_PARAMETERS MONO_DEST_VOLUME_PARAMETERS -#define VOLUME_VARIABLES MONO_DEST_VOLUME_VARIABLES -#define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES -#define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES -#define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO -#define PEEK_FIR MONO_DEST_PEEK_FIR -#define MIX_FIR MONO_DEST_MIX_FIR -#define MIX_ZEROS(op) *dst++ op 0 -#include "resamp3.inc" -#else -#undef SUFFIX3 -#endif - -/* Create stereo destination resampler. */ -#define SUFFIX3 _2 -#define VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right -#define VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm -#define SET_VOLUME_VARIABLES { \ - if ( volume_left ) { \ - lvolr = xs_FloorToInt(volume_left->volume * 16777216.f); \ - lvold = xs_FloorToInt(volume_left->delta * 16777216.f); \ - lvolt = xs_FloorToInt(volume_left->target * 16777216.f); \ - lvolm = xs_FloorToInt(volume_left->mix * 16777216.f); \ - lvol = MULSCV( lvolr, lvolm ); \ - if ( lvolr == lvolt ) volume_left = NULL; \ - } else { \ - lvol = 0; \ - lvold = 0; \ - lvolt = 0; \ - lvolm = 0; \ - } \ - if ( volume_right ) { \ - rvolr = xs_FloorToInt(volume_right->volume * 16777216.f); \ - rvold = xs_FloorToInt(volume_right->delta * 16777216.f); \ - rvolt = xs_FloorToInt(volume_right->target * 16777216.f); \ - rvolm = xs_FloorToInt(volume_right->mix * 16777216.f); \ - rvol = MULSCV( rvolr, rvolm ); \ - if ( rvolr == rvolt ) volume_right = NULL; \ - } else { \ - rvol = 0; \ - rvold = 0; \ - rvolt = 0; \ - rvolm = 0; \ - } \ -} -#define RETURN_VOLUME_VARIABLES { \ - if ( volume_left ) volume_left->volume = (float)lvolr / 16777216.0f; \ - if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \ -} -#define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) -#define MIX_ALIAS(op, upd, offset) STEREO_DEST_MIX_ALIAS(op, upd, offset) -#define MIX_LINEAR(op, upd, o0, o1) STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) -#define MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) -#define PEEK_FIR STEREO_DEST_PEEK_FIR -#define MIX_FIR STEREO_DEST_MIX_FIR -#define MIX_ZEROS(op) { *dst++ op 0; *dst++ op 0; } -#include "resamp3.inc" - - - -#undef STEREO_DEST_MIX_CUBIC -#undef STEREO_DEST_MIX_LINEAR -#undef STEREO_DEST_MIX_ALIAS -#undef MONO_DEST_VOLUMES_ARE_ZERO -#undef SET_MONO_DEST_VOLUME_VARIABLES -#undef RETURN_MONO_DEST_VOLUME_VARIABLES -#undef MONO_DEST_VOLUME_ZEROS -#undef MONO_DEST_VOLUME_VARIABLES -#undef MONO_DEST_VOLUME_PARAMETERS -#undef STEREO_DEST_PEEK_ALIAS -#undef POKE_ALIAS -#undef MONO_DEST_PEEK_FIR -#undef STEREO_DEST_PEEK_FIR -#undef MONO_DEST_MIX_FIR -#undef STEREO_DEST_MIX_FIR -#undef ADVANCE_FIR -#undef POKE_FIR -#undef COPYSRC2 -#undef COPYSRC -#undef DIVIDE_BY_SRC_CHANNELS -#undef SRC_CHANNELS -#undef SUFFIX2 diff --git a/libraries/dumb/src/helpers/resamp3.inc b/libraries/dumb/src/helpers/resamp3.inc deleted file mode 100644 index 5fc13618b..000000000 --- a/libraries/dumb/src/helpers/resamp3.inc +++ /dev/null @@ -1,436 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * resamp3.inc - Resampling helper template. / / \ \ - * | < / \_ - * By Bob and entheh. | \/ /\ / - * \_ / > / - * In order to find a good trade-off between | \ / / - * speed and accuracy in this code, some tests | ' / - * were carried out regarding the behaviour of \__/ - * long long ints with gcc. The following code - * was tested: - * - * int a, b, c; - * c = ((long long)a * b) >> 16; - * - * DJGPP GCC Version 3.0.3 generated the following assembly language code for - * the multiplication and scaling, leaving the 32-bit result in EAX. - * - * movl -8(%ebp), %eax ; read one int into EAX - * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX - * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX - * - * Note that a 32*32->64 multiplication is performed, allowing for high - * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally), - * so it is a minor concern when four multiplications are being performed - * (the cubic resampler). On the Pentium MMX and earlier, it takes four or - * more cycles, so this method is unsuitable for use in the low-quality - * resamplers. - * - * Since "long long" is a gcc-specific extension, we use LONG_LONG instead, - * defined in dumb.h. We may investigate later what code MSVC generates, but - * if it seems too slow then we suggest you use a good compiler. - * - * FIXME: these comments are somewhat out of date now. - */ - - - -int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VOLUME_PARAMETERS, double delta) -{ - int dt, inv_dt; - int VOLUME_VARIABLES; - long done; - long todo; - double tododbl; - int quality; - - if (!resampler || resampler->dir == 0) return 0; - ASSERT(resampler->dir == -1 || resampler->dir == 1); - - done = 0; - dt = xs_CRoundToInt(delta * 65536.0); - if (dt == 0 || dt == 0x80000000) return 0; - inv_dt = xs_CRoundToInt(1.0 / delta * 65536.0); - SET_VOLUME_VARIABLES; - - if (VOLUMES_ARE_ZERO) dst = NULL; - - _dumb_init_cubic(); - - quality = resampler->quality; - - while (done < dst_size) { - if (process_pickup(resampler)) { - RETURN_VOLUME_VARIABLES; - return done; - } - - if ((resampler->dir ^ dt) < 0) - dt = -dt; - - if (resampler->dir < 0) - tododbl = ((resampler->pos - resampler->start) * 65536.f + (resampler->subpos - dt)) / -dt; - else - tododbl = ((resampler->end - resampler->pos) * 65536.f - (resampler->subpos + 1 - dt)) / dt; - - if (tododbl <= 0) - todo = 0; - else if (tododbl >= dst_size - done) - todo = dst_size - done; - else - todo = xs_FloorToInt(tododbl); - - done += todo; - - { - SRCTYPE *src = resampler->src; - long pos = resampler->pos; - int subpos = resampler->subpos; - long diff = pos; - long overshot; - if (resampler->dir < 0) { - if (!dst) { - /* Silence or simulation */ - LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo; - pos += (long)(new_subpos >> 16); - subpos = (long)new_subpos & 65535; - } else if (quality <= DUMB_RQ_ALIASING) { - /* Aliasing, backwards */ - SRCTYPE xbuf[2*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[0]; - SRCTYPE *xstart; - COPYSRC(xbuf, 0, resampler->X, 1); - COPYSRC(xbuf, 1, resampler->X, 2); - while (todo && x < &xbuf[2*SRC_CHANNELS]) { - // TODO: check what happens when multiple tempo slides occur per row - HEAVYASSERT(pos >= resampler->start); - MIX_ALIAS(+=, 1, 0); - subpos += dt; - pos += subpos >> 16; - x -= (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = xstart = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - MIX_ALIAS(+=, 1, 2); - subpos += dt; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - pos += DIVIDE_BY_SRC_CHANNELS(x - xstart); - } else if (quality <= DUMB_LQ_LINEAR) { - /* Linear interpolation, backwards */ - SRCTYPE xbuf[3*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[1*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 1); - COPYSRC(xbuf, 1, resampler->X, 2); - COPYSRC(xbuf, 2, src, pos); - while (todo && x < &xbuf[3*SRC_CHANNELS]) { - HEAVYASSERT(pos >= resampler->start); - MIX_LINEAR(+=, 1, 0, -1); - subpos += dt; - pos += subpos >> 16; - x -= (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - // TODO: use xstart for others too - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos >= resampler->start); - MIX_LINEAR(+=, 1, 1, 2); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - } else if (quality <= DUMB_LQ_CUBIC) { - /* Cubic interpolation, backwards */ - SRCTYPE xbuf[6*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[3*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 0); - COPYSRC(xbuf, 1, resampler->X, 1); - COPYSRC(xbuf, 2, resampler->X, 2); - COPYSRC(xbuf, 3, src, pos); - if (pos-1 >= resampler->start) COPYSRC(xbuf, 4, src, pos-1); - if (pos-2 >= resampler->start) COPYSRC(xbuf, 5, src, pos-2); - while (todo && x < &xbuf[6*SRC_CHANNELS]) { - HEAVYASSERT(pos >= resampler->start); - MIX_CUBIC(+=, 1, x, x, 0, -1, -2, -3); - subpos += dt; - pos += subpos >> 16; - x -= (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos >= resampler->start); - MIX_CUBIC(+=, 1, x, x, 0, 1, 2, 3); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - } else { - /* FIR resampling, backwards */ - SRCTYPE *x; - if ( resampler->fir_resampler_ratio != delta ) { - resampler_set_rate( resampler->fir_resampler[0], delta ); - resampler_set_rate( resampler->fir_resampler[1], delta ); - resampler->fir_resampler_ratio = delta; - } - x = &src[pos*SRC_CHANNELS]; - while ( todo ) { - while ( ( resampler_get_free_count( resampler->fir_resampler[0] ) || - (!resampler_get_sample_count( resampler->fir_resampler[0] ) - #if SRC_CHANNELS == 2 - && !resampler_get_sample_count( resampler->fir_resampler[1] ) - #endif - ) ) && pos >= resampler->start ) - { - POKE_FIR(0); - pos--; - x -= SRC_CHANNELS; - } - if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; - MIX_FIR; - ADVANCE_FIR; - --todo; - } - done -= todo; - } - diff = diff - pos; - overshot = resampler->start - pos - 1; - if (diff >= 3) { - COPYSRC2(resampler->X, 0, overshot < 3, src, pos+3); - COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2); - COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1); - } else if (diff >= 2) { - COPYSRC(resampler->X, 0, resampler->X, 2); - COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2); - COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1); - } else if (diff >= 1) { - COPYSRC(resampler->X, 0, resampler->X, 1); - COPYSRC(resampler->X, 1, resampler->X, 2); - COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1); - } - } else { - if (!dst) { - /* Silence or simulation */ - LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo; - pos += (long)(new_subpos >> 16); - subpos = (long)new_subpos & 65535; - } else if (quality <= DUMB_RQ_ALIASING) { - /* Aliasing, forwards */ - SRCTYPE xbuf[2*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[0]; - SRCTYPE *xstart; - COPYSRC(xbuf, 0, resampler->X, 1); - COPYSRC(xbuf, 1, resampler->X, 2); - while (todo && x < &xbuf[2*SRC_CHANNELS]) { - HEAVYASSERT(pos < resampler->end); - MIX_ALIAS(+=, 1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = xstart = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - MIX_ALIAS(+=, 1, -2); - subpos += dt; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - pos += DIVIDE_BY_SRC_CHANNELS(x - xstart); - } else if (quality <= DUMB_LQ_LINEAR) { - /* Linear interpolation, forwards */ - SRCTYPE xbuf[3*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[1*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 1); - COPYSRC(xbuf, 1, resampler->X, 2); - COPYSRC(xbuf, 2, src, pos); - while (todo && x < &xbuf[3*SRC_CHANNELS]) { - HEAVYASSERT(pos < resampler->end); - MIX_LINEAR(+=, 1, -1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos < resampler->end); - MIX_LINEAR(+=, 1, -2, -1); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - } else if (quality <= DUMB_LQ_CUBIC) { - /* Cubic interpolation, forwards */ - SRCTYPE xbuf[6*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[3*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 0); - COPYSRC(xbuf, 1, resampler->X, 1); - COPYSRC(xbuf, 2, resampler->X, 2); - COPYSRC(xbuf, 3, src, pos); - if (pos+1 < resampler->end) COPYSRC(xbuf, 4, src, pos+1); - if (pos+2 < resampler->end) COPYSRC(xbuf, 5, src, pos+2); - while (todo && x < &xbuf[6*SRC_CHANNELS]) { - HEAVYASSERT(pos < resampler->end); - MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos < resampler->end); - MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - } else { - /* FIR resampling, forwards */ - SRCTYPE *x; - if ( resampler->fir_resampler_ratio != delta ) { - resampler_set_rate( resampler->fir_resampler[0], delta ); - resampler_set_rate( resampler->fir_resampler[1], delta ); - resampler->fir_resampler_ratio = delta; - } - x = &src[pos*SRC_CHANNELS]; - while ( todo ) { - while ( ( resampler_get_free_count( resampler->fir_resampler[0] ) || - (!resampler_get_sample_count( resampler->fir_resampler[0] ) - #if SRC_CHANNELS == 2 - && !resampler_get_sample_count( resampler->fir_resampler[1] ) - #endif - ) ) && pos < resampler->end ) - { - POKE_FIR(0); - pos++; - x += SRC_CHANNELS; - } - if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; - MIX_FIR; - ADVANCE_FIR; - --todo; - } - done -= todo; - } - diff = pos - diff; - overshot = pos - resampler->end; - if (diff >= 3) { - COPYSRC2(resampler->X, 0, overshot < 3, src, pos-3); - COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2); - COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1); - } else if (diff >= 2) { - COPYSRC(resampler->X, 0, resampler->X, 2); - COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2); - COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1); - } else if (diff >= 1) { - COPYSRC(resampler->X, 0, resampler->X, 1); - COPYSRC(resampler->X, 1, resampler->X, 2); - COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1); - } - } - resampler->pos = pos; - resampler->subpos = subpos; - } - } - - RETURN_VOLUME_VARIABLES; - return done; -} - - - -void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETERS, sample_t *dst) -{ - int VOLUME_VARIABLES; - SRCTYPE *src; - long pos; - int subpos; - int quality; - SRCTYPE *x; - - if (!resampler || resampler->dir == 0) { MIX_ZEROS(=); return; } - ASSERT(resampler->dir == -1 || resampler->dir == 1); - - if (process_pickup(resampler)) { MIX_ZEROS(=); return; } - - SET_VOLUME_VARIABLES; - - if (VOLUMES_ARE_ZERO) { MIX_ZEROS(=); return; } - - _dumb_init_cubic(); - - quality = resampler->quality; - - src = resampler->src; - pos = resampler->pos; - subpos = resampler->subpos; - x = resampler->X; - - if (resampler->dir < 0) { - HEAVYASSERT(pos >= resampler->start); - if (quality <= DUMB_RQ_ALIASING) { - /* Aliasing, backwards */ - MIX_ALIAS(=, 0, 1); - } else if (quality <= DUMB_LQ_LINEAR) { - /* Linear interpolation, backwards */ - MIX_LINEAR(=, 0, 2, 1); - } else if (quality <= DUMB_LQ_CUBIC) { - /* Cubic interpolation, backwards */ - MIX_CUBIC(=, 0, src, x, pos, 2, 1, 0); - } else { - /* FIR resampling, backwards */ - PEEK_FIR; - } - } else { - HEAVYASSERT(pos < resampler->end); - if (quality <= DUMB_RQ_ALIASING) { - /* Aliasing */ - MIX_ALIAS(=, 0, 1); - } else if (quality <= DUMB_LQ_LINEAR) { - /* Linear interpolation, forwards */ - MIX_LINEAR(=, 0, 1, 2); - } else if (quality <= DUMB_LQ_CUBIC) { - /* Cubic interpolation, forwards */ - MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos); - } else { - /* FIR resampling, forwards */ - PEEK_FIR; - } - } -} - - - -#undef MIX_ZEROS -#undef MIX_FIR -#undef PEEK_FIR -#undef VOLUMES_ARE_ZERO -#undef SET_VOLUME_VARIABLES -#undef RETURN_VOLUME_VARIABLES -#undef VOLUME_VARIABLES -#undef VOLUME_PARAMETERS -#undef SUFFIX3 diff --git a/libraries/dumb/src/helpers/resample.c b/libraries/dumb/src/helpers/resample.c deleted file mode 100644 index 30a60d8da..000000000 --- a/libraries/dumb/src/helpers/resample.c +++ /dev/null @@ -1,420 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * resample.c - Resampling helpers. / / \ \ - * | < / \_ - * By Bob and entheh. | \/ /\ / - * \_ / > / - * In order to find a good trade-off between | \ / / - * speed and accuracy in this code, some tests | ' / - * were carried out regarding the behaviour of \__/ - * long long ints with gcc. The following code - * was tested: - * - * int a, b, c; - * c = ((long long)a * b) >> 16; - * - * DJGPP GCC Version 3.0.3 generated the following assembly language code for - * the multiplication and scaling, leaving the 32-bit result in EAX. - * - * movl -8(%ebp), %eax ; read one int into EAX - * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX - * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX - * - * Note that a 32*32->64 multiplication is performed, allowing for high - * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally), - * so it is a minor concern when four multiplications are being performed - * (the cubic resampler). On the Pentium MMX and earlier, it takes four or - * more cycles, so this method is unsuitable for use in the low-quality - * resamplers. - * - * Since "long long" is a gcc-specific extension, we use LONG_LONG instead, - * defined in dumb.h. We may investigate later what code MSVC generates, but - * if it seems too slow then we suggest you use a good compiler. - * - * FIXME: these comments are somewhat out of date now. - */ - -#include -#include "dumb.h" - -#include "internal/resampler.h" -#include "internal/mulsc.h" - - - -/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is - * called when it should be. There will be a considerable performance hit, - * since at least one condition has to be tested for every sample generated. - */ -#ifdef HEAVYDEBUG -#define HEAVYASSERT(cond) ASSERT(cond) -#else -#define HEAVYASSERT(cond) -#endif - - - -/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */ -#ifdef _MSC_VER -#pragma warning(disable:4127 4701) -#endif - - - -/* A global variable for controlling resampling quality wherever a local - * specification doesn't override it. The following values are valid: - * - * 0 - DUMB_RQ_ALIASING - fastest - * 1 - DUMB_RQ_BLEP - nicer than aliasing, but slower - * 2 - DUMB_RQ_LINEAR - * 3 - DUMB_RQ_BLAM - band-limited linear interpolation, nice but slower - * 4 - DUMB_RQ_CUBIC - * 5 - DUMB_RQ_FIR - nicest - * - * Values outside the range 0-4 will behave the same as the nearest - * value within the range. - */ -int dumb_resampling_quality = DUMB_RQ_CUBIC; - - - -/* From xs_Float.h ==============================================*/ -#if __BIG_ENDIAN__ - #define _xs_iman_ 1 -#else - #define _xs_iman_ 0 -#endif //BigEndian_ - -#ifdef __GNUC__ -#define finline inline -#else -#define finline __forceinline -#endif - -union _xs_doubleints -{ - double val; - unsigned int ival[2]; -}; - -static const double _xs_doublemagic = (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor -static const double _xs_doublemagicroundeps = (.5f-(1.5e-8)); //almost .5f = .5f - 1e^(number of exp bit) - -static finline int xs_CRoundToInt(double val) -{ - union _xs_doubleints uval; - val += _xs_doublemagic; - uval.val = val; - return uval.ival[_xs_iman_]; -} -static finline int xs_FloorToInt(double val) -{ - union _xs_doubleints uval; - val -= _xs_doublemagicroundeps; - val += _xs_doublemagic; - uval.val = val; - return uval.ival[_xs_iman_]; -} -/* Not from xs_Float.h ==========================================*/ - - -/* Executes the content 'iterator' times. - * Clobbers the 'iterator' variable. - * The loop is unrolled by four. - */ -#if 0 -#define LOOP4(iterator, CONTENT) \ -{ \ - if ((iterator) & 2) { \ - CONTENT; \ - CONTENT; \ - } \ - if ((iterator) & 1) { \ - CONTENT; \ - } \ - (iterator) >>= 2; \ - while (iterator) { \ - CONTENT; \ - CONTENT; \ - CONTENT; \ - CONTENT; \ - (iterator)--; \ - } \ -} -#else -#define LOOP4(iterator, CONTENT) \ -{ \ - while ( (iterator)-- ) \ - { \ - CONTENT; \ - } \ -} -#endif - -#define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */ -#define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */ - -#define X PASTE(x.x, SRCBITS) - - - -/* Cubic resampler: look-up tables - * - * a = 1.5*x1 - 1.5*x2 + 0.5*x3 - 0.5*x0 - * b = 2*x2 + x0 - 2.5*x1 - 0.5*x3 - * c = 0.5*x2 - 0.5*x0 - * d = x1 - * - * x = a*t*t*t + b*t*t + c*t + d - * = (-0.5*x0 + 1.5*x1 - 1.5*x2 + 0.5*x3) * t*t*t + - * ( 1*x0 - 2.5*x1 + 2 *x2 - 0.5*x3) * t*t + - * (-0.5*x0 + 0.5*x2 ) * t + - * ( 1*x1 ) - * = (-0.5*t*t*t + 1 *t*t - 0.5*t ) * x0 + - * ( 1.5*t*t*t - 2.5*t*t + 1) * x1 + - * (-1.5*t*t*t + 2 *t*t + 0.5*t ) * x2 + - * ( 0.5*t*t*t - 0.5*t*t ) * x3 - * = A0(t) * x0 + A1(t) * x1 + A2(t) * x2 + A3(t) * x3 - * - * A0, A1, A2 and A3 stay within the range [-1,1]. - * In the tables, they are scaled with 14 fractional bits. - * - * Turns out we don't need to store A2 and A3; they are symmetrical to A1 and A0. - * - * TODO: A0 and A3 stay very small indeed. Consider different scale/resolution? - */ - -static short cubicA0[1025], cubicA1[1025]; - -void _dumb_init_cubic(void) -{ - unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */ - static int done = 0; - if (done) return; - for (t = 0; t < 1025; t++) { - /* int casts to pacify warnings about negating unsigned values */ - cubicA0[t] = -(int)( t*t*t >> 17) + (int)( t*t >> 6) - (int)(t << 3); - cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14); - } - resampler_init(); - - done = 1; -} - - - -/* Create resamplers for 24-in-32-bit source samples. */ - -/* #define SUFFIX - * MSVC warns if we try to paste a null SUFFIX, so instead we define - * special macros for the function names that don't bother doing the - * corresponding paste. The more generic definitions are further down. - */ -#define process_pickup PASTE(process_pickup, SUFFIX2) -#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3) -#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3) - -#define SRCTYPE sample_t -#define SRCBITS 24 -#define ALIAS(x, vol) MULSC(x, vol) -#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos)) -#define CUBIC(x0, x1, x2, x3) ( \ - MULSC(x0, cubicA0[subpos >> 6] << 2) + \ - MULSC(x1, cubicA1[subpos >> 6] << 2) + \ - MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \ - MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2)) -#define CUBICVOL(x, vol) MULSC(x, vol) -#define FIR(x) (x >> 8) -#include "resample.inc" - -/* Undefine the simplified macros. */ -#undef dumb_resample_get_current_sample -#undef dumb_resample -#undef process_pickup - - -/* Now define the proper ones that use SUFFIX. */ -#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX) -#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX) -#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2) -#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3) -#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3) -#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX) - -/* Create resamplers for 16-bit source samples. */ -#define SUFFIX _16 -#define SRCTYPE short -#define SRCBITS 16 -#define ALIAS(x, vol) (x * vol >> 8) -#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos)) -#define CUBIC(x0, x1, x2, x3) ( \ - x0 * cubicA0[subpos >> 6] + \ - x1 * cubicA1[subpos >> 6] + \ - x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \ - x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) -#define CUBICVOL(x, vol) MULSCV((x), ((vol) << 10)) -#define FIR(x) (x) -#include "resample.inc" - -/* Create resamplers for 8-bit source samples. */ -#define SUFFIX _8 -#define SRCTYPE signed char -#define SRCBITS 8 -#define ALIAS(x, vol) (x * vol) -#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos) -#define CUBIC(x0, x1, x2, x3) (( \ - x0 * cubicA0[subpos >> 6] + \ - x1 * cubicA1[subpos >> 6] + \ - x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \ - x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6) -#define CUBICVOL(x, vol) MULSCV((x), ((vol) << 12)) -#define FIR(x) (x << 8) -#include "resample.inc" - - -#undef dumb_reset_resampler -#undef dumb_start_resampler -#undef process_pickup -#undef dumb_resample -#undef dumb_resample_get_current_sample -#undef dumb_end_resampler - - - -void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, int32 pos, int32 start, int32 end, int quality) -{ - if (n == 8) - dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality); - else if (n == 16) - dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality); - else - dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality); -} - - - -DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, int32 pos, int32 start, int32 end, int quality) -{ - if (n == 8) - return dumb_start_resampler_8(src, src_channels, pos, start, end, quality); - else if (n == 16) - return dumb_start_resampler_16(src, src_channels, pos, start, end, quality); - else - return dumb_start_resampler(src, src_channels, pos, start, end, quality); -} - - -#if 0 -int32 dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume, double delta) -{ - if (n == 8) - return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta); - else if (n == 16) - return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta); - else - return dumb_resample_1_1(resampler, dst, dst_size, volume, delta); -} -#endif - - -int32 dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta) -{ - if (n == 8) - return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); - else if (n == 16) - return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); - else - return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); -} - - -#if 0 -int32 dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta) -{ - if (n == 8) - return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); - else if (n == 16) - return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); - else - return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); -} -#endif - - -int32 dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, double delta) -{ - if (n == 8) - return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); - else if (n == 16) - return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); - else - return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); -} - - -#if 0 -void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst) -{ - if (n == 8) - dumb_resample_get_current_sample_8_1_1(resampler, volume, dst); - else if (n == 16) - dumb_resample_get_current_sample_16_1_1(resampler, volume, dst); - else - dumb_resample_get_current_sample_1_1(resampler, volume, dst); -} -#endif - - -void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst) -{ - if (n == 8) - dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst); - else if (n == 16) - dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst); - else - dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst); -} - - -#if 0 -void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst) -{ - if (n == 8) - dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst); - else if (n == 16) - dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst); - else - dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst); -} -#endif - - -void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst) -{ - if (n == 8) - dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst); - else if (n == 16) - dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst); - else - dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst); -} - - - -void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler) -{ - if (n == 8) - dumb_end_resampler_8(resampler); - else if (n == 16) - dumb_end_resampler_16(resampler); - else - dumb_end_resampler(resampler); -} diff --git a/libraries/dumb/src/helpers/resample.inc b/libraries/dumb/src/helpers/resample.inc deleted file mode 100644 index e5b8345d5..000000000 --- a/libraries/dumb/src/helpers/resample.inc +++ /dev/null @@ -1,299 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * resample.inc - Resampling helper template. / / \ \ - * | < / \_ - * By Bob and entheh. | \/ /\ / - * \_ / > / - * In order to find a good trade-off between | \ / / - * speed and accuracy in this code, some tests | ' / - * were carried out regarding the behaviour of \__/ - * long long ints with gcc. The following code - * was tested: - * - * int a, b, c; - * c = ((long long)a * b) >> 16; - * - * DJGPP GCC Version 3.0.3 generated the following assembly language code for - * the multiplication and scaling, leaving the 32-bit result in EAX. - * - * movl -8(%ebp), %eax ; read one int into EAX - * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX - * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX - * - * Note that a 32*32->64 multiplication is performed, allowing for high - * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally), - * so it is a minor concern when four multiplications are being performed - * (the cubic resampler). On the Pentium MMX and earlier, it takes four or - * more cycles, so this method is unsuitable for use in the low-quality - * resamplers. - * - * Since "long long" is a gcc-specific extension, we use LONG_LONG instead, - * defined in dumb.h. We may investigate later what code MSVC generates, but - * if it seems too slow then we suggest you use a good compiler. - * - * FIXME: these comments are somewhat out of date now. - */ - - - -void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_channels, int32 pos, int32 start, int32 end, int quality) -{ - int i; - resampler->src = src; - resampler->pos = pos; - resampler->subpos = 0; - resampler->start = start; - resampler->end = end; - resampler->dir = 1; - resampler->pickup = NULL; - resampler->pickup_data = NULL; - if (quality < 0) - { - resampler->quality = 0; - } - else if (quality > DUMB_RQ_N_LEVELS - 1) - { - resampler->quality = DUMB_RQ_N_LEVELS - 1; - } - else - { - resampler->quality = quality; - } - for (i = 0; i < src_channels*3; i++) resampler->X[i] = 0; - resampler->overshot = -1; - resampler->fir_resampler_ratio = 0; - resampler_clear(resampler->fir_resampler[0]); - resampler_clear(resampler->fir_resampler[1]); - resampler_set_quality(resampler->fir_resampler[0], resampler->quality - DUMB_RESAMPLER_BASE); - resampler_set_quality(resampler->fir_resampler[1], resampler->quality - DUMB_RESAMPLER_BASE); -} - - - -DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, int32 pos, int32 start, int32 end, int quality) -{ - DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler)); - if (!resampler) return NULL; - dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality); - return resampler; -} - - - -#define UPDATE_VOLUME( pvol, vol ) { \ - if (pvol) { \ - vol##r += vol##d; \ - if ((vol##d < 0 && vol##r <= vol##t) || \ - (vol##d > 0 && vol##r >= vol##t)) { \ - pvol->volume = pvol->target; \ - if ( pvol->declick_stage == 0 || \ - pvol->declick_stage >= 3) \ - pvol->declick_stage++; \ - pvol = NULL; \ - vol = MULSCV( vol##t, vol##m ); \ - } else { \ - vol = MULSCV( vol##r, vol##m ); \ - } \ - } \ -} - - - -/* Create mono source resampler. */ -#define SUFFIX2 _1 -#define SRC_CHANNELS 1 -#define DIVIDE_BY_SRC_CHANNELS(x) (int)(x) -#define COPYSRC(dstarray, dstindex, srcarray, srcindex) (dstarray)[dstindex] = (srcarray)[srcindex] -#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) (dstarray)[dstindex] = condition ? (srcarray)[srcindex] : 0 -#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume -#define MONO_DEST_VOLUME_VARIABLES vol, volr, vold, volt, volm -#define MONO_DEST_VOLUME_ZEROS 0, 0 -#define SET_MONO_DEST_VOLUME_VARIABLES { \ - if ( volume ) { \ - volr = xs_FloorToInt(volume->volume * 16777216.f); \ - vold = xs_FloorToInt(volume->delta * 16777216.f); \ - volt = xs_FloorToInt(volume->target * 16777216.f); \ - volm = xs_FloorToInt(volume->mix * 16777216.f); \ - vol = MULSCV( volr, volm ); \ - if ( volr == volt ) volume = NULL; \ - } else { \ - vol = 0; \ - vold = 0; \ - volt = 0; \ - volm = 0; \ - } \ -} -#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = (float)volr / 16777216.0f -#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0) -#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \ - int xm = x[offset]; \ - *dst++ op ALIAS(xm, lvol); \ - *dst++ op ALIAS(xm, rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ -} -#define STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) { \ - int xm = LINEAR(x[o0], x[o1]); \ - *dst++ op MULSC(xm, lvol); \ - *dst++ op MULSC(xm, rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ -} -#define STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \ - int xm = CUBIC(x0[o0], x[o1], x[o2], x3[o3]); \ - *dst++ op CUBICVOL(xm, lvol); \ - *dst++ op CUBICVOL(xm, rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ -} -#define POKE_FIR(offset) { \ - resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \ -} -#define MONO_DEST_PEEK_FIR *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ) -#define MONO_DEST_MIX_FIR { \ - *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ); \ - UPDATE_VOLUME( volume, vol ); \ -} -#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0], 1 ) -#define STEREO_DEST_PEEK_FIR { \ - int sample = resampler_get_sample( resampler->fir_resampler[0] ); \ - *dst++ = MULSC( sample, lvol ); \ - *dst++ = MULSC( sample, rvol ); \ -} -#define STEREO_DEST_MIX_FIR { \ - int sample = resampler_get_sample( resampler->fir_resampler[0] ); \ - *dst++ += MULSC( sample, lvol ); \ - *dst++ += MULSC( sample, rvol ); \ - UPDATE_VOLUME( volume_left, lvol ); \ - UPDATE_VOLUME( volume_right, rvol ); \ -} -#include "resamp2.inc" - -/* Create stereo source resampler. */ -#define SUFFIX2 _2 -#define SRC_CHANNELS 2 -#define DIVIDE_BY_SRC_CHANNELS(x) (int)((x) >> 1) -#define COPYSRC(dstarray, dstindex, srcarray, srcindex) { \ - (dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \ - (dstarray)[(dstindex)*2+1] = (srcarray)[(srcindex)*2+1]; \ -} -#define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) { \ - if (condition) { \ - (dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \ - (dstarray)[(dstindex)*2+1] = (srcarray)[(srcindex)*2+1]; \ - } else { \ - (dstarray)[(dstindex)*2] = 0; \ - (dstarray)[(dstindex)*2+1] = 0; \ - } \ -} - -#define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right -#define MONO_DEST_VOLUME_VARIABLES lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm -#define MONO_DEST_VOLUME_ZEROS 0, 0 -#define SET_MONO_DEST_VOLUME_VARIABLES { \ - if ( volume_left ) { \ - lvolr = xs_FloorToInt(volume_left->volume * 16777216.f); \ - lvold = xs_FloorToInt(volume_left->delta * 16777216.f); \ - lvolt = xs_FloorToInt(volume_left->target * 16777216.f); \ - lvolm = xs_FloorToInt(volume_left->mix * 16777216.f); \ - lvol = MULSCV( lvolr, lvolm ); \ - if ( lvolr == lvolt ) volume_left = NULL; \ - } else { \ - lvol = 0; \ - lvold = 0; \ - lvolt = 0; \ - lvolm = 0; \ - } \ - if ( volume_right ) { \ - rvolr = xs_FloorToInt(volume_right->volume * 16777216.f); \ - rvold = xs_FloorToInt(volume_right->delta * 16777216.f); \ - rvolt = xs_FloorToInt(volume_right->target * 16777216.f); \ - rvolm = xs_FloorToInt(volume_right->mix * 16777216.f); \ - rvol = MULSCV( rvolr, rvolm ); \ - if ( rvolr == rvolt ) volume_right = NULL; \ - } else { \ - rvol = 0; \ - rvold = 0; \ - rvolt = 0; \ - rvolm = 0; \ - } \ -} -#define RETURN_MONO_DEST_VOLUME_VARIABLES { \ - if ( volume_left ) volume_left->volume = (float)lvolr / 16777216.0f; \ - if ( volume_right ) volume_right->volume = (float)rvolr / 16777216.0f; \ -} -#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) -#define STEREO_DEST_MIX_ALIAS(op, upd, offset) { \ - *dst++ op ALIAS(x[(offset)*2], lvol); \ - *dst++ op ALIAS(x[(offset)*2+1], rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ -} -#define STEREO_DEST_MIX_LINEAR(op, upd, o0, o1) { \ - *dst++ op MULSC(LINEAR(x[(o0)*2], x[(o1)*2]), lvol); \ - *dst++ op MULSC(LINEAR(x[(o0)*2+1], x[(o1)*2+1]), rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ -} -#define STEREO_DEST_MIX_CUBIC(op, upd, x0, x3, o0, o1, o2, o3) { \ - *dst++ op CUBICVOL(CUBIC(x0[(o0)*2], x[(o1)*2], x[(o2)*2], x3[(o3)*2]), lvol); \ - *dst++ op CUBICVOL(CUBIC(x0[(o0)*2+1], x[(o1)*2+1], x[(o2)*2+1], x3[(o3)*2+1]), rvol); \ - if ( upd ) UPDATE_VOLUME( volume_left, lvol ); \ - if ( upd ) UPDATE_VOLUME( volume_right, rvol ); \ -} -#define POKE_FIR(offset) { \ - resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \ - resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \ -} -#define MONO_DEST_PEEK_FIR { \ - *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ - MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ -} -#define MONO_DEST_MIX_FIR { \ - *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ - MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ - UPDATE_VOLUME( volume_left, lvol ); \ - UPDATE_VOLUME( volume_right, rvol ); \ -} -#define ADVANCE_FIR { \ - resampler_remove_sample( resampler->fir_resampler[0], 1 ); \ - resampler_remove_sample( resampler->fir_resampler[1], 1 ); \ -} -#define STEREO_DEST_PEEK_FIR { \ - *dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ - *dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ -} -#define STEREO_DEST_MIX_FIR { \ - *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ - *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ - UPDATE_VOLUME( volume_left, lvol ); \ - UPDATE_VOLUME( volume_right, rvol ); \ -} -#include "resamp2.inc" - - - -void dumb_end_resampler(DUMB_RESAMPLER *resampler) -{ - if (resampler) - free(resampler); -} - - - -#undef FIR -#undef CUBICVOL -#undef CUBIC -#undef LINEAR -#undef ALIAS -#undef SRCBITS -#undef SRCTYPE -#undef SUFFIX diff --git a/libraries/dumb/src/helpers/resampler.c b/libraries/dumb/src/helpers/resampler.c deleted file mode 100644 index d608c8cf6..000000000 --- a/libraries/dumb/src/helpers/resampler.c +++ /dev/null @@ -1,1512 +0,0 @@ -#include -#include -#define _USE_MATH_DEFINES -#include -#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) -#include -#define RESAMPLER_SSE -#endif -#ifdef __APPLE__ -#include -#if TARGET_CPU_ARM || TARGET_CPU_ARM64 -#include -#define RESAMPLER_NEON -#endif -#endif - -#ifdef _MSC_VER -#define ALIGNED _declspec(align(16)) -#else -#define ALIGNED __attribute__((aligned(16))) -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include "internal/resampler.h" - -enum { RESAMPLER_SHIFT = 10 }; -enum { RESAMPLER_SHIFT_EXTRA = 8 }; -enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; -enum { RESAMPLER_RESOLUTION_EXTRA = 1 << (RESAMPLER_SHIFT + RESAMPLER_SHIFT_EXTRA) }; -enum { SINC_WIDTH = 16 }; -enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; -enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 }; - -typedef union bigint -{ - unsigned long long quad; -#ifndef __BIG_ENDIAN__ - struct { unsigned int lo, hi; }; -#else - struct { unsigned int hi, lo; }; -#endif -} bigint; - -// What works well on 32-bit can make for extra work on 64-bit -#if defined(_M_X64) || defined(__amd64__) || TARGET_CPU_ARM64 -#define CLEAR_HI(p) (p.quad &= 0xffffffffu) -#define ADD_HI(a,p) (a += p.quad >> 32) -#define PHASE_REDUCE(p) (int)(p.quad >> (32 - RESAMPLER_SHIFT)) -#else -#define CLEAR_HI(p) p.hi = 0 -#define ADD_HI(a,p) a += p.hi -// Should be equivalent to (int)(p.quad >> (32 - RESAMPLER_SHIFT)), -// since the high part should get zeroed after every sample. -#define PHASE_REDUCE(p) (p.lo >> (32 - RESAMPLER_SHIFT)) -#endif - -static const float RESAMPLER_BLEP_CUTOFF = 0.90f; -static const float RESAMPLER_BLAM_CUTOFF = 0.93f; -static const float RESAMPLER_SINC_CUTOFF = 0.999f; - -ALIGNED static float cubic_lut[CUBIC_SAMPLES]; - -static float sinc_lut[SINC_SAMPLES + 1]; -static float window_lut[SINC_SAMPLES + 1]; - -enum { resampler_buffer_size = SINC_WIDTH * 4 }; - -static int fEqual(const double b, const double a) -{ - return fabs(a - b) < 1.0e-6; -} - -static double sinc(double x) -{ - return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI); -} - -#ifdef RESAMPLER_SSE -#ifdef _MSC_VER -#include -#elif defined(__clang__) || defined(__GNUC__) -static inline void -__cpuid(int *data, int selector) -{ -#if defined(__PIC__) && defined(__i386__) - asm("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi" - : "=a" (data[0]), - "=S" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "0" (selector)); -#elif defined(__PIC__) && defined(__amd64__) - asm("xchg{q} {%%}rbx, %q1; cpuid; xchg{q} {%%}rbx, %q1" - : "=a" (data[0]), - "=&r" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "0" (selector)); -#else - asm("cpuid" - : "=a" (data[0]), - "=b" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "0" (selector)); -#endif -} -#else -#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4) -#endif - -static int query_cpu_feature_sse() { - int buffer[4]; - __cpuid(buffer,1); - if ((buffer[3]&(1<<25)) == 0) return 0; - return 1; -} - -static int resampler_has_sse = 0; -#endif - -void resampler_init(void) -{ - unsigned i; - double dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; - for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx) - { - double y = x / SINC_WIDTH; -#if 0 - // Blackman - float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y); -#elif 1 - // Nuttal 3 term - double window = 0.40897 + 0.5 * cos(M_PI * y) + 0.09103 * cos(2.0 * M_PI * y); -#elif 0 - // C.R.Helmrich's 2 term window - float window = 0.79445 * cos(0.5 * M_PI * y) + 0.20555 * cos(1.5 * M_PI * y); -#elif 0 - // Lanczos - float window = sinc(y); -#endif - sinc_lut[i] = (float)(fabs(x) < SINC_WIDTH ? sinc(x) : 0.0); - window_lut[i] = (float)window; - } - dx = 1.0 / RESAMPLER_RESOLUTION; - x = 0.0; - for (i = 0; i < RESAMPLER_RESOLUTION; ++i, x += dx) - { - cubic_lut[i*4] = (float)(-0.5 * x * x * x + x * x - 0.5 * x); - cubic_lut[i*4+1] = (float)( 1.5 * x * x * x - 2.5 * x * x + 1.0); - cubic_lut[i*4+2] = (float)(-1.5 * x * x * x + 2.0 * x * x + 0.5 * x); - cubic_lut[i*4+3] = (float)( 0.5 * x * x * x - 0.5 * x * x); - } -#ifdef RESAMPLER_SSE - resampler_has_sse = query_cpu_feature_sse(); -#endif -} - -typedef struct resampler -{ - int write_pos, write_filled; - int read_pos, read_filled; - bigint phase; - bigint phase_inc; - bigint inv_phase; - bigint inv_phase_inc; - unsigned char quality; - signed char delay_added; - signed char delay_removed; - double last_amp; - double accumulator; - float buffer_in[resampler_buffer_size * 2]; - float buffer_out[resampler_buffer_size + SINC_WIDTH * 2 - 1]; -} resampler; - -void * resampler_create(void) -{ - resampler * r = ( resampler * ) malloc( sizeof(resampler) ); - if ( !r ) return 0; - - r->write_pos = SINC_WIDTH - 1; - r->write_filled = 0; - r->read_pos = 0; - r->read_filled = 0; - r->phase.quad = 0; - r->phase_inc.quad = 0; - r->inv_phase.quad = 0; - r->inv_phase_inc.quad = 0; - r->quality = RESAMPLER_QUALITY_MAX; - r->delay_added = -1; - r->delay_removed = -1; - r->last_amp = 0; - r->accumulator = 0; - memset( r->buffer_in, 0, sizeof(r->buffer_in) ); - memset( r->buffer_out, 0, sizeof(r->buffer_out) ); - - return r; -} - -void resampler_delete(void * _r) -{ - free( _r ); -} - -void * resampler_dup(const void * _r) -{ - void * r_out = malloc( sizeof(resampler) ); - if ( !r_out ) return 0; - - resampler_dup_inplace(r_out, _r); - - return r_out; -} - -void resampler_dup_inplace(void *_d, const void *_s) -{ - const resampler * r_in = ( const resampler * ) _s; - resampler * r_out = ( resampler * ) _d; - - r_out->write_pos = r_in->write_pos; - r_out->write_filled = r_in->write_filled; - r_out->read_pos = r_in->read_pos; - r_out->read_filled = r_in->read_filled; - r_out->phase = r_in->phase; - r_out->phase_inc = r_in->phase_inc; - r_out->inv_phase = r_in->inv_phase; - r_out->inv_phase_inc = r_in->inv_phase_inc; - r_out->quality = r_in->quality; - r_out->delay_added = r_in->delay_added; - r_out->delay_removed = r_in->delay_removed; - r_out->last_amp = r_in->last_amp; - r_out->accumulator = r_in->accumulator; - memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); - memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); -} - -void resampler_set_quality(void *_r, int quality) -{ - resampler * r = ( resampler * ) _r; - if (quality < RESAMPLER_QUALITY_MIN) - quality = RESAMPLER_QUALITY_MIN; - else if (quality > RESAMPLER_QUALITY_MAX) - quality = RESAMPLER_QUALITY_MAX; - if ( r->quality != quality ) - { - if ( quality == RESAMPLER_QUALITY_BLEP || r->quality == RESAMPLER_QUALITY_BLEP || - quality == RESAMPLER_QUALITY_BLAM || r->quality == RESAMPLER_QUALITY_BLAM ) - { - r->read_pos = 0; - r->read_filled = 0; - r->last_amp = 0; - r->accumulator = 0; - memset( r->buffer_out, 0, sizeof(r->buffer_out) ); - } - r->delay_added = -1; - r->delay_removed = -1; - } - r->quality = (unsigned char)quality; -} - -int resampler_get_free_count(void *_r) -{ - resampler * r = ( resampler * ) _r; - return resampler_buffer_size - r->write_filled; -} - -static int resampler_min_filled(resampler *r) -{ - switch (r->quality) - { - default: - case RESAMPLER_QUALITY_ZOH: - case RESAMPLER_QUALITY_BLEP: - return 1; - - case RESAMPLER_QUALITY_LINEAR: - case RESAMPLER_QUALITY_BLAM: - return 2; - - case RESAMPLER_QUALITY_CUBIC: - return 4; - - case RESAMPLER_QUALITY_SINC: - return SINC_WIDTH * 2; - } -} - -static int resampler_input_delay(resampler *r) -{ - switch (r->quality) - { - default: - case RESAMPLER_QUALITY_ZOH: - case RESAMPLER_QUALITY_BLEP: - case RESAMPLER_QUALITY_LINEAR: - case RESAMPLER_QUALITY_BLAM: - return 0; - - case RESAMPLER_QUALITY_CUBIC: - return 1; - - case RESAMPLER_QUALITY_SINC: - return SINC_WIDTH - 1; - } -} - -static int resampler_output_delay(resampler *r) -{ - switch (r->quality) - { - default: - case RESAMPLER_QUALITY_ZOH: - case RESAMPLER_QUALITY_LINEAR: - case RESAMPLER_QUALITY_CUBIC: - case RESAMPLER_QUALITY_SINC: - return 0; - - case RESAMPLER_QUALITY_BLEP: - case RESAMPLER_QUALITY_BLAM: - return SINC_WIDTH - 1; - } -} - -int resampler_ready(void *_r) -{ - resampler * r = ( resampler * ) _r; - return r->write_filled > resampler_min_filled(r); -} - -void resampler_clear(void *_r) -{ - resampler * r = ( resampler * ) _r; - r->write_pos = SINC_WIDTH - 1; - r->write_filled = 0; - r->read_pos = 0; - r->read_filled = 0; - r->phase.quad = 0; - r->delay_added = -1; - r->delay_removed = -1; - memset(r->buffer_in, 0, (SINC_WIDTH - 1) * sizeof(r->buffer_in[0])); - memset(r->buffer_in + resampler_buffer_size, 0, (SINC_WIDTH - 1) * sizeof(r->buffer_in[0])); - if (r->quality == RESAMPLER_QUALITY_BLEP || r->quality == RESAMPLER_QUALITY_BLAM) - { - r->inv_phase.quad = 0; - r->last_amp = 0; - r->accumulator = 0; - memset(r->buffer_out, 0, sizeof(r->buffer_out)); - } -} - -void resampler_set_rate(void *_r, double new_factor) -{ - resampler * r = ( resampler * ) _r; - r->phase_inc.quad = (long long)(new_factor * 0x100000000ll); - new_factor = 1.0 / new_factor; - r->inv_phase_inc.quad = (long long)(new_factor * 0x100000000ll); -} - -void resampler_write_sample(void *_r, short s) -{ - resampler * r = ( resampler * ) _r; - - if ( r->delay_added < 0 ) - { - r->delay_added = 0; - r->write_filled = resampler_input_delay( r ); - } - - if ( r->write_filled < resampler_buffer_size ) - { - float s32 = s; - s32 *= 256.0; - - r->buffer_in[ r->write_pos ] = s32; - r->buffer_in[ r->write_pos + resampler_buffer_size ] = s32; - - ++r->write_filled; - - r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size; - } -} - -void resampler_write_sample_fixed(void *_r, int s, unsigned char depth) -{ - resampler * r = ( resampler * ) _r; - - if ( r->delay_added < 0 ) - { - r->delay_added = 0; - r->write_filled = resampler_input_delay( r ); - } - - if ( r->write_filled < resampler_buffer_size ) - { - double s32 = s; - s32 /= (double)(1 << (depth - 1)); - - r->buffer_in[ r->write_pos ] = (float)s32; - r->buffer_in[ r->write_pos + resampler_buffer_size ] = (float)s32; - - ++r->write_filled; - - r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size; - } -} - -static int resampler_run_zoh(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 1; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - do - { - if ( out >= out_end ) - break; - - *out++ = *in; - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} - -#ifndef RESAMPLER_NEON -static int resampler_run_blep(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 1; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - double last_amp = r->last_amp; - bigint inv_phase = r->inv_phase; - bigint inv_phase_inc = r->inv_phase_inc; - - const int step = (int)(RESAMPLER_BLEP_CUTOFF * RESAMPLER_RESOLUTION); - const int window_step = RESAMPLER_RESOLUTION; - - do - { - double sample; - - if ( out + SINC_WIDTH * 2 > out_end ) - break; - - sample = *in++ - last_amp; - - if (sample) - { - double kernel[SINC_WIDTH * 2], kernel_sum = 0.0f; - int phase_reduced = PHASE_REDUCE(inv_phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - int i = SINC_WIDTH; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - last_amp += sample; - sample /= kernel_sum; - for (i = 0; i < SINC_WIDTH * 2; ++i) - out[i] += (float)(sample * kernel[i]); - } - - inv_phase.quad += inv_phase_inc.quad; - - ADD_HI(out, inv_phase); - - CLEAR_HI(inv_phase); - } - while ( in < in_end ); - - r->inv_phase = inv_phase; - r->last_amp = last_amp; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_SSE -static int resampler_run_blep_sse(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 1; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - double last_amp = r->last_amp; - bigint inv_phase = r->inv_phase; - bigint inv_phase_inc = r->inv_phase_inc; - - const int step = (int)(RESAMPLER_BLEP_CUTOFF * RESAMPLER_RESOLUTION); - const int window_step = RESAMPLER_RESOLUTION; - - do - { - double sample; - - if ( out + SINC_WIDTH * 2 > out_end ) - break; - - sample = *in++ - last_amp; - - if (sample) - { - float kernel_sum = 0.0f; - __m128 kernel[SINC_WIDTH / 2]; - __m128 temp1, temp2; - __m128 samplex; - float *kernelf = (float*)(&kernel); - int phase_reduced = PHASE_REDUCE(inv_phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - int i = SINC_WIDTH; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - last_amp += sample; - sample /= kernel_sum; - samplex = _mm_set1_ps( (float)sample ); - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = _mm_load_ps( (const float *)( kernel + i ) ); - temp1 = _mm_mul_ps( temp1, samplex ); - temp2 = _mm_loadu_ps( (const float *) out + i * 4 ); - temp1 = _mm_add_ps( temp1, temp2 ); - _mm_storeu_ps( (float *) out + i * 4, temp1 ); - } - } - - inv_phase.quad += inv_phase_inc.quad; - - ADD_HI(out, inv_phase); - - CLEAR_HI(inv_phase); - } - while ( in < in_end ); - - r->inv_phase = inv_phase; - r->last_amp = last_amp; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_NEON -static int resampler_run_blep(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 1; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - float last_amp = r->last_amp; - bigint inv_phase = r->inv_phase; - bigint inv_phase_inc = r->inv_phase_inc; - - const int step = RESAMPLER_BLEP_CUTOFF * RESAMPLER_RESOLUTION; - const int window_step = RESAMPLER_RESOLUTION; - - do - { - float sample; - - if ( out + SINC_WIDTH * 2 > out_end ) - break; - - sample = *in++ - last_amp; - - if (sample) - { - float kernel_sum = 0.0f; - float32x4_t kernel[SINC_WIDTH / 2]; - float32x4_t temp1, temp2; - float32x4_t samplex; - float *kernelf = (float*)(&kernel); - int phase_reduced = PHASE_REDUCE(inv_phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - int i = SINC_WIDTH; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - last_amp += sample; - sample /= kernel_sum; - samplex = vdupq_n_f32(sample); - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = vld1q_f32( (const float32_t *)( kernel + i ) ); - temp2 = vld1q_f32( (const float32_t *) out + i * 4 ); - temp2 = vmlaq_f32( temp2, temp1, samplex ); - vst1q_f32( (float32_t *) out + i * 4, temp2 ); - } - } - - inv_phase.quad += inv_phase_inc.quad; - - ADD_HI(out, inv_phase); - - CLEAR_HI(inv_phase); - } - while ( in < in_end ); - - r->inv_phase = inv_phase; - r->last_amp = last_amp; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -static int resampler_run_linear(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - do - { - if ( out >= out_end ) - break; - - *out++ = (float)(in[0] + (in[1] - in[0]) * phase.lo * (1.f / 0x100000000ll)); - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} - -#ifndef RESAMPLER_NEON -static int resampler_run_blam(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - double last_amp = r->last_amp; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - bigint inv_phase = r->inv_phase; - bigint inv_phase_inc = r->inv_phase_inc; - - const int step = (int)(RESAMPLER_BLAM_CUTOFF * RESAMPLER_RESOLUTION); - const int window_step = RESAMPLER_RESOLUTION; - - do - { - double sample; - - if ( out + SINC_WIDTH * 2 > out_end ) - break; - - sample = in[0]; - if (phase_inc.quad < 0x100000000ll) - sample += (in[1] - in[0]) * phase.quad * (1.f / 0x100000000ll); - sample -= last_amp; - - if (sample) - { - double kernel[SINC_WIDTH * 2], kernel_sum = 0.0f; - int phase_reduced = PHASE_REDUCE(inv_phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - int i = SINC_WIDTH; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - last_amp += sample; - sample /= kernel_sum; - for (i = 0; i < SINC_WIDTH * 2; ++i) - out[i] += (float)(sample * kernel[i]); - } - - if (inv_phase_inc.quad < 0x100000000ll) - { - ++in; - inv_phase.quad += inv_phase_inc.quad; - ADD_HI(out, inv_phase); - CLEAR_HI(inv_phase); - } - else - { - phase.quad += phase_inc.quad; - ++out; - ADD_HI(in, phase); - CLEAR_HI(phase); - } - } - while ( in < in_end ); - - r->phase = phase; - r->inv_phase = inv_phase; - r->last_amp = last_amp; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_SSE -static int resampler_run_blam_sse(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - double last_amp = r->last_amp; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - bigint inv_phase = r->inv_phase; - bigint inv_phase_inc = r->inv_phase_inc; - - const int step = (int)(RESAMPLER_BLAM_CUTOFF * RESAMPLER_RESOLUTION); - const int window_step = RESAMPLER_RESOLUTION; - - do - { - double sample; - - if ( out + SINC_WIDTH * 2 > out_end ) - break; - - sample = in[0]; - if (phase_inc.quad < 0x100000000ll) - { - sample += (in[1] - in[0]) * phase.quad * (1.f / 0x100000000ll); - } - sample -= last_amp; - - if (sample) - { - float kernel_sum = 0.0f; - __m128 kernel[SINC_WIDTH / 2]; - __m128 temp1, temp2; - __m128 samplex; - float *kernelf = (float*)(&kernel); - int phase_reduced = PHASE_REDUCE(inv_phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - int i = SINC_WIDTH; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - last_amp += sample; - sample /= kernel_sum; - samplex = _mm_set1_ps( (float)sample ); - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = _mm_load_ps( (const float *)( kernel + i ) ); - temp1 = _mm_mul_ps( temp1, samplex ); - temp2 = _mm_loadu_ps( (const float *) out + i * 4 ); - temp1 = _mm_add_ps( temp1, temp2 ); - _mm_storeu_ps( (float *) out + i * 4, temp1 ); - } - } - - if (inv_phase_inc.quad < 0x100000000ll) - { - ++in; - inv_phase.quad += inv_phase_inc.quad; - ADD_HI(out, inv_phase); - CLEAR_HI(inv_phase); - } - else - { - phase.quad += phase_inc.quad; - ++out; - - if (phase.quad >= 0x100000000ll) - { - ++in; - CLEAR_HI(phase); - } - } - } - while ( in < in_end ); - - r->phase = phase; - r->inv_phase = inv_phase; - r->last_amp = last_amp; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_NEON -static int resampler_run_blam(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - float last_amp = r->last_amp; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - bigint inv_phase = r->inv_phase; - bigint inv_phase_inc = r->inv_phase_inc; - - const int step = RESAMPLER_BLAM_CUTOFF * RESAMPLER_RESOLUTION; - const int window_step = RESAMPLER_RESOLUTION; - - do - { - float sample; - - if ( out + SINC_WIDTH * 2 > out_end ) - break; - - sample = in[0]; - if (phase_inc.quad < 0x100000000ll) - sample += (in[1] - in[0]) * phase; - sample -= last_amp; - - if (sample) - { - float kernel_sum = 0.0; - float32x4_t kernel[SINC_WIDTH / 2]; - float32x4_t temp1, temp2; - float32x4_t samplex; - float *kernelf = (float*)(&kernel); - int phase_reduced = PHASE_REDUCE(inv_phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - int i = SINC_WIDTH; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - last_amp += sample; - sample /= kernel_sum; - samplex = vdupq_n_f32(sample); - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = vld1q_f32( (const float32_t *)( kernel + i ) ); - temp2 = vld1q_f32( (const float32_t *) out + i * 4 ); - temp2 = vmlaq_f32( temp2, temp1, samplex ); - vst1q_f32( (float32_t *) out + i * 4, temp2 ); - } - } - - if (inv_phase_inc.quad < 0x100000000ll) - { - ++in; - inv_phase.quad += inv_phase_inc.quad; - ADD_HI(out, inv_phase); - CLEAR_HI(inv_phase); - } - else - { - phase.quad += phase_inc.quad; - ++out; - - if (phase.quad >= 0x100000000ll) - { - ++in; - CLEAR_HI(phase); - } - } - } - while ( in < in_end ); - - r->phase = phase; - r->inv_phase = inv_phase; - r->last_amp = last_amp; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifndef RESAMPLER_NEON -static int resampler_run_cubic(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 4; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - do - { - float * kernel; - int i; - float sample; - - if ( out >= out_end ) - break; - - kernel = cubic_lut + PHASE_REDUCE(phase) * 4; - - for (sample = 0, i = 0; i < 4; ++i) - sample += in[i] * kernel[i]; - *out++ = sample; - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_SSE -static int resampler_run_cubic_sse(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 4; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - do - { - __m128 temp1, temp2; - __m128 samplex = _mm_setzero_ps(); - - if ( out >= out_end ) - break; - - temp1 = _mm_loadu_ps( (const float *)( in ) ); - temp2 = _mm_load_ps( (const float *)( cubic_lut + PHASE_REDUCE(phase) * 4 ) ); - temp1 = _mm_mul_ps( temp1, temp2 ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = _mm_movehl_ps( temp1, samplex ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = samplex; - temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); - samplex = _mm_add_ps( samplex, temp1 ); - _mm_store_ss( out, samplex ); - ++out; - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_NEON -static int resampler_run_cubic(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= 4; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - do - { - float32x4_t temp1, temp2; - float32x2_t half; - - if ( out >= out_end ) - break; - - temp1 = vld1q_f32( (const float32_t *)( in ) ); - temp2 = vld1q_f32( (const float32_t *)( cubic_lut + PHASE_REDUCE(phase) * 4 ) ); - temp1 = vmulq_f32( temp1, temp2 ); - half = vadd_f32(vget_high_f32(temp1), vget_low_f32(temp1)); - *out++ = vget_lane_f32(vpadd_f32(half, half), 0); - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase) - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifndef RESAMPLER_NEON -static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - int step = phase_inc.quad > 0x100000000ll ? - (int)(RESAMPLER_RESOLUTION / (phase_inc.quad * (1.f / 0x100000000ll)) * RESAMPLER_SINC_CUTOFF) : - (int)(RESAMPLER_RESOLUTION * RESAMPLER_SINC_CUTOFF); - int window_step = RESAMPLER_RESOLUTION; - - do - { - double kernel[SINC_WIDTH * 2], kernel_sum = 0.0; - int i = SINC_WIDTH; - int phase_reduced = PHASE_REDUCE(phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - float sample; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) - sample += (float)(in[i] * kernel[i]); - *out++ = (float)(sample / kernel_sum); - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_SSE -static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - int step = phase_inc.quad > 0x100000000ll ? - (int)(RESAMPLER_RESOLUTION / (phase_inc.quad * (1.f / 0x100000000ll)) * RESAMPLER_SINC_CUTOFF) : - (int)(RESAMPLER_RESOLUTION * RESAMPLER_SINC_CUTOFF); - int window_step = RESAMPLER_RESOLUTION; - - do - { - // accumulate in extended precision - float kernel_sum = 0.0; - __m128 kernel[SINC_WIDTH / 2]; - __m128 temp1, temp2; - __m128 samplex = _mm_setzero_ps(); - float *kernelf = (float*)(&kernel); - int i = SINC_WIDTH; - int phase_reduced = PHASE_REDUCE(phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) ); - temp2 = _mm_load_ps( (const float *)( kernel + i ) ); - temp1 = _mm_mul_ps( temp1, temp2 ); - samplex = _mm_add_ps( samplex, temp1 ); - } - kernel_sum = 1.0f / kernel_sum; - temp1 = _mm_movehl_ps( temp1, samplex ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = samplex; - temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = _mm_set_ss( kernel_sum ); - samplex = _mm_mul_ps( samplex, temp1 ); - _mm_store_ss( out, samplex ); - ++out; - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -#ifdef RESAMPLER_NEON -static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - bigint phase = r->phase; - bigint phase_inc = r->phase_inc; - - int step = phase_inc.quad > 0x100000000ll ? - (int)(RESAMPLER_RESOLUTION / (phase_inc.quad * (1.f / 0x100000000ll)) * RESAMPLER_SINC_CUTOFF) : - (int)(RESAMPLER_RESOLUTION * RESAMPLER_SINC_CUTOFF); - int window_step = RESAMPLER_RESOLUTION; - - do - { - // accumulate in extended precision - float kernel_sum = 0.0; - float32x4_t kernel[SINC_WIDTH / 2]; - float32x4_t temp1, temp2; - float32x4_t samplex = {0}; - float32x2_t half; - float *kernelf = (float*)(&kernel); - int i = SINC_WIDTH; - int phase_reduced = PHASE_REDUCE(phase); - int phase_adj = phase_reduced * step / RESAMPLER_RESOLUTION; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - int window_pos = i * window_step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)] * window_lut[abs(phase_reduced - window_pos)]; - } - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = vld1q_f32( (const float32_t *)( in + i * 4 ) ); - temp2 = vld1q_f32( (const float32_t *)( kernel + i ) ); - samplex = vmlaq_f32( samplex, temp1, temp2 ); - } - kernel_sum = 1.0 / kernel_sum; - samplex = vmulq_f32(samplex, vmovq_n_f32(kernel_sum)); - half = vadd_f32(vget_high_f32(samplex), vget_low_f32(samplex)); - *out++ = vget_lane_f32(vpadd_f32(half, half), 0); - - phase.quad += phase_inc.quad; - - ADD_HI(in, phase); - - CLEAR_HI(phase); - } - while ( in < in_end ); - - r->phase = phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -static void resampler_fill(resampler * r) -{ - int min_filled = resampler_min_filled(r); - int quality = r->quality; - while ( r->write_filled > min_filled && - r->read_filled < resampler_buffer_size ) - { - int write_pos = ( r->read_pos + r->read_filled ) % resampler_buffer_size; - int write_size = resampler_buffer_size - write_pos; - float * out = r->buffer_out + write_pos; - if ( write_size > ( resampler_buffer_size - r->read_filled ) ) - write_size = resampler_buffer_size - r->read_filled; - switch (quality) - { - case RESAMPLER_QUALITY_ZOH: - resampler_run_zoh( r, &out, out + write_size ); - break; - - case RESAMPLER_QUALITY_BLEP: - { - int used; - int write_extra = 0; - if ( write_pos >= r->read_pos ) - write_extra = r->read_pos; - if ( write_extra > SINC_WIDTH * 2 - 1 ) - write_extra = SINC_WIDTH * 2 - 1; - memcpy( r->buffer_out + resampler_buffer_size, r->buffer_out, write_extra * sizeof(r->buffer_out[0]) ); -#ifdef RESAMPLER_SSE - if ( resampler_has_sse ) - used = resampler_run_blep_sse( r, &out, out + write_size + write_extra ); - else -#endif - used = resampler_run_blep( r, &out, out + write_size + write_extra ); - memcpy( r->buffer_out, r->buffer_out + resampler_buffer_size, write_extra * sizeof(r->buffer_out[0]) ); - if (!used) - return; - break; - } - - case RESAMPLER_QUALITY_LINEAR: - resampler_run_linear( r, &out, out + write_size ); - break; - - case RESAMPLER_QUALITY_BLAM: - { - float * out_ = out; - int write_extra = 0; - if ( write_pos >= r->read_pos ) - write_extra = r->read_pos; - if ( write_extra > SINC_WIDTH * 2 - 1 ) - write_extra = SINC_WIDTH * 2 - 1; - memcpy( r->buffer_out + resampler_buffer_size, r->buffer_out, write_extra * sizeof(r->buffer_out[0]) ); -#ifdef RESAMPLER_SSE - if ( resampler_has_sse ) - resampler_run_blam_sse( r, &out, out + write_size + write_extra ); - else -#endif - resampler_run_blam( r, &out, out + write_size + write_extra ); - memcpy( r->buffer_out, r->buffer_out + resampler_buffer_size, write_extra * sizeof(r->buffer_out[0]) ); - if ( out == out_ ) - return; - break; - } - - case RESAMPLER_QUALITY_CUBIC: -#ifdef RESAMPLER_SSE - if ( resampler_has_sse ) - resampler_run_cubic_sse( r, &out, out + write_size ); - else -#endif - resampler_run_cubic( r, &out, out + write_size ); - break; - - case RESAMPLER_QUALITY_SINC: -#ifdef RESAMPLER_SSE - if ( resampler_has_sse ) - resampler_run_sinc_sse( r, &out, out + write_size ); - else -#endif - resampler_run_sinc( r, &out, out + write_size ); - break; - } - r->read_filled += (int)(out - r->buffer_out - write_pos); - } -} - -static void resampler_fill_and_remove_delay(resampler * r) -{ - resampler_fill( r ); - if ( r->delay_removed < 0 ) - { - int delay = resampler_output_delay( r ); - r->delay_removed = 0; - while ( delay-- ) - resampler_remove_sample( r, 1 ); - } -} - -int resampler_get_sample_count(void *_r) -{ - resampler * r = ( resampler * ) _r; - if ( r->read_filled < 1 && ((r->quality != RESAMPLER_QUALITY_BLEP && r->quality != RESAMPLER_QUALITY_BLAM) || r->inv_phase_inc.quad)) - resampler_fill_and_remove_delay( r ); - return r->read_filled; -} - -int resampler_get_sample(void *_r) -{ - resampler * r = ( resampler * ) _r; - if ( r->read_filled < 1 && r->phase_inc.quad) - resampler_fill_and_remove_delay( r ); - if ( r->read_filled < 1 ) - return 0; - if ( r->quality == RESAMPLER_QUALITY_BLEP || r->quality == RESAMPLER_QUALITY_BLAM ) - return (int)(r->buffer_out[ r->read_pos ] + r->accumulator); - else - return (int)r->buffer_out[ r->read_pos ]; -} - -float resampler_get_sample_float(void *_r) -{ - resampler * r = ( resampler * ) _r; - if ( r->read_filled < 1 && r->phase_inc.quad) - resampler_fill_and_remove_delay( r ); - if ( r->read_filled < 1 ) - return 0; - if ( r->quality == RESAMPLER_QUALITY_BLEP || r->quality == RESAMPLER_QUALITY_BLAM ) - return (float)(r->buffer_out[ r->read_pos ] + r->accumulator); - else - return r->buffer_out[ r->read_pos ]; -} - -void resampler_remove_sample(void *_r, int decay) -{ - resampler * r = ( resampler * ) _r; - if ( r->read_filled > 0 ) - { - if ( r->quality == RESAMPLER_QUALITY_BLEP || r->quality == RESAMPLER_QUALITY_BLAM ) - { - r->accumulator += r->buffer_out[ r->read_pos ]; - r->buffer_out[ r->read_pos ] = 0; - if (decay) - { - r->accumulator -= r->accumulator * (1.0f / 8192.0f); - if (fabs(r->accumulator) < 1e-20f) - r->accumulator = 0; - } - } - --r->read_filled; - r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size; - } -} diff --git a/libraries/dumb/src/helpers/riff.c b/libraries/dumb/src/helpers/riff.c deleted file mode 100644 index 6589d12ff..000000000 --- a/libraries/dumb/src/helpers/riff.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "dumb.h" -#include "internal/riff.h" - -#include -#include - -struct riff * riff_parse( DUMBFILE * f, int32 offset, int32 size, unsigned proper ) -{ - unsigned stream_size; - struct riff * stream; - - - if ( size < 8 ) return 0; - - if ( dumbfile_seek(f, offset, DFS_SEEK_SET) ) return 0; - if ( dumbfile_mgetl(f) != DUMB_ID('R','I','F','F') ) return 0; - - stream_size = dumbfile_igetl(f); - if ( stream_size + 8 > (unsigned)size ) return 0; - if ( stream_size < 4 ) return 0; - - stream = (struct riff *) malloc( sizeof( struct riff ) ); - if ( ! stream ) return 0; - - stream->type = dumbfile_mgetl(f); - stream->chunk_count = 0; - stream->chunks = 0; - - stream_size -= 4; - - while ( stream_size && !dumbfile_error(f) ) - { - struct riff_chunk * chunk; - if ( stream_size < 8 ) break; - stream->chunks = ( struct riff_chunk * ) realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) ); - if ( ! stream->chunks ) break; - chunk = stream->chunks + stream->chunk_count; - chunk->type = dumbfile_mgetl(f); - chunk->size = dumbfile_igetl(f); - chunk->offset = dumbfile_pos(f); - stream_size -= 8; - if ( stream_size < chunk->size ) break; - if ( chunk->type == DUMB_ID('R','I','F','F') ) - { - chunk->nested = riff_parse( f, chunk->offset - 8, chunk->size + 8, proper ); - if ( ! chunk->nested ) break; - } - else - { - chunk->nested = 0; - } - dumbfile_seek(f, chunk->offset + chunk->size, DFS_SEEK_SET); - stream_size -= chunk->size; - if ( proper && ( chunk->size & 1 ) ) - { - dumbfile_skip(f, 1); - -- stream_size; - } - ++stream->chunk_count; - } - - if ( stream_size ) - { - riff_free( stream ); - stream = 0; - } - - return stream; -} - -void riff_free( struct riff * stream ) -{ - if ( stream ) - { - if ( stream->chunks ) - { - unsigned i; - for ( i = 0; i < stream->chunk_count; ++i ) - { - struct riff_chunk * chunk = stream->chunks + i; - if ( chunk->nested ) riff_free( chunk->nested ); - } - free( stream->chunks ); - } - free( stream ); - } -} diff --git a/libraries/dumb/src/helpers/sampbuf.c b/libraries/dumb/src/helpers/sampbuf.c deleted file mode 100644 index ea30d506f..000000000 --- a/libraries/dumb/src/helpers/sampbuf.c +++ /dev/null @@ -1,64 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * sampbuf.c - Helper for allocating sample / / \ \ - * buffers. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include "dumb.h" - - - -/* DEPRECATED */ -sample_t **create_sample_buffer(int n_channels, int32 length) -{ - int i; - sample_t **samples = malloc(n_channels * sizeof(*samples)); - if (!samples) return NULL; - samples[0] = malloc(n_channels * length * sizeof(*samples[0])); - if (!samples[0]) { - free(samples); - return NULL; - } - for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length; - return samples; -} - - - -sample_t **DUMBEXPORT allocate_sample_buffer(int n_channels, int32 length) -{ - int i; - sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples)); - if (!samples) return NULL; - samples[0] = malloc(n_channels * length * sizeof(*samples[0])); - if (!samples[0]) { - free(samples); - return NULL; - } - for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2; - return samples; -} - - - -void DUMBEXPORT destroy_sample_buffer(sample_t **samples) -{ - if (samples) { - free(samples[0]); - free(samples); - } -} diff --git a/libraries/dumb/src/helpers/silence.c b/libraries/dumb/src/helpers/silence.c deleted file mode 100644 index 428f6577f..000000000 --- a/libraries/dumb/src/helpers/silence.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * silence.c - Silencing helper. / / \ \ - * | < / \_ - * By entheh. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include "dumb.h" - - - -void DUMBEXPORT dumb_silence(sample_t *samples, int32 length) -{ - memset(samples, 0, length * sizeof(*samples)); -} - diff --git a/libraries/dumb/src/helpers/stdfile.c b/libraries/dumb/src/helpers/stdfile.c deleted file mode 100644 index f46022791..000000000 --- a/libraries/dumb/src/helpers/stdfile.c +++ /dev/null @@ -1,146 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * stdfile.c - stdio file input module. / / \ \ - * | < / \_ - * By entheh. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" - - - -typedef struct dumb_stdfile -{ - FILE * file; - long size; -} dumb_stdfile; - - - -static void *DUMBCALLBACK dumb_stdfile_open(const char *filename) -{ - dumb_stdfile * file = ( dumb_stdfile * ) malloc( sizeof(dumb_stdfile) ); - if ( !file ) return 0; - file->file = fopen(filename, "rb"); - fseek(file->file, 0, SEEK_END); - file->size = ftell(file->file); - fseek(file->file, 0, SEEK_SET); - return file; -} - - - -static int DUMBCALLBACK dumb_stdfile_skip(void *f, long n) -{ - dumb_stdfile * file = ( dumb_stdfile * ) f; - return fseek(file->file, n, SEEK_CUR); -} - - - -static int DUMBCALLBACK dumb_stdfile_getc(void *f) -{ - dumb_stdfile * file = ( dumb_stdfile * ) f; - return fgetc(file->file); -} - - - -static int32 DUMBCALLBACK dumb_stdfile_getnc(char *ptr, int32 n, void *f) -{ - dumb_stdfile * file = ( dumb_stdfile * ) f; - return (int32)fread(ptr, 1, n, file->file); -} - - - -static void DUMBCALLBACK dumb_stdfile_close(void *f) -{ - dumb_stdfile * file = ( dumb_stdfile * ) f; - fclose(file->file); - free(f); -} - - - -static void DUMBCALLBACK dumb_stdfile_noclose(void *f) -{ - free(f); -} - - - -static int DUMBCALLBACK dumb_stdfile_seek(void *f, long n) -{ - dumb_stdfile * file = ( dumb_stdfile * ) f; - return fseek(file->file, n, SEEK_SET); -} - - - -static long DUMBCALLBACK dumb_stdfile_get_size(void *f) -{ - dumb_stdfile * file = ( dumb_stdfile * ) f; - return file->size; -} - - - -static const DUMBFILE_SYSTEM stdfile_dfs = { - &dumb_stdfile_open, - &dumb_stdfile_skip, - &dumb_stdfile_getc, - &dumb_stdfile_getnc, - &dumb_stdfile_close, - &dumb_stdfile_seek, - &dumb_stdfile_get_size -}; - - - -void DUMBEXPORT dumb_register_stdfiles(void) -{ - register_dumbfile_system(&stdfile_dfs); -} - - - -static const DUMBFILE_SYSTEM stdfile_dfs_leave_open = { - NULL, - &dumb_stdfile_skip, - &dumb_stdfile_getc, - &dumb_stdfile_getnc, - &dumb_stdfile_noclose, - &dumb_stdfile_seek, - &dumb_stdfile_get_size -}; - - - -DUMBFILE *DUMBEXPORT dumbfile_open_stdfile(FILE *p) -{ - dumb_stdfile * file = ( dumb_stdfile * ) malloc( sizeof(dumb_stdfile) ); - DUMBFILE *d; - if ( !file ) return 0; - file->file = p; - fseek(p, 0, SEEK_END); - file->size = ftell(p); - fseek(p, 0, SEEK_SET); - d = dumbfile_open_ex(file, &stdfile_dfs_leave_open); - - return d; -} diff --git a/libraries/dumb/src/it/itload.c b/libraries/dumb/src/it/itload.c deleted file mode 100644 index 01f7cf019..000000000 --- a/libraries/dumb/src/it/itload.c +++ /dev/null @@ -1,43 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itload.c - Code to read an Impulse Tracker / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By entheh. Don't worry Bob, you're credited | \ / / - * in itread.c! | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must pass - * the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_it_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_it_quick(f); - - dumbfile_close(f); - - return duh; -} - diff --git a/libraries/dumb/src/it/itload2.c b/libraries/dumb/src/it/itload2.c deleted file mode 100644 index 68b38cd77..000000000 --- a/libraries/dumb/src/it/itload2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itload2.c - Function to read an Impulse Tracker / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * Split off from itload.c by entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_it(const char *filename) -{ - DUH *duh = dumb_load_it_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/itmisc.c b/libraries/dumb/src/it/itmisc.c deleted file mode 100644 index 389c74736..000000000 --- a/libraries/dumb/src/it/itmisc.c +++ /dev/null @@ -1,249 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itmisc.c - Miscellaneous functions relating / / \ \ - * to module files. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - -int dumb_it_default_panning_separation = 25; - - -DUMB_IT_SIGDATA *DUMBEXPORT duh_get_it_sigdata(DUH *duh) -{ - return duh_get_raw_sigdata(duh, -1, SIGTYPE_IT); -} - - - -const unsigned char *DUMBEXPORT dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->song_message : NULL; -} - - - -int DUMBEXPORT dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->n_orders : 0; -} - - - -int DUMBEXPORT dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->n_samples : 0; -} - - - -int DUMBEXPORT dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->n_instruments : 0; -} - - - -const unsigned char *DUMBEXPORT dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i) -{ - ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples); - return sd->sample[i].name; -} - - - -const unsigned char *DUMBEXPORT dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i) -{ - ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples); - return sd->sample[i].filename; -} - - - -const unsigned char *DUMBEXPORT dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i) -{ - ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments); - return sd->instrument[i].name; -} - - - -const unsigned char *DUMBEXPORT dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i) -{ - ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments); - return sd->instrument[i].filename; -} - - - -int DUMBEXPORT dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->global_volume : 0; -} - - - -void DUMBEXPORT dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv) -{ - if (sd) sd->global_volume = gv; -} - - - -int DUMBEXPORT dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->mixing_volume : 0; -} - - - -void DUMBEXPORT dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv) -{ - if (sd) sd->mixing_volume = mv; -} - - - -int DUMBEXPORT dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->speed : 0; -} - - - -void DUMBEXPORT dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed) -{ - if (sd) sd->speed = speed; -} - - - -int DUMBEXPORT dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd) -{ - return sd ? sd->tempo : 0; -} - - - -void DUMBEXPORT dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo) -{ - if (sd) sd->tempo = tempo; -} - - - -int DUMBEXPORT dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel) -{ - ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS); - return sd ? sd->channel_volume[channel] : 0; -} - -void DUMBEXPORT dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume) -{ - ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS); - if (sd) sd->channel_volume[channel] = volume; -} - - - -int DUMBEXPORT dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr) -{ - return sr ? sr->order : -1; -} - - - -int DUMBEXPORT dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr) -{ - return sr ? sr->row : -1; -} - - - -int DUMBEXPORT dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr) -{ - return sr ? sr->globalvolume : 0; -} - - - -void DUMBEXPORT dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv) -{ - if (sr) sr->globalvolume = gv; -} - - - -int DUMBEXPORT dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr) -{ - return sr ? sr->tempo : 0; -} - - - -void DUMBEXPORT dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo) -{ - if (sr) sr->tempo = tempo; -} - - - -int DUMBEXPORT dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr) -{ - return sr ? sr->speed : 0; -} - - - -void DUMBEXPORT dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed) -{ - if (sr) sr->speed = speed; -} - - - -int DUMBEXPORT dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel) -{ - return sr ? sr->channel[channel].channelvolume : 0; -} - - - -void DUMBEXPORT dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume) -{ - if (sr) sr->channel[channel].channelvolume = volume; -} - - - -void DUMBEXPORT dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted) -{ - if (sr) { - if (muted) - sr->channel[channel].flags |= IT_CHANNEL_MUTED; - else - sr->channel[channel].flags &= ~IT_CHANNEL_MUTED; - } -} - - - -int DUMBEXPORT dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel) -{ - return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0; -} diff --git a/libraries/dumb/src/it/itorder.c b/libraries/dumb/src/it/itorder.c deleted file mode 100644 index 6959f0544..000000000 --- a/libraries/dumb/src/it/itorder.c +++ /dev/null @@ -1,63 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itorder.c - Code to fix invalid patterns in / / \ \ - * the pattern table. | < / \_ - * | \/ /\ / - * By Julien Cugniere. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - - - -#include - -#include "dumb.h" -#include "internal/it.h" - - - -/* This function ensures that any pattern mentioned in the order table but - * not present in the pattern table is treated as an empty 64 rows pattern. - * This is done by adding such a dummy pattern at the end of the pattern - * table, and redirect invalid orders to it. - * Patterns 254 and 255 are left untouched, unless the signal is an XM. - */ -int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata) -{ - int i; - int found_some = 0; - - int first_invalid = sigdata->n_patterns; - int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253; - - for (i = 0; i < sigdata->n_orders; i++) { - if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) { - sigdata->order[i] = sigdata->n_patterns; - found_some = 1; - } - } - - if (found_some) { - IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1)); - if (!new_pattern) - return -1; - - new_pattern[sigdata->n_patterns].n_rows = 64; - new_pattern[sigdata->n_patterns].n_entries = 0; - new_pattern[sigdata->n_patterns].entry = NULL; - sigdata->pattern = new_pattern; - sigdata->n_patterns++; - } - - return 0; -} diff --git a/libraries/dumb/src/it/itread.c b/libraries/dumb/src/it/itread.c deleted file mode 100644 index a226c530f..000000000 --- a/libraries/dumb/src/it/itread.c +++ /dev/null @@ -1,1414 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itread.c - Code to read an Impulse Tracker / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * Based on the loader from an IT player by Bob. \_ / > / - * Adapted for DUMB by entheh. | \ / / - * | ' / - * \__/ - */ - -#include -#include //might not be necessary later; required for memset - -#include "dumb.h" -#include "internal/it.h" - -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - - -#define INVESTIGATE_OLD_INSTRUMENTS - - - -typedef unsigned char byte; -typedef unsigned short word; -typedef uint32 dword; - -typedef struct readblock_crap readblock_crap; - -struct readblock_crap { - unsigned char *sourcebuf; - unsigned char *sourcepos; - unsigned char *sourceend; - int rembits; -}; - - -static int readblock(DUMBFILE *f, readblock_crap * crap) -{ - int32 size; - int c; - - size = dumbfile_igetw(f); - if (size < 0) - return size; - - crap->sourcebuf = malloc(size); - if (!crap->sourcebuf) - return -1; - - c = dumbfile_getnc((char *)crap->sourcebuf, size, f); - if (c < size) { - free(crap->sourcebuf); - crap->sourcebuf = NULL; - return -1; - } - - crap->sourcepos = crap->sourcebuf; - crap->sourceend = crap->sourcebuf + size; - crap->rembits = 8; - return 0; -} - - - -static void freeblock(readblock_crap * crap) -{ - free(crap->sourcebuf); - crap->sourcebuf = NULL; -} - - - -static int readbits(int bitwidth, readblock_crap * crap) -{ - int val = 0; - int b = 0; - - if (crap->sourcepos >= crap->sourceend) return val; - - while (bitwidth > crap->rembits) { - val |= *crap->sourcepos++ << b; - if (crap->sourcepos >= crap->sourceend) return val; - b += crap->rembits; - bitwidth -= crap->rembits; - crap->rembits = 8; - } - - val |= (*crap->sourcepos & ((1 << bitwidth) - 1)) << b; - *crap->sourcepos >>= bitwidth; - crap->rembits -= bitwidth; - - return val; -} - - - -/** WARNING - do we even need to pass `right`? */ -/** WARNING - why bother memsetting at all? The whole array is written... */ -// if we do memset, dumb_silence() would be neater... -static int decompress8(DUMBFILE *f, signed char *data, int len, int it215, int stereo) -{ - int blocklen, blockpos; - byte bitwidth; - word val; - char d1, d2; - readblock_crap crap; - - memset(&crap, 0, sizeof(crap)); - - for (blocklen = 0, blockpos = 0; blocklen < len; blocklen++, blockpos += 1 + stereo) - data[ blockpos ] = 0; - - while (len > 0) { - //Read a block of compressed data: - if (readblock(f, &crap)) - return -1; - //Set up a few variables - blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes - blockpos = 0; - bitwidth = 9; - d1 = d2 = 0; - //Start the decompression: - while (blockpos < blocklen) { - //Read a value: - val = (word)readbits(bitwidth, &crap); - //Check for bit width change: - - if (bitwidth < 7) { //Method 1: - if (val == (1 << (bitwidth - 1))) { - val = (word)readbits(3, &crap) + 1; - bitwidth = (val < bitwidth) ? val : val + 1; - continue; - } - } - else if (bitwidth < 9) { //Method 2 - byte border = (0xFF >> (9 - bitwidth)) - 4; - - if (val > border && val <= (border + 8)) { - val -= border; - bitwidth = (val < bitwidth) ? val : val + 1; - continue; - } - } - else if (bitwidth == 9) { //Method 3 - if (val & 0x100) { - bitwidth = (val + 1) & 0xFF; - continue; - } - } - else { //Illegal width, abort ? - freeblock(&crap); - return -1; - } - - //Expand the value to signed byte: - { - char v; //The sample value: - if (bitwidth < 8) { - byte shift = 8 - bitwidth; - v = (val << shift); - v >>= shift; - } - else - v = (char)val; - - //And integrate the sample value - //(It always has to end with integration doesn't it ? ;-) - d1 += v; - d2 += d1; - } - - //Store ! - /* Version 2.15 was an unofficial version with hacked compression - * code. Yay, better compression :D - */ - *data++ = it215 ? d2 : d1; - data += stereo; - len--; - blockpos++; - } - freeblock(&crap); - } - return 0; -} - - - -static int decompress16(DUMBFILE *f, short *data, int len, int it215, int stereo) -{ - int blocklen, blockpos; - byte bitwidth; - int32 val; - short d1, d2; - readblock_crap crap; - - memset(&crap, 0, sizeof(crap)); - - for ( blocklen = 0, blockpos = 0; blocklen < len; blocklen++, blockpos += 1 + stereo ) - data[ blockpos ] = 0; - - while (len > 0) { - //Read a block of compressed data: - if (readblock(f, &crap)) - return -1; - //Set up a few variables - blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes - blockpos = 0; - bitwidth = 17; - d1 = d2 = 0; - //Start the decompression: - while (blockpos < blocklen) { - val = readbits(bitwidth, &crap); - //Check for bit width change: - - if (bitwidth < 7) { //Method 1: - if (val == (1 << (bitwidth - 1))) { - val = readbits(4, &crap) + 1; - bitwidth = (byte)((val < bitwidth) ? val : val + 1); - continue; - } - } - else if (bitwidth < 17) { //Method 2 - word border = (0xFFFF >> (17 - bitwidth)) - 8; - - if (val > border && val <= (border + 16)) { - val -= border; - bitwidth = (byte)(val < bitwidth ? val : val + 1); - continue; - } - } - else if (bitwidth == 17) { //Method 3 - if (val & 0x10000) { - bitwidth = (byte)((val + 1) & 0xFF); - continue; - } - } - else { //Illegal width, abort ? - freeblock(&crap); - return -1; - } - - //Expand the value to signed byte: - { - short v; //The sample value: - if (bitwidth < 16) { - byte shift = 16 - bitwidth; - v = (short)(val << shift); - v >>= shift; - } - else - v = (short)val; - - //And integrate the sample value - //(It always has to end with integration doesn't it ? ;-) - d1 += v; - d2 += d1; - } - - //Store ! - /* Version 2.15 was an unofficial version with hacked compression - * code. Yay, better compression :D - */ - *data++ = it215 ? d2 : d1; - data += stereo; - len--; - blockpos++; - } - freeblock(&crap); - } - return 0; -} - - - -static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f) -{ - int n; - - envelope->flags = dumbfile_getc(f); - envelope->n_nodes = dumbfile_getc(f); - if(envelope->n_nodes > 25) { - TRACE("IT error: wrong number of envelope nodes (%d)\n", envelope->n_nodes); - envelope->n_nodes = 0; - return -1; - } - envelope->loop_start = dumbfile_getc(f); - envelope->loop_end = dumbfile_getc(f); - envelope->sus_loop_start = dumbfile_getc(f); - envelope->sus_loop_end = dumbfile_getc(f); - for (n = 0; n < envelope->n_nodes; n++) { - envelope->node_y[n] = dumbfile_getc(f); - envelope->node_t[n] = dumbfile_igetw(f); - } - dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1); - - if (envelope->n_nodes <= 0) - envelope->flags &= ~IT_ENVELOPE_ON; - else { - if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; - if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; - } - - return dumbfile_error(f); -} - - - -static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f) -{ - int n; - - /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE) - return -1;*/ - // XXX - dumbfile_skip(f, 4); - - dumbfile_getnc((char *)instrument->filename, 13, f); - instrument->filename[13] = 0; - - instrument->volume_envelope.flags = dumbfile_getc(f); - instrument->volume_envelope.loop_start = dumbfile_getc(f); - instrument->volume_envelope.loop_end = dumbfile_getc(f); - instrument->volume_envelope.sus_loop_start = dumbfile_getc(f); - instrument->volume_envelope.sus_loop_end = dumbfile_getc(f); - - /* Skip two unused bytes. */ - dumbfile_skip(f, 2); - - /* In the old instrument format, fadeout ranges from 0 to 64, and is - * subtracted at intervals from a value starting at 512. In the new - * format, all these values are doubled. Therefore we double when loading - * from the old instrument format - that way we don't have to think about - * it later. - */ - instrument->fadeout = dumbfile_igetw(f) << 1; - instrument->new_note_action = dumbfile_getc(f); - instrument->dup_check_type = dumbfile_getc(f); - instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong! - /** WARNING - what is the duplicate check action for old-style instruments? */ - - /* Skip Tracker Version and Number of Samples. These are only used in - * separate instrument files. Also skip unused byte. - */ - dumbfile_skip(f, 4); - - dumbfile_getnc((char *)instrument->name, 26, f); - instrument->name[26] = 0; - - /* Skip unused bytes following the Instrument Name. */ - dumbfile_skip(f, 6); - - instrument->pp_separation = 0; - instrument->pp_centre = 60; - instrument->global_volume = 128; - /** WARNING - should global_volume be 64 or something? */ - instrument->default_pan = 32; - /** WARNING - should default_pan be 128, meaning don`t use? */ - instrument->random_volume = 0; - instrument->random_pan = 0; - - for (n = 0; n < 120; n++) { - instrument->map_note[n] = dumbfile_getc(f); - instrument->map_sample[n] = dumbfile_getc(f); - } - - /* Skip "Volume envelope (200 bytes)". */ - // - need to know better what this is for though. - dumbfile_skip(f, 200); - -#ifdef INVESTIGATE_OLD_INSTRUMENTS - fprintf(stderr, "Inst %02d Env:", n); -#endif - - for (n = 0; n < 25; n++) - { - instrument->volume_envelope.node_t[n] = dumbfile_getc(f); - instrument->volume_envelope.node_y[n] = dumbfile_getc(f); - -#ifdef INVESTIGATE_OLD_INSTRUMENTS - fprintf(stderr, " %d,%d", - instrument->volume_envelope.node_t[n], - instrument->volume_envelope.node_y[n]); -#endif - - // This loop is unfinished, as we can probably escape from it before - // the end if we want to. Hence the otherwise useless dumbfile_skip() - // call below. - } - dumbfile_skip(f, 50 - (n << 1)); - instrument->volume_envelope.n_nodes = n; - -#ifdef INVESTIGATE_OLD_INSTRUMENTS - fprintf(stderr, "\n"); -#endif - - if (dumbfile_error(f)) - return -1; - - { - IT_ENVELOPE *envelope = &instrument->volume_envelope; - if (envelope->n_nodes <= 0) - envelope->flags &= ~IT_ENVELOPE_ON; - else { - if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; - if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; - } - } - - instrument->filter_cutoff = 127; - instrument->filter_resonance = 0; - - instrument->pan_envelope.flags = 0; - instrument->pitch_envelope.flags = 0; - - return 0; -} - - - -static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen) -{ - int n, len = 0; - - /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE) - return -1;*/ - // XXX - - if (maxlen) len = dumbfile_pos(f); - - dumbfile_skip(f, 4); - - dumbfile_getnc((char *)instrument->filename, 13, f); - instrument->filename[13] = 0; - - instrument->new_note_action = dumbfile_getc(f); - instrument->dup_check_type = dumbfile_getc(f); - instrument->dup_check_action = dumbfile_getc(f); - instrument->fadeout = dumbfile_igetw(f); - instrument->pp_separation = dumbfile_getc(f); - instrument->pp_centre = dumbfile_getc(f); - instrument->global_volume = dumbfile_getc(f); - instrument->default_pan = dumbfile_getc(f); - instrument->random_volume = dumbfile_getc(f); - instrument->random_pan = dumbfile_getc(f); - - /* Skip Tracker Version and Number of Samples. These are only used in - * separate instrument files. Also skip unused byte. - */ - dumbfile_skip(f, 4); - - dumbfile_getnc((char *)instrument->name, 26, f); - instrument->name[26] = 0; - - instrument->filter_cutoff = dumbfile_getc(f); - instrument->filter_resonance = dumbfile_getc(f); - - /* Skip MIDI Channel, Program and Bank. */ - //dumbfile_skip(f, 4); - /*instrument->output = dumbfile_getc(f); - if ( instrument->output > 16 ) { - instrument->output -= 128; - } else { - instrument->output = 0; - } - dumbfile_skip(f, 3);*/ - dumbfile_skip(f, 4); - - for (n = 0; n < 120; n++) { - instrument->map_note[n] = dumbfile_getc(f); - instrument->map_sample[n] = dumbfile_getc(f); - } - - if (dumbfile_error(f)) - return -1; - - if (it_read_envelope(&instrument->volume_envelope, f)) return -1; - if (it_read_envelope(&instrument->pan_envelope, f)) return -1; - if (it_read_envelope(&instrument->pitch_envelope, f)) return -1; - - if (maxlen) { - len = dumbfile_pos(f) - len; - if ( maxlen - len < 124 ) return 0; - } - - if ( dumbfile_mgetl(f) == IT_MPTX_SIGNATURE ) { - for ( n = 0; n < 120; n++ ) { - instrument->map_sample[ n ] += dumbfile_getc( f ) << 8; - } - - if (dumbfile_error(f)) - return -1; - } - - /*if ( dumbfile_mgetl(f) == IT_INSM_SIGNATURE ) { - int32 end = dumbfile_igetl(f); - end += dumbfile_pos(f); - while ( dumbfile_pos(f) < end ) { - int chunkid = dumbfile_igetl(f); - switch ( chunkid ) { - case DUMB_ID('P','L','U','G'): - instrument->output = dumbfile_getc(f); - break; - default: - chunkid = chunkid / 0x100 + dumbfile_getc(f) * 0x1000000; - break; - } - } - - if (dumbfile_error(f)) - return -1; - }*/ - - return 0; -} - - - -static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, int32 *offset, DUMBFILE *f) -{ - /* XXX - if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE) - return -1;*/ - int hax = 0; - int32 s = dumbfile_mgetl(f); - if (s != IT_SAMPLE_SIGNATURE) { - if ( s == ( IT_SAMPLE_SIGNATURE >> 16 ) ) { - s <<= 16; - s |= dumbfile_mgetw(f); - if ( s != IT_SAMPLE_SIGNATURE ) - return -1; - hax = 1; - } - } - - dumbfile_getnc((char *)sample->filename, 13, f); - sample->filename[13] = 0; - - sample->global_volume = dumbfile_getc(f); - sample->flags = dumbfile_getc(f); - sample->default_volume = dumbfile_getc(f); - - dumbfile_getnc((char *)sample->name, 26, f); - sample->name[26] = 0; - - *convert = dumbfile_getc(f); - sample->default_pan = dumbfile_getc(f); - sample->length = dumbfile_igetl(f); - sample->loop_start = dumbfile_igetl(f); - sample->loop_end = dumbfile_igetl(f); - sample->C5_speed = dumbfile_igetl(f); - sample->sus_loop_start = dumbfile_igetl(f); - sample->sus_loop_end = dumbfile_igetl(f); - -#ifdef STEREO_SAMPLES_COUNT_AS_TWO - if (sample->flags & IT_SAMPLE_STEREO) { - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - sample->C5_speed >>= 1; - sample->sus_loop_start >>= 1; - sample->sus_loop_end >>= 1; - } -#endif - - if (sample->flags & IT_SAMPLE_EXISTS) { - if (sample->length <= 0) - sample->flags &= ~IT_SAMPLE_EXISTS; - else { - if ((unsigned int)sample->loop_end > (unsigned int)sample->length) - sample->flags &= ~IT_SAMPLE_LOOP; - else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) - sample->flags &= ~IT_SAMPLE_LOOP; - - if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length) - sample->flags &= ~IT_SAMPLE_SUS_LOOP; - else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end) - sample->flags &= ~IT_SAMPLE_SUS_LOOP; - - /* We may be able to truncate the sample to save memory. */ - if (sample->flags & IT_SAMPLE_LOOP && - *convert != 0xFF) { /* not truncating compressed samples, for now... */ - if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end) - sample->length = sample->sus_loop_end; - else - sample->length = sample->loop_end; - } - } - } - - *offset = dumbfile_igetl(f); - - sample->vibrato_speed = dumbfile_getc(f); - sample->vibrato_depth = dumbfile_getc(f); - if ( ! hax ) { - sample->vibrato_rate = dumbfile_getc(f); - sample->vibrato_waveform = dumbfile_getc(f); - } else { - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; - } - sample->finetune = 0; - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - -int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f) -{ - int32 n, len, delta; - signed char * ptr, * end; - signed char compression_table[16]; - if (dumbfile_getnc((char *)compression_table, 16, f) != 16) - return -1; - ptr = (signed char *) sample->data; - delta = 0; - - end = ptr + sample->length; - len = (sample->length + 1) / 2; - for (n = 0; n < len; n++) { - int b = dumbfile_getc(f); - if (b < 0) return -1; - delta += compression_table[b & 0x0F]; - *ptr++ = (signed char)delta; - if (ptr >= end) break; - delta += compression_table[b >> 4]; - *ptr++ = (signed char)delta; - } - - return 0; -} - - -static int32 it_read_sample_data(IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f) -{ - int32 n; - - int32 datasize = sample->length; - if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1; - - sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); - if (!sample->data) - return -1; - - if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) { - if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) - return -1; - } else if (sample->flags & 8) { - /* If the sample is packed, then we must unpack it. */ - - /* Behavior as defined by greasemonkey's munch.py and observed by XMPlay and OpenMPT */ - - if (sample->flags & IT_SAMPLE_STEREO) { - if (sample->flags & IT_SAMPLE_16BIT) { - decompress16(f, (short *) sample->data, datasize >> 1, convert & 4, 1); - decompress16(f, (short *) sample->data + 1, datasize >> 1, convert & 4, 1); - } else { - decompress8(f, (signed char *) sample->data, datasize >> 1, convert & 4, 1); - decompress8(f, (signed char *) sample->data + 1, datasize >> 1, convert & 4, 1); - } - } else { - if (sample->flags & IT_SAMPLE_16BIT) - decompress16(f, (short *) sample->data, datasize, convert & 4, 0); - else - decompress8(f, (signed char *) sample->data, datasize, convert & 4, 0); - } - } else if (sample->flags & IT_SAMPLE_16BIT) { - if (sample->flags & IT_SAMPLE_STEREO) { - if (convert & 2) { - for (n = 0; n < datasize; n += 2) - ((short *)sample->data)[n] = dumbfile_mgetw(f); - for (n = 1; n < datasize; n += 2) - ((short *)sample->data)[n] = dumbfile_mgetw(f); - } else { - for (n = 0; n < datasize; n += 2) - ((short *)sample->data)[n] = dumbfile_igetw(f); - for (n = 1; n < datasize; n += 2) - ((short *)sample->data)[n] = dumbfile_igetw(f); - } - } else { - if (convert & 2) - for (n = 0; n < datasize; n++) - ((short *)sample->data)[n] = dumbfile_mgetw(f); - else - for (n = 0; n < datasize; n++) - ((short *)sample->data)[n] = dumbfile_igetw(f); - } - } else { - if (sample->flags & IT_SAMPLE_STEREO) { - for (n = 0; n < datasize; n += 2) - ((signed char *)sample->data)[n] = dumbfile_getc(f); - for (n = 1; n < datasize; n += 2) - ((signed char *)sample->data)[n] = dumbfile_getc(f); - } else - for (n = 0; n < datasize; n++) - ((signed char *)sample->data)[n] = dumbfile_getc(f); - } - - if (dumbfile_error(f)) - return -1; - - if (!(convert & 1)) { - /* Convert to signed. */ - if (sample->flags & IT_SAMPLE_16BIT) - for (n = 0; n < datasize; n++) - ((short *)sample->data)[n] ^= 0x8000; - else - for (n = 0; n < datasize; n++) - ((signed char *)sample->data)[n] ^= 0x80; - } - - /* NOT SUPPORTED: - * - * convert & 4 - Samples stored as delta values - * convert & 16 - Samples stored as TX-Wave 12-bit values - * convert & 32 - Left/Right/All Stereo prompt - */ - - return 0; -} - - - -//#define DETECT_DUPLICATE_CHANNELS -#ifdef DETECT_DUPLICATE_CHANNELS -#include -#endif -static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer) -{ - unsigned char cmask[DUMB_IT_N_CHANNELS]; - unsigned char cnote[DUMB_IT_N_CHANNELS]; - unsigned char cinstrument[DUMB_IT_N_CHANNELS]; - unsigned char cvolpan[DUMB_IT_N_CHANNELS]; - unsigned char ceffect[DUMB_IT_N_CHANNELS]; - unsigned char ceffectvalue[DUMB_IT_N_CHANNELS]; -#ifdef DETECT_DUPLICATE_CHANNELS - IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS]; -#endif - - int n_entries = 0; - int buflen; - int bufpos = 0; - - IT_ENTRY *entry; - - unsigned char channel; - unsigned char mask; - - memset(cmask, 0, sizeof(cmask)); - memset(cnote, 0, sizeof(cnote)); - memset(cinstrument, 0, sizeof(cinstrument)); - memset(cvolpan, 0, sizeof(cvolpan)); - memset(ceffect, 0, sizeof(ceffect)); - memset(ceffectvalue, 0, sizeof(ceffectvalue)); -#ifdef DETECT_DUPLICATE_CHANNELS - { - int i; - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL; - } -#endif - - buflen = dumbfile_igetw(f); - pattern->n_rows = dumbfile_igetw(f); - - /* Skip four unused bytes. */ - dumbfile_skip(f, 4); - - if (dumbfile_error(f)) - return -1; - - /* Read in the pattern data. */ - dumbfile_getnc((char *)buffer, buflen, f); - - if (dumbfile_error(f)) - return -1; - - /* Scan the pattern data, and work out how many entries we need room for. */ - while (bufpos < buflen) { - unsigned char b = buffer[bufpos++]; - - if (b == 0) { - /* End of row */ - n_entries++; - continue; - } - - channel = (b - 1) & 63; - - if (b & 128) - cmask[channel] = mask = buffer[bufpos++]; - else - mask = cmask[channel]; - - { - static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5}; - n_entries += (mask != 0); - bufpos += used[mask & 15]; - } - } - - pattern->n_entries = n_entries; - - pattern->entry = malloc(n_entries * sizeof(*pattern->entry)); - - if (!pattern->entry) - return -1; - - bufpos = 0; - memset(cmask, 0, sizeof(cmask)); - - entry = pattern->entry; - - while (bufpos < buflen) { - unsigned char b = buffer[bufpos++]; - - if (b == 0) { - /* End of row */ - IT_SET_END_ROW(entry); - entry++; -#ifdef DETECT_DUPLICATE_CHANNELS - { - int i; - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL; - } -#endif - continue; - } - - channel = (b - 1) & 63; - - if (b & 128) - cmask[channel] = mask = buffer[bufpos++]; - else - mask = cmask[channel]; - - if (mask) { - entry->mask = (mask & 15) | (mask >> 4); - entry->channel = channel; - - if (mask & IT_ENTRY_NOTE) - cnote[channel] = entry->note = buffer[bufpos++]; - else if (mask & (IT_ENTRY_NOTE << 4)) - entry->note = cnote[channel]; - - if (mask & IT_ENTRY_INSTRUMENT) - cinstrument[channel] = entry->instrument = buffer[bufpos++]; - else if (mask & (IT_ENTRY_INSTRUMENT << 4)) - entry->instrument = cinstrument[channel]; - - if (mask & IT_ENTRY_VOLPAN) - cvolpan[channel] = entry->volpan = buffer[bufpos++]; - else if (mask & (IT_ENTRY_VOLPAN << 4)) - entry->volpan = cvolpan[channel]; - - if (mask & IT_ENTRY_EFFECT) { - ceffect[channel] = entry->effect = buffer[bufpos++]; - ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++]; - } else { - entry->effect = ceffect[channel]; - entry->effectvalue = ceffectvalue[channel]; - } - -#ifdef DETECT_DUPLICATE_CHANNELS - if (dupentry[channel]) { - FILE *f = fopen("dupentry.txt", "a"); - if (!f) abort(); - fprintf(f, "Two events on channel %d:", channel); - fprintf(f, " Event #1:"); - if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ..."); - if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ..."); - if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ..."); - if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n"); - fprintf(f, " Event #2:"); - if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ..."); - if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ..."); - if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ..."); - if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n"); - fclose(f); - } - dupentry[channel] = entry; -#endif - - entry++; - } - } - - ASSERT(entry == pattern->entry + n_entries); - - return 0; -} - - - -/* Currently we assume the sample data are stored after the sample headers in - * module files. This assumption may be unjustified; let me know if you have - * trouble. - */ - -#define IT_COMPONENT_SONG_MESSAGE 1 -#define IT_COMPONENT_INSTRUMENT 2 -#define IT_COMPONENT_PATTERN 3 -#define IT_COMPONENT_SAMPLE 4 - -typedef struct IT_COMPONENT -{ - unsigned char type; - unsigned short n; - int32 offset; - short sampfirst; /* component[sampfirst] = first sample data after this */ - short sampnext; /* sampnext is used to create linked lists of sample data */ -} -IT_COMPONENT; - - - -static int CDECL it_component_compare(const void *e1, const void *e2) -{ - return ((const IT_COMPONENT *)e1)->offset - - ((const IT_COMPONENT *)e2)->offset; -} - - - -static sigdata_t *it_load_sigdata(DUMBFILE *f) -{ - DUMB_IT_SIGDATA *sigdata; - - int cwt, cmwt; - int special; - int message_length, message_offset; - - IT_COMPONENT *component; - int n_components = 0; - - unsigned char sample_convert[4096]; - - int n; - - unsigned char *buffer; - - if (dumbfile_mgetl(f) != IT_SIGNATURE) - { - return NULL; - } - - sigdata = malloc(sizeof(*sigdata)); - - if (!sigdata) - { - return NULL; - } - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - dumbfile_getnc((char *)sigdata->name, 26, f); - sigdata->name[26] = 0; - - /* Skip pattern row highlight info. */ - dumbfile_skip(f, 2); - - sigdata->n_orders = dumbfile_igetw(f); - sigdata->n_instruments = dumbfile_igetw(f); - sigdata->n_samples = dumbfile_igetw(f); - sigdata->n_patterns = dumbfile_igetw(f); - - cwt = dumbfile_igetw(f); - cmwt = dumbfile_igetw(f); - - sigdata->flags = dumbfile_igetw(f); - special = dumbfile_igetw(f); - - sigdata->global_volume = dumbfile_getc(f); - sigdata->mixing_volume = dumbfile_getc(f); - sigdata->speed = dumbfile_getc(f); - if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? - sigdata->tempo = dumbfile_getc(f); - sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */ - - /* Skip Pitch Wheel Depth */ - dumbfile_skip(f, 1); - - message_length = dumbfile_igetw(f); - message_offset = dumbfile_igetl(f); - - /* Skip Reserved. */ - dumbfile_skip(f, 4); - - dumbfile_getnc((char *)sigdata->channel_pan, DUMB_IT_N_CHANNELS, f); - dumbfile_getnc((char *)sigdata->channel_volume, DUMB_IT_N_CHANNELS, f); - - // XXX sample count - if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->order = malloc(sigdata->n_orders); - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (sigdata->n_instruments) { - sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); - if (!sigdata->instrument) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - - if (sigdata->n_samples) { - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_samples; n++) - sigdata->sample[n].data = NULL; - } - - if (sigdata->n_patterns) { - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - } - - dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f); - sigdata->restart_position = 0; - - component = malloc(769 * sizeof(*component)); - if (!component) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (special & 1) { - component[n_components].type = IT_COMPONENT_SONG_MESSAGE; - component[n_components].offset = message_offset; - component[n_components].sampfirst = -1; - n_components++; - } - - for (n = 0; n < sigdata->n_instruments; n++) { - component[n_components].type = IT_COMPONENT_INSTRUMENT; - component[n_components].n = n; - component[n_components].offset = dumbfile_igetl(f); - component[n_components].sampfirst = -1; - n_components++; - } - - for (n = 0; n < sigdata->n_samples; n++) { - component[n_components].type = IT_COMPONENT_SAMPLE; - component[n_components].n = n; - component[n_components].offset = dumbfile_igetl(f); - component[n_components].sampfirst = -1; - n_components++; - } - - for (n = 0; n < sigdata->n_patterns; n++) { - int32 offset = dumbfile_igetl(f); - if (offset) { - component[n_components].type = IT_COMPONENT_PATTERN; - component[n_components].n = n; - component[n_components].offset = offset; - component[n_components].sampfirst = -1; - n_components++; - } else { - /* Empty 64-row pattern */ - sigdata->pattern[n].n_rows = 64; - sigdata->pattern[n].n_entries = 0; - } - } - - if (dumbfile_error(f)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - /* - if (!(sigdata->flags & 128) != !(special & 8)) { - fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear"); - fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear"); - fprintf(stderr, "entheh would like to investigate this IT file.\n"); - fprintf(stderr, "Please contact him! entheh@users.sf.net\n"); - } - */ - - if (special & 8) { - /* MIDI configuration is embedded. */ - unsigned char mididata[32]; - int i; - sigdata->midi = malloc(sizeof(*sigdata->midi)); - if (!sigdata->midi) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - // Should we be happy with this outcome in some situations? - } - // What are we skipping? - i = dumbfile_igetw(f); - if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - /* Read embedded MIDI configuration */ - // What are the first 9 commands for? - if (dumbfile_skip(f, 32*9)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < 16; i++) { - unsigned char len = 0; - int j, leftdigit = -1; - if (dumbfile_getnc((char *)mididata, 32, f) < 32) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - sigdata->midi->SFmacroz[i] = 0; - for (j = 0; j < 32; j++) { - if (leftdigit >= 0) { - if (mididata[j] == 0) { - sigdata->midi->SFmacro[i][len++] = leftdigit; - break; - } else if (mididata[j] == ' ') - sigdata->midi->SFmacro[i][len++] = leftdigit; - else if (mididata[j] >= '0' && mididata[j] <= '9') - sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0'); - else if (mididata[j] >= 'A' && mididata[j] <= 'F') - sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA); - leftdigit = -1; - } else if (mididata[j] == 0) - break; - else if (mididata[j] == 'z') - sigdata->midi->SFmacroz[i] |= 1 << len++; - else if (mididata[j] >= '0' && mididata[j] <= '9') - leftdigit = mididata[j] - '0'; - else if (mididata[j] >= 'A' && mididata[j] <= 'F') - leftdigit = mididata[j] - 'A' + 0xA; - } - sigdata->midi->SFmacrolen[i] = len; - } - for (i = 0; i < 128; i++) { - unsigned char len = 0; - int j, leftdigit = -1; - dumbfile_getnc((char *)mididata, 32, f); - for (j = 0; j < 32; j++) { - if (leftdigit >= 0) { - if (mididata[j] == 0) { - sigdata->midi->Zmacro[i][len++] = leftdigit; - break; - } else if (mididata[j] == ' ') - sigdata->midi->Zmacro[i][len++] = leftdigit; - else if (mididata[j] >= '0' && mididata[j] <= '9') - sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0'); - else if (mididata[j] >= 'A' && mididata[j] <= 'F') - sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA); - leftdigit = -1; - } else if (mididata[j] == 0) - break; - else if (mididata[j] >= '0' && mididata[j] <= '9') - leftdigit = mididata[j] - '0'; - else if (mididata[j] >= 'A' && mididata[j] <= 'F') - leftdigit = mididata[j] - 'A' + 0xA; - } - sigdata->midi->Zmacrolen[i] = len; - } - } - - sigdata->flags &= IT_REAL_FLAGS; - - qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare); - - buffer = malloc(65536); - if (!buffer) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (n = 0; n < n_components; n++) { - int32 offset; - int m; - - /* XXX */ - if ( component[n].offset == 0 ) { - switch (component[n].type) { - case IT_COMPONENT_INSTRUMENT: - memset( &sigdata->instrument[component[n].n], 0, sizeof(IT_INSTRUMENT) ); - break; - case IT_COMPONENT_SAMPLE: - memset( &sigdata->sample[component[n].n], 0, sizeof(IT_SAMPLE) ); - break; - case IT_COMPONENT_PATTERN: - { - IT_PATTERN * p = &sigdata->pattern[component[n].n]; - p->entry = 0; - p->n_rows = 64; - p->n_entries = 0; - } - break; - } - continue; - } - - if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - switch (component[n].type) { - - case IT_COMPONENT_SONG_MESSAGE: - if ( n < n_components ) { - message_length = min( message_length, component[n+1].offset - component[n].offset ); - } - sigdata->song_message = malloc(message_length + 1); - if (sigdata->song_message) { - if (dumbfile_getnc((char *)sigdata->song_message, message_length, f) < message_length) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - sigdata->song_message[message_length] = 0; - } - break; - - case IT_COMPONENT_INSTRUMENT: - if (cmwt < 0x200) - m = it_read_old_instrument(&sigdata->instrument[component[n].n], f); - else - m = it_read_instrument(&sigdata->instrument[component[n].n], f, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0); - - if (m) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - break; - - case IT_COMPONENT_PATTERN: - if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - break; - - case IT_COMPONENT_SAMPLE: - if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) { - short *sample; - - for (m = n + 1; m < n_components; m++) - if (component[m].offset > offset) - break; - m--; - - sample = &component[m].sampfirst; - - while (*sample >= 0 && component[*sample].offset <= offset) - sample = &component[*sample].sampnext; - - component[n].sampnext = *sample; - *sample = n; - - component[n].offset = offset; - } - } - - m = component[n].sampfirst; - - while (m >= 0) { - if (dumbfile_seek(f, component[m].offset, DFS_SEEK_SET)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (it_read_sample_data(&sigdata->sample[component[m].n], sample_convert[component[m].n], f)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - m = component[m].sampnext; - } - } - - for ( n = 0; n < 10; n++ ) - { - if ( dumbfile_getc( f ) == 'X' ) - { - if ( dumbfile_getc( f ) == 'T' ) - { - if ( dumbfile_getc( f ) == 'P' ) - { - if ( dumbfile_getc( f ) == 'M' ) - { - break; - } - } - } - } - } - - if ( !dumbfile_error( f ) && n < 10 ) - { - unsigned int mptx_id = dumbfile_igetl( f ); - while ( !dumbfile_error( f ) && mptx_id != DUMB_ID('M','P','T','S') ) - { - unsigned int size = dumbfile_igetw( f ); - switch (mptx_id) - { - /* TODO: Add instrument extension readers */ - - default: - dumbfile_skip(f, size * sigdata->n_instruments); - break; - } - - mptx_id = dumbfile_igetl( f ); - } - - mptx_id = dumbfile_igetl( f ); - while ( !dumbfile_error(f) && dumbfile_pos(f) < dumbfile_get_size(f) ) - { - unsigned int size = dumbfile_igetw( f ); - switch (mptx_id) - { - /* TODO: Add more song extension readers */ - - case DUMB_ID('D','T','.','.'): - if ( size == 2 ) - sigdata->tempo = dumbfile_igetw( f ); - else if ( size == 4 ) - sigdata->tempo = dumbfile_igetl( f ); - break; - - default: - dumbfile_skip(f, size); - break; - } - mptx_id = dumbfile_igetl( f ); - } - } - - free(buffer); - free(component); - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - - - -DUH *DUMBEXPORT dumb_read_it_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_load_sigdata(f); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "IT"; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/itread2.c b/libraries/dumb/src/it/itread2.c deleted file mode 100644 index 718565729..000000000 --- a/libraries/dumb/src/it/itread2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itread2.c - Function to read an Impulse Tracker / / \ \ - * module from an open file and do an | < / \_ - * initial run-through. | \/ /\ / - * \_ / > / - * Split off from itread.c by entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_it(DUMBFILE *f) -{ - DUH *duh = dumb_read_it_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/itrender.c b/libraries/dumb/src/it/itrender.c deleted file mode 100644 index f9dc268e5..000000000 --- a/libraries/dumb/src/it/itrender.c +++ /dev/null @@ -1,5961 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itrender.c - Code to render an Impulse Tracker / / \ \ - * module. | < / \_ - * | \/ /\ / - * Written - painstakingly - by entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/dumb.h" -#include "internal/it.h" -#include "internal/lpc.h" - -#include "internal/resampler.h" -#include "internal/mulsc.h" - -// #define BIT_ARRAY_BULLSHIT - -static IT_PLAYING *new_playing(DUMB_IT_SIGRENDERER *itsr) -{ - IT_PLAYING *r; - - if (itsr->free_playing != NULL) - { - r = itsr->free_playing; - itsr->free_playing = r->next; - return r; - } - r = (IT_PLAYING *)malloc(sizeof(IT_PLAYING)); - if (r) - { - r->resampler.fir_resampler_ratio = 0.0; - r->resampler.fir_resampler[0] = resampler_create(); - if ( !r->resampler.fir_resampler[0] ) { - free( r ); - return NULL; - } - r->resampler.fir_resampler[1] = resampler_create(); - if ( !r->resampler.fir_resampler[1] ) { - resampler_delete( r->resampler.fir_resampler[0] ); - free( r ); - return NULL; - } - } - return r; -} - -static void free_playing(DUMB_IT_SIGRENDERER *itsr, IT_PLAYING *playing) -{ - playing->next = itsr->free_playing; - itsr->free_playing = playing; -} - -static void free_playing_orig(IT_PLAYING * r) -{ - resampler_delete( r->resampler.fir_resampler[1] ); - resampler_delete( r->resampler.fir_resampler[0] ); - free( r ); -} - -static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel) -{ - IT_PLAYING *dst; - - if (!src) return NULL; - - dst = malloc(sizeof(*dst)); - if (!dst) return NULL; - - dst->flags = src->flags; - dst->resampling_quality = src->resampling_quality; - - ASSERT(src->channel); - dst->channel = &dstchannel[src->channel - srcchannel]; - dst->sample = src->sample; - dst->instrument = src->instrument; - dst->env_instrument = src->env_instrument; - - dst->sampnum = src->sampnum; - dst->instnum = src->instnum; - - dst->declick_stage = src->declick_stage; - - dst->float_volume[0] = src->float_volume[0]; - dst->float_volume[1] = src->float_volume[1]; - - dst->ramp_volume[0] = src->ramp_volume[0]; - dst->ramp_volume[1] = src->ramp_volume[1]; - - dst->ramp_delta[0] = src->ramp_delta[0]; - dst->ramp_delta[1] = src->ramp_delta[1]; - - dst->channel_volume = src->channel_volume; - - dst->volume = src->volume; - dst->pan = src->pan; - - dst->volume_offset = src->volume_offset; - dst->panning_offset = src->panning_offset; - - dst->note = src->note; - - dst->enabled_envelopes = src->enabled_envelopes; - - dst->filter_cutoff = src->filter_cutoff; - dst->filter_resonance = src->filter_resonance; - - dst->true_filter_cutoff = src->true_filter_cutoff; - dst->true_filter_resonance = src->true_filter_resonance; - - dst->vibrato_speed = src->vibrato_speed; - dst->vibrato_depth = src->vibrato_depth; - dst->vibrato_n = src->vibrato_n; - dst->vibrato_time = src->vibrato_time; - dst->vibrato_waveform = src->vibrato_waveform; - - dst->tremolo_speed = src->tremolo_speed; - dst->tremolo_depth = src->tremolo_depth; - dst->tremolo_time = src->tremolo_time; - dst->tremolo_waveform = src->tremolo_waveform; - - dst->panbrello_speed = src->panbrello_speed; - dst->panbrello_depth = src->panbrello_depth; - dst->panbrello_time = src->panbrello_time; - dst->panbrello_waveform = src->panbrello_waveform; - dst->panbrello_random = src->panbrello_random; - - dst->sample_vibrato_time = src->sample_vibrato_time; - dst->sample_vibrato_waveform = src->sample_vibrato_waveform; - dst->sample_vibrato_depth = src->sample_vibrato_depth; - - dst->slide = src->slide; - dst->delta = src->delta; - dst->finetune = src->finetune; - - dst->volume_envelope = src->volume_envelope; - dst->pan_envelope = src->pan_envelope; - dst->pitch_envelope = src->pitch_envelope; - - dst->fadeoutcount = src->fadeoutcount; - - dst->filter_state[0] = src->filter_state[0]; - dst->filter_state[1] = src->filter_state[1]; - - dst->resampler = src->resampler; - dst->resampler.pickup_data = dst; - dst->resampler.fir_resampler_ratio = src->resampler.fir_resampler_ratio; - dst->resampler.fir_resampler[0] = resampler_dup( src->resampler.fir_resampler[0] ); - if ( !dst->resampler.fir_resampler[0] ) { - free( dst ); - return NULL; - } - dst->resampler.fir_resampler[1] = resampler_dup( src->resampler.fir_resampler[1] ); - if ( !dst->resampler.fir_resampler[1] ) { - resampler_delete( dst->resampler.fir_resampler[0] ); - free( dst ); - return NULL; - } - dst->time_lost = src->time_lost; - - //dst->output = src->output; - - return dst; -} - - - -static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src) -{ - dst->flags = src->flags; - - dst->volume = src->volume; - dst->volslide = src->volslide; - dst->xm_volslide = src->xm_volslide; - dst->panslide = src->panslide; - - dst->pan = src->pan; - dst->truepan = src->truepan; - - dst->channelvolume = src->channelvolume; - dst->channelvolslide = src->channelvolslide; - - dst->instrument = src->instrument; - dst->note = src->note; - - dst->SFmacro = src->SFmacro; - - dst->filter_cutoff = src->filter_cutoff; - dst->filter_resonance = src->filter_resonance; - - dst->key_off_count = src->key_off_count; - dst->note_cut_count = src->note_cut_count; - dst->note_delay_count = src->note_delay_count; - dst->note_delay_entry = src->note_delay_entry; - - dst->new_note_action = src->new_note_action; - - dst->arpeggio_table = src->arpeggio_table; - memcpy(dst->arpeggio_offsets, src->arpeggio_offsets, sizeof(dst->arpeggio_offsets)); - dst->retrig = src->retrig; - dst->xm_retrig = src->xm_retrig; - dst->retrig_tick = src->retrig_tick; - - dst->tremor_time = src->tremor_time; - - dst->vibrato_waveform = src->vibrato_waveform; - dst->tremolo_waveform = src->tremolo_waveform; - dst->panbrello_waveform = src->panbrello_waveform; - - dst->portamento = src->portamento; - dst->toneporta = src->toneporta; - dst->toneslide = src->toneslide; - dst->toneslide_tick = src->toneslide_tick; - dst->last_toneslide_tick = src->last_toneslide_tick; - dst->ptm_toneslide = src->ptm_toneslide; - dst->ptm_last_toneslide = src->ptm_last_toneslide; - dst->okt_toneslide = src->okt_toneslide; - dst->destnote = src->destnote; - - dst->glissando = src->glissando; - - dst->sample = src->sample; - dst->truenote = src->truenote; - - dst->midi_state = src->midi_state; - - dst->lastvolslide = src->lastvolslide; - dst->lastDKL = src->lastDKL; - dst->lastEF = src->lastEF; - dst->lastG = src->lastG; - dst->lastHspeed = src->lastHspeed; - dst->lastHdepth = src->lastHdepth; - dst->lastRspeed = src->lastRspeed; - dst->lastRdepth = src->lastRdepth; - dst->lastYspeed = src->lastYspeed; - dst->lastYdepth = src->lastYdepth; - dst->lastI = src->lastI; - dst->lastJ = src->lastJ; - dst->lastN = src->lastN; - dst->lastO = src->lastO; - dst->high_offset = src->high_offset; - dst->lastP = src->lastP; - dst->lastQ = src->lastQ; - dst->lastS = src->lastS; - dst->pat_loop_row = src->pat_loop_row; - dst->pat_loop_count = src->pat_loop_count; - dst->pat_loop_end_row = src->pat_loop_end_row; - dst->lastW = src->lastW; - - dst->xm_lastE1 = src->xm_lastE1; - dst->xm_lastE2 = src->xm_lastE2; - dst->xm_lastEA = src->xm_lastEA; - dst->xm_lastEB = src->xm_lastEB; - dst->xm_lastX1 = src->xm_lastX1; - dst->xm_lastX2 = src->xm_lastX2; - - dst->inv_loop_delay = src->inv_loop_delay; - dst->inv_loop_speed = src->inv_loop_speed; - dst->inv_loop_offset = src->inv_loop_offset; - - dst->playing = dup_playing(src->playing, dst, src); - -#ifdef BIT_ARRAY_BULLSHIT - dst->played_patjump = bit_array_dup(src->played_patjump); - dst->played_patjump_order = src->played_patjump_order; -#endif - - //dst->output = src->output; -} - - - -/* Allocate the new callbacks first, then pass them to this function! - * It will free them on failure. - */ -static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_channels, IT_CALLBACKS *callbacks) -{ - DUMB_IT_SIGRENDERER *dst; - int i; - - if (!src) { - if (callbacks) free(callbacks); - return NULL; - } - - dst = malloc(sizeof(*dst)); - if (!dst) { - if (callbacks) free(callbacks); - return NULL; - } - - dst->free_playing = NULL; - dst->sigdata = src->sigdata; - - dst->n_channels = n_channels; - - dst->resampling_quality = src->resampling_quality; - - dst->globalvolume = src->globalvolume; - dst->globalvolslide = src->globalvolslide; - - dst->tempo = src->tempo; - dst->temposlide = src->temposlide; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) - dup_channel(&dst->channel[i], &src->channel[i]); - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - dst->playing[i] = dup_playing(src->playing[i], dst->channel, src->channel); - - dst->tick = src->tick; - dst->speed = src->speed; - dst->rowcount = src->rowcount; - - dst->order = src->order; - dst->row = src->row; - dst->processorder = src->processorder; - dst->processrow = src->processrow; - dst->breakrow = src->breakrow; - - dst->restart_position = src->restart_position; - - dst->n_rows = src->n_rows; - - dst->entry_start = src->entry_start; - dst->entry = src->entry; - dst->entry_end = src->entry_end; - - dst->time_left = src->time_left; - dst->sub_time_left = src->sub_time_left; - - dst->ramp_style = src->ramp_style; - - dst->click_remover = NULL; - - dst->callbacks = callbacks; - -#ifdef BIT_ARRAY_BULLSHIT - dst->played = bit_array_dup(src->played); -#endif - - dst->gvz_time = src->gvz_time; - dst->gvz_sub_time = src->gvz_sub_time; - - //dst->max_output = src->max_output; - - return dst; -} - - - -static const IT_MIDI default_midi = { - /* unsigned char SFmacro[16][16]; */ - { - {0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }, - /* unsigned char SFmacrolen[16]; */ - {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - /* unsigned short SFmacroz[16]; */ - /* Bitfield; bit 0 set = z in first position */ - { - 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 - }, - /* unsigned char Zmacro[128][16]; */ - { - {0xF0, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xF0, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }, - /* unsigned char Zmacrolen[128]; */ - { - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - } -}; - - - -static void it_reset_filter_state(IT_FILTER_STATE *state) -{ - state->currsample = 0; - state->prevsample = 0; -} - - - -#define LOG10 2.30258509299 - -/* IMPORTANT: This function expects one extra sample in 'src' so it can apply - * click removal. It reads size samples, starting from src[0], and writes its - * output starting at dst[pos]. The pos parameter is required for getting - * click removal right. - */ - -static void it_filter_int(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance) -{ - sample_t currsample = state->currsample; - sample_t prevsample = state->prevsample; - - float a, b, c; - - int32 datasize; - - { - float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24< 2.0f) d = 2.0f; - d = (loss - d) * inv_angle; - e = inv_angle * inv_angle; - a = 1.0f / (1.0f + d + e); - c = -e * a; - b = 1.0f - a - c; -#else - a = 1.0f / (inv_angle*inv_angle + inv_angle*loss + loss); - c = -(inv_angle*inv_angle) * a; - b = 1.0f - a - c; -#endif - } - - dst += pos * step; - datasize = size * step; - -#define INT_FILTERS -#ifdef INT_FILTERS -#define SCALEB 12 - { - int ai = (int)(a * (1 << (16+SCALEB))); - int bi = (int)(b * (1 << (16+SCALEB))); - int ci = (int)(c * (1 << (16+SCALEB))); - int i; - - if (cr) { - sample_t startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); - dumb_record_click(cr, pos, startstep); - } - - for (i = 0; i < datasize; i += step) { - { - sample_t newsample = MULSCA(src[i], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); - prevsample = currsample; - currsample = newsample; - } - dst[i] += currsample; - } - - if (cr) { - sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); - dumb_record_click(cr, pos + size, -endstep); - } - } -#else -#error This version is broken - it does not use step, and state should contain floats for it - if (cr) { - float startstep = src[0]*a + currsample*b + prevsample*c; - dumb_record_click(cr, pos, (sample_t)startstep); - } - - { - int i = size % 3; - while (i > 0) { - { - float newsample = *src++*a + currsample*b + prevsample*c; - prevsample = currsample; - currsample = newsample; - } - *dst++ += (sample_t)currsample; - i--; - } - i = size / 3; - while (i > 0) { - float newsample; - /* Gotta love unrolled loops! */ - *dst++ += (sample_t)(newsample = *src++*a + currsample*b + prevsample*c); - *dst++ += (sample_t)(prevsample = *src++*a + newsample*b + currsample*c); - *dst++ += (sample_t)(currsample = *src++*a + prevsample*b + newsample*c); - i--; - } - } - - if (cr) { - float endstep = src[datasize]*a + currsample*b + prevsample*c; - dumb_record_click(cr, pos + size, -(sample_t)endstep); - } -#endif - - state->currsample = currsample; - state->prevsample = prevsample; -} - -#if defined(_USE_SSE) && (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) -#include - -static void it_filter_sse(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int step, int sampfreq, int cutoff, int resonance) -{ - __m128 data, impulse; - __m128 temp1, temp2; - - sample_t currsample = state->currsample; - sample_t prevsample = state->prevsample; - - float imp[4]; - - //profiler( filter_sse ); On ClawHammer Athlon64 3200+, ~12000 cycles, ~500 for that x87 setup code (as opposed to ~25500 for the original integer code) - - long datasize; - - { - float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24< 2.0f) d = 2.0f; - d = (loss - d) * inv_angle; - e = inv_angle * inv_angle; - imp[0] = 1.0f / (1.0f + d + e); - imp[2] = -e * imp[0]; - imp[1] = 1.0f - imp[0] - imp[2]; -#else - imp[0] = 1.0f / (inv_angle*inv_angle + inv_angle*loss + loss); - imp[2] = -(inv_angle*inv_angle) * imp[0]; - imp[1] = 1.0f - imp[0] - imp[2]; -#endif - imp[3] = 0.0f; - } - - dst += pos * step; - datasize = size * step; - - { - int ai, bi, ci, i; - - if (cr) { - sample_t startstep; - ai = (int)(imp[0] * (1 << (16+SCALEB))); - bi = (int)(imp[1] * (1 << (16+SCALEB))); - ci = (int)(imp[2] * (1 << (16+SCALEB))); - startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); - dumb_record_click(cr, pos, startstep); - } - - temp1 = _mm_setzero_ps(); - data = _mm_cvtsi32_ss( temp1, currsample ); - temp2 = _mm_cvtsi32_ss( temp1, prevsample ); - impulse = _mm_loadu_ps( (const float *) &imp ); - data = _mm_shuffle_ps( data, temp2, _MM_SHUFFLE(1, 0, 0, 1) ); - - for (i = 0; i < datasize; i += step) { - temp1 = _mm_cvtsi32_ss( data, src [i] ); - temp1 = _mm_mul_ps( temp1, impulse ); - temp2 = _mm_movehl_ps( temp2, temp1 ); - temp1 = _mm_add_ps( temp1, temp2 ); - temp2 = temp1; - temp2 = _mm_shuffle_ps( temp2, temp1, _MM_SHUFFLE(0, 0, 0, 1) ); - temp1 = _mm_add_ps( temp1, temp2 ); - temp1 = _mm_shuffle_ps( temp1, data, _MM_SHUFFLE(2, 1, 0, 0) ); - data = temp1; - dst [i] += _mm_cvtss_si32( temp1 ); - } - - currsample = _mm_cvtss_si32( temp1 ); - temp1 = _mm_shuffle_ps( temp1, data, _MM_SHUFFLE(0, 0, 0, 2) ); - prevsample = _mm_cvtss_si32( temp1 ); - - if (cr) { - sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); - dumb_record_click(cr, pos + size, -endstep); - } - } - - state->currsample = currsample; - state->prevsample = prevsample; -} -#endif - -#undef LOG10 - -#ifdef _USE_SSE -#if defined(_M_IX86) || defined(__i386__) - -#ifdef _MSC_VER -#include -#elif defined(__clang__) || defined(__GNUC__) -static inline void -__cpuid(int *data, int selector) -{ -#if defined(__PIC__) && defined(__i386__) - asm("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi" - : "=a" (data[0]), - "=S" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "0" (selector)); -#elif defined(__PIC__) && defined(__amd64__) - asm("xchg{q} {%%}rbx, %q1; cpuid; xchg{q} {%%}rbx, %q1" - : "=a" (data[0]), - "=&r" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "0" (selector)); -#else - asm("cpuid" - : "=a" (data[0]), - "=b" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "a"(selector)); -#endif -} -#else -#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4) -#endif - -static int query_cpu_feature_sse() { - int buffer[4]; - __cpuid(buffer,1); - if ((buffer[3]&(1<<25)) == 0) return 0; - return 1; -} - -static int _dumb_it_use_sse = 0; - -void _dumb_init_sse() -{ - static int initialized = 0; - if (!initialized) - { - _dumb_it_use_sse = query_cpu_feature_sse(); - initialized = 1; - } -} - -#elif defined(_M_X64) || defined(__amd64__) - -static const int _dumb_it_use_sse = 1; - -void _dumb_init_sse() { } - -#else - -static const int _dumb_it_use_sse = 0; - -void _dumb_init_sse() { } - -#endif -#endif - -static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, int32 pos, sample_t *src, int32 size, int step, int sampfreq, int cutoff, int resonance) -{ -#if defined(_USE_SSE) && (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) - _dumb_init_sse(); - if ( _dumb_it_use_sse ) it_filter_sse( cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance ); - else -#endif - it_filter_int( cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance ); -} - - - -static const signed char it_sine[256] = { - 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, - 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, - 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, - 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, - 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, - 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2, - 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23, - -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, - -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, - -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, - -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, - -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, - -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2 -}; - - - -#if 1 -/** WARNING: use these! */ -/** JULIEN: Plus for XM compatibility it could be interesting to rename - * it_sawtooth[] to it_rampdown[], and add an it_rampup[]. - * Also, still for XM compat', twood be good if it was possible to tell the - * the player not to retrig' the waveform on a new instrument. - * Both of these are only for completness though, as I don't think it would - * be very noticeable ;) - */ -/** ENTHEH: IT also has the 'don't retrig' thingy :) */ -static const signed char it_sawtooth[256] = { - 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56, - 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, - 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, - 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32, - 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, - 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16, - 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, - 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, - 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8, - -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16, - -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24, - -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32, - -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40, - -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48, - -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56, - -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64 -}; - -static const signed char it_squarewave[256] = { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const signed char it_xm_ramp[256] = { - 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8, - -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16, - -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24, - -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32, - -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40, - -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48, - -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56, - -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64, - 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56, - 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, - 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, - 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32, - 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, - 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16, - 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, - 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0 -}; - -static const signed char it_xm_squarewave[256] = { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64 -}; - -#endif - - - -static void reset_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer) -{ - int i; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - IT_CHANNEL *channel = &sigrenderer->channel[i]; - channel->key_off_count = 0; - channel->note_cut_count = 0; - channel->note_delay_count = 0; - } -} - - - -static const unsigned char arpeggio_mod[32] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1}; -static const unsigned char arpeggio_xm[32] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; -static const unsigned char arpeggio_okt_3[32] = {1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0}; -static const unsigned char arpeggio_okt_4[32] = {0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1}; -static const unsigned char arpeggio_okt_5[32] = {2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2}; - - - -static void reset_channel_effects(IT_CHANNEL *channel) -{ - channel->volslide = 0; - channel->xm_volslide = 0; - channel->panslide = 0; - channel->channelvolslide = 0; - channel->arpeggio_table = (const unsigned char *) &arpeggio_mod; - memset(channel->arpeggio_offsets, 0, sizeof(channel->arpeggio_offsets)); - channel->retrig = 0; - if (channel->xm_retrig) { - channel->xm_retrig = 0; - channel->retrig_tick = 0; - } - channel->tremor_time &= 127; - channel->portamento = 0; - channel->toneporta = 0; - if (channel->ptm_toneslide) { - channel->ptm_last_toneslide = channel->ptm_toneslide; - channel->last_toneslide_tick = channel->toneslide_tick; - } else - channel->ptm_last_toneslide = 0; - channel->ptm_toneslide = 0; - channel->toneslide_tick = 0; - channel->okt_toneslide = 0; - if (channel->playing) { - channel->playing->vibrato_n = 0; - channel->playing->tremolo_speed = 0; - channel->playing->tremolo_depth = 0; - channel->playing->panbrello_speed = 0; - } -} - -static void reset_effects(DUMB_IT_SIGRENDERER *sigrenderer) -{ - int i; - - sigrenderer->globalvolslide = 0; - sigrenderer->temposlide = 0; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - reset_channel_effects(&sigrenderer->channel[i]); - } -} - - - -static void update_tremor(IT_CHANNEL *channel) -{ - if ((channel->tremor_time & 128) && channel->playing) { - if (channel->tremor_time == 128) - channel->tremor_time = (channel->lastI >> 4) | 192; - else if (channel->tremor_time == 192) - channel->tremor_time = (channel->lastI & 15) | 128; - else - channel->tremor_time--; - } -} - - - -static void it_pickup_loop(DUMB_RESAMPLER *resampler, void *data) -{ - resampler->pos -= resampler->end - resampler->start; - ((IT_PLAYING *)data)->time_lost += resampler->end - resampler->start; -} - - - -static void it_pickup_pingpong_loop(DUMB_RESAMPLER *resampler, void *data) -{ - if (resampler->dir < 0) { - resampler->pos = (resampler->start << 1) - 1 - resampler->pos; - resampler->subpos ^= 65535; - resampler->dir = 1; - ((IT_PLAYING *)data)->time_lost += (resampler->end - resampler->start) << 1; - } else { - resampler->pos = (resampler->end << 1) - 1 - resampler->pos; - resampler->subpos ^= 65535; - resampler->dir = -1; - } -} - - - -static void it_pickup_stop_at_end(DUMB_RESAMPLER *resampler, void *data) -{ - (void)data; - - if (resampler->dir < 0) { - resampler->pos = (resampler->start << 1) - 1 - resampler->pos; - resampler->subpos ^= 65535; - /* By rights, time_lost would be updated here. However, there is no - * need at this point; it will not be used. - * - * ((IT_PLAYING *)data)->time_lost += (resampler->src_end - resampler->src_start) << 1; - */ - resampler->dir = 1; - } else - resampler->dir = 0; -} - - - -static void it_pickup_stop_after_reverse(DUMB_RESAMPLER *resampler, void *data) -{ - (void)data; - - resampler->dir = 0; -} - - - -static void it_playing_update_resamplers(IT_PLAYING *playing) -{ - if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { - playing->resampler.start = playing->sample->sus_loop_start; - playing->resampler.end = playing->sample->sus_loop_end; - if (playing->resampler.start == playing->resampler.end) - playing->resampler.pickup = &it_pickup_stop_at_end; - else if (playing->sample->flags & IT_SAMPLE_PINGPONG_SUS_LOOP) - playing->resampler.pickup = &it_pickup_pingpong_loop; - else - playing->resampler.pickup = &it_pickup_loop; - } else if (playing->sample->flags & IT_SAMPLE_LOOP) { - playing->resampler.start = playing->sample->loop_start; - playing->resampler.end = playing->sample->loop_end; - if (playing->resampler.start == playing->resampler.end) - playing->resampler.pickup = &it_pickup_stop_at_end; - else if (playing->sample->flags & IT_SAMPLE_PINGPONG_LOOP) - playing->resampler.pickup = &it_pickup_pingpong_loop; - else - playing->resampler.pickup = &it_pickup_loop; - } else if (playing->flags & IT_PLAYING_REVERSE) { - playing->resampler.start = 0; - playing->resampler.end = playing->sample->length; - playing->resampler.dir = -1; - playing->resampler.pickup = &it_pickup_stop_after_reverse; - } else { - if (playing->sample->flags & IT_SAMPLE_SUS_LOOP) - playing->resampler.start = playing->sample->sus_loop_start; - else - playing->resampler.start = 0; - playing->resampler.end = playing->sample->length; - playing->resampler.pickup = &it_pickup_stop_at_end; - } - ASSERT(playing->resampler.pickup_data == playing); -} - - - -/* This should be called whenever the sample or sample position changes. */ -static void it_playing_reset_resamplers(IT_PLAYING *playing, int32 pos) -{ - int bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8; - int quality = playing->resampling_quality; - int channels = playing->sample->flags & IT_SAMPLE_STEREO ? 2 : 1; - if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality) - quality = playing->sample->max_resampling_quality; - dumb_reset_resampler_n(bits, &playing->resampler, playing->sample->data, channels, pos, 0, 0, quality); - playing->resampler.pickup_data = playing; - playing->time_lost = 0; - playing->flags &= ~IT_PLAYING_DEAD; - it_playing_update_resamplers(playing); -} - -static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel); - -/* Should we only be retriggering short samples on XM? */ - -static void update_retrig(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel) -{ - if (channel->xm_retrig) { - channel->retrig_tick--; - if (channel->retrig_tick <= 0) { - if (channel->playing) { - it_playing_reset_resamplers(channel->playing, 0); - channel->playing->declick_stage = 0; - } else if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) it_retrigger_note(sigrenderer, channel); - channel->retrig_tick = channel->xm_retrig; - } - } else if (channel->retrig & 0x0F) { - channel->retrig_tick--; - if (channel->retrig_tick <= 0) { - if (channel->retrig < 0x10) { - } else if (channel->retrig < 0x20) { - channel->volume--; - if (channel->volume > 64) channel->volume = 0; - } else if (channel->retrig < 0x30) { - channel->volume -= 2; - if (channel->volume > 64) channel->volume = 0; - } else if (channel->retrig < 0x40) { - channel->volume -= 4; - if (channel->volume > 64) channel->volume = 0; - } else if (channel->retrig < 0x50) { - channel->volume -= 8; - if (channel->volume > 64) channel->volume = 0; - } else if (channel->retrig < 0x60) { - channel->volume -= 16; - if (channel->volume > 64) channel->volume = 0; - } else if (channel->retrig < 0x70) { - channel->volume <<= 1; - channel->volume /= 3; - } else if (channel->retrig < 0x80) { - channel->volume >>= 1; - } else if (channel->retrig < 0x90) { - } else if (channel->retrig < 0xA0) { - channel->volume++; - if (channel->volume > 64) channel->volume = 64; - } else if (channel->retrig < 0xB0) { - channel->volume += 2; - if (channel->volume > 64) channel->volume = 64; - } else if (channel->retrig < 0xC0) { - channel->volume += 4; - if (channel->volume > 64) channel->volume = 64; - } else if (channel->retrig < 0xD0) { - channel->volume += 8; - if (channel->volume > 64) channel->volume = 64; - } else if (channel->retrig < 0xE0) { - channel->volume += 16; - if (channel->volume > 64) channel->volume = 64; - } else if (channel->retrig < 0xF0) { - channel->volume *= 3; - channel->volume >>= 1; - if (channel->volume > 64) channel->volume = 64; - } else { - channel->volume <<= 1; - if (channel->volume > 64) channel->volume = 64; - } - if (channel->playing) { - it_playing_reset_resamplers(channel->playing, 0); - channel->playing->declick_stage = 0; - } else if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) it_retrigger_note(sigrenderer, channel); - channel->retrig_tick = channel->retrig & 0x0F; - } - } -} - - -static void update_smooth_effects_playing(IT_PLAYING *playing) -{ - playing->vibrato_time += playing->vibrato_n * - (playing->vibrato_speed << 2); - playing->tremolo_time += playing->tremolo_speed << 2; - playing->panbrello_time += playing->panbrello_speed; - if (playing->panbrello_waveform == 3) - playing->panbrello_random = (rand() % 129) - 64; -} - -static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer) -{ - int i; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - IT_CHANNEL *channel = &sigrenderer->channel[i]; - IT_PLAYING *playing = channel->playing; - - if (playing) { - update_smooth_effects_playing(playing); - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - IT_PLAYING *playing = sigrenderer->playing[i]; - - if (playing) { - update_smooth_effects_playing(playing); - } - } -} - - -static const unsigned char pt_tab_invloop[16] = -{ - 0x00, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, - 0x0F, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80 -}; - -static void update_invert_loop(IT_CHANNEL *channel, IT_SAMPLE *sample) -{ - channel->inv_loop_delay += pt_tab_invloop[channel->inv_loop_speed]; - if (channel->inv_loop_delay >= 0x80) - { - channel->inv_loop_delay = 0; - - if (sample && ((sample->flags & (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) == (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) && !(sample->flags & (IT_SAMPLE_STEREO | IT_SAMPLE_16BIT))) - { - if (sample->loop_end - sample->loop_start >= 4) - { - channel->inv_loop_offset++; - if (channel->inv_loop_offset >= (sample->loop_end - sample->loop_start)) channel->inv_loop_offset = 0; - - ((char *)sample->data)[sample->loop_start + channel->inv_loop_offset] ^= 0xFF; - } - } - } -} - - -static void update_playing_effects(IT_PLAYING *playing) -{ - IT_CHANNEL *channel = playing->channel; - - if (channel->channelvolslide) { - playing->channel_volume = channel->channelvolume; - } - - if (channel->okt_toneslide) { - if (channel->okt_toneslide--) { - playing->note += channel->toneslide; - if (playing->note >= 120) { - if (channel->toneslide < 0) playing->note = 0; - else playing->note = 119; - } - } - } else if (channel->ptm_toneslide) { - if (--channel->toneslide_tick == 0) { - channel->toneslide_tick = channel->ptm_toneslide; - if (playing) { - playing->note += channel->toneslide; - if (playing->note >= 120) { - if (channel->toneslide < 0) playing->note = 0; - else playing->note = 119; - } - if (channel->playing == playing) { - channel->note = channel->truenote = playing->note; - } - if (channel->toneslide_retrig) { - it_playing_reset_resamplers(playing, 0); - playing->declick_stage = 0; - } - } - } - } -} - - -static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) -{ - int i; - - if (sigrenderer->globalvolslide) { - sigrenderer->globalvolume += sigrenderer->globalvolslide; - if (sigrenderer->globalvolume > 128) { - if (sigrenderer->globalvolslide >= 0) - sigrenderer->globalvolume = 128; - else - sigrenderer->globalvolume = 0; - } - } - - if (sigrenderer->temposlide) { - sigrenderer->tempo += sigrenderer->temposlide; - if (sigrenderer->tempo < 32) { - if (sigrenderer->temposlide >= 0) - sigrenderer->tempo = 255; - else - sigrenderer->tempo = 32; - } - } - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - IT_CHANNEL *channel = &sigrenderer->channel[i]; - IT_PLAYING *playing = channel->playing; - - if (channel->xm_volslide) { - channel->volume += channel->xm_volslide; - if (channel->volume > 64) { - if (channel->xm_volslide >= 0) - channel->volume = 64; - else - channel->volume = 0; - } - } - - if (channel->volslide) { - int clip = (sigrenderer->sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64; - channel->volume += channel->volslide; - if (channel->volume > clip) { - if (channel->volslide >= 0) - channel->volume = clip; - else - channel->volume = 0; - } - } - - if (channel->panslide) { - if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) { - if (IT_IS_SURROUND(channel->pan)) - { - channel->pan = 32; - channel->truepan = 32 + 128 * 64; - } - if (channel->panslide == -128) - channel->truepan = 32; - else - channel->truepan = MID(32, channel->truepan + channel->panslide*64, 32+255*64); - } else { - if (IT_IS_SURROUND(channel->pan)) - { - channel->pan = 32; - } - channel->pan += channel->panslide; - if (channel->pan > 64) { - if (channel->panslide >= 0) - channel->pan = 64; - else - channel->pan = 0; - } - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - } - } - - if (channel->channelvolslide) { - channel->channelvolume += channel->channelvolslide; - if (channel->channelvolume > 64) { - if (channel->channelvolslide >= 0) - channel->channelvolume = 64; - else - channel->channelvolume = 0; - } - } - - update_tremor(channel); - - update_retrig(sigrenderer, channel); - - if (channel->inv_loop_speed) update_invert_loop(channel, playing ? playing->sample : NULL); - - if (playing) { - playing->slide += channel->portamento; - - if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { - if (channel->toneporta && channel->destnote < 120) { - int currpitch = ((playing->note - 60) << 8) + playing->slide; - int destpitch = (channel->destnote - 60) << 8; - if (currpitch > destpitch) { - currpitch -= channel->toneporta; - if (currpitch < destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } else if (currpitch < destpitch) { - currpitch += channel->toneporta; - if (currpitch > destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } - playing->slide = currpitch - ((playing->note - 60) << 8); - } - } else { - if (channel->toneporta && channel->destnote < 120) { - float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); - - float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); - /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ - - float deltaslid = deltanote - playing->slide * amiga_multiplier; - - float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); - if (deltaslid < destdelta) { - playing->slide -= channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid > destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; - } - } else { - playing->slide += channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid < destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; - } - } - } - } - - update_playing_effects(playing); - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - IT_PLAYING *playing = sigrenderer->playing[i]; - if (playing) update_playing_effects(playing); - } - - update_smooth_effects(sigrenderer); -} - - -static void it_note_off(IT_PLAYING *playing); - -// This function should be renamed; it doesn't do the 'Update Pattern Variables' operation ittech.txt describes -/* Returns 1 if a pattern loop is happening. */ -static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) -{ - IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - - if (entry->mask & IT_ENTRY_EFFECT) { - switch (entry->effect) { - case IT_JUMP_TO_ORDER: - /* XXX jump and break in same row */ - if ( ( ( sigrenderer->processrow | 0xC00 ) == 0xFFFE ) && - ! ( sigrenderer->processrow & 0x800 ) ) { - sigrenderer->processrow = 0xFFFE & ~0xC00; - } else { - sigrenderer->breakrow = 0; - sigrenderer->processrow = 0xFFFE & ~0x400; - } - sigrenderer->processorder = entry->effectvalue - 1; - break; - - case IT_S: - { - unsigned char effectvalue = entry->effectvalue; - if (sigrenderer->sigdata->flags & IT_WAS_AN_S3M) { - if (effectvalue == 0) - effectvalue = channel->lastDKL; - channel->lastDKL = effectvalue; - } else { - if (effectvalue == 0) - effectvalue = channel->lastS; - } - channel->lastS = effectvalue; - switch (effectvalue >> 4) { - case IT_S_PATTERN_LOOP: - { - unsigned char v = effectvalue & 15; - if (v == 0) { -#ifdef BIT_ARRAY_BULLSHIT - if (!channel->played_patjump) - channel->played_patjump = bit_array_create(256); - else { - if ( channel->played_patjump_order != 0xFFFE && channel->played_patjump_order != sigrenderer->order ) - bit_array_merge(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); - //if (channel->played_patjump_order != sigrenderer->order) - bit_array_reset(channel->played_patjump); - } - channel->played_patjump_order = sigrenderer->order; -#endif - channel->pat_loop_row = sigrenderer->processrow; - } else { - if (channel->pat_loop_count == 0) { -#ifdef BIT_ARRAY_BULLSHIT - /* wft, uninitialized and no start marker yet... */ - if (channel->played_patjump_order == 0xFFFE) { - int n; - bit_array_destroy(channel->played_patjump); - channel->played_patjump = bit_array_create(256); - for (n = channel->pat_loop_row; n <= sigrenderer->row; n++) - bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + n); - channel->played_patjump_order = sigrenderer->order; - } else if (channel->played_patjump_order == sigrenderer->order) { - bit_array_set(channel->played_patjump, sigrenderer->row); - bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); - //bit_array_reset(channel->played_patjump); - } -#endif - channel->pat_loop_count = v; - sigrenderer->breakrow = channel->pat_loop_row; - if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { - /* For XM files, if a loop occurs by itself, keep breakrow set for when the pattern ends - fun bug in FT2! */ - if ((sigrenderer->processrow|0xC00) < 0xFFFE) { - /* Infinite pattern loops are possible, so we check whether the pattern loop we're hitting now is earlier than the last one we hit. */ - if (sigrenderer->processrow < channel->pat_loop_end_row) - sigrenderer->processorder = 0xFFFE; /* suspect infinite loop, so trigger loop callback */ - else - sigrenderer->processorder = 0xFFFF; /* don't trigger loop callback */ - channel->pat_loop_end_row = sigrenderer->processrow; - sigrenderer->processrow = 0xFFFF; /* special case: don't reset breakrow or pat_loop_end_row */ - } - } else { - /* IT files do this regardless of other flow control effects seen here. */ - sigrenderer->processorder = 0xFFFF; /* special case: don't trigger loop callback */ - sigrenderer->processrow = 0xFFFE; - } - return 1; - } else if (--channel->pat_loop_count) { -#ifdef BIT_ARRAY_BULLSHIT - if (channel->played_patjump_order == sigrenderer->order) { - bit_array_set(channel->played_patjump, sigrenderer->row); - bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); - //bit_array_reset(channel->played_patjump); - } -#endif - sigrenderer->breakrow = channel->pat_loop_row; - if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { - /* For XM files, if a loop occurs by itself, keep breakrow set for when the pattern ends - fun bug in FT2! */ - if ((sigrenderer->processrow|0xC00) < 0xFFFE) { - /* Infinite pattern loops are possible, so we check whether the pattern loop we're hitting now is earlier than the last one we hit. */ - if (sigrenderer->processrow < channel->pat_loop_end_row) - sigrenderer->processorder = 0xFFFE; /* suspect infinite loop, so trigger loop callback */ - else - sigrenderer->processorder = 0xFFFF; /* don't trigger loop callback */ - channel->pat_loop_end_row = sigrenderer->processrow; - sigrenderer->processrow = 0xFFFF; /* special case: don't reset breakrow or pat_loop_end_row */ - } - } else { - /* IT files do this regardless of other flow control effects seen here. */ - sigrenderer->processorder = 0xFFFF; /* special case: don't trigger loop callback */ - sigrenderer->processrow = 0xFFFE; - } - return 1; - } else if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { - channel->pat_loop_end_row = 0; - // TODO - /* Findings: - - If a pattern loop completes successfully, and then the pattern terminates, then the next pattern will start on the row corresponding to the E60. - - If a pattern loop doesn't do any loops, and then the pattern terminates, then the next pattern will start on the first row. - - If a break appears to the left of the pattern loop, it jumps into the relevant position in the next pattern, and that's it. - - If a break appears to the right of the pattern loop, it jumps to the start of the next pattern, and that's it. - - If we jump, then effect a loop using an old E60, and then the pattern ends, the next pattern starts on the row corresponding to the E60. - - Theory: breakrow is not cleared when it's a pattern loop effect! - */ - if ((sigrenderer->processrow | 0xC00) < 0xFFFE) // I have no idea if this is correct or not - FT2 is so weird :( - sigrenderer->breakrow = channel->pat_loop_row; /* emulate bug in FT2 */ - } else - channel->pat_loop_row = sigrenderer->processrow + 1; -#ifdef BIT_ARRAY_BULLSHIT - /*channel->played_patjump_order |= 0x8000;*/ - if (channel->played_patjump_order == sigrenderer->order) { - bit_array_destroy(channel->played_patjump); - channel->played_patjump = 0; - channel->played_patjump_order = 0xFFFE; - } - bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); -#endif - } - } - break; - case IT_S_PATTERN_DELAY: - sigrenderer->rowcount = 1 + (effectvalue & 15); - break; - } - } - } - } - - return 0; -} - - - -/* This function guarantees that channel->sample will always be valid if it - * is nonzero. In other words, to check if it is valid, simply check if it is - * nonzero. - */ -static void instrument_to_sample(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) -{ - if (sigdata->flags & IT_USE_INSTRUMENTS) { - if (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments) { - if (channel->note < 120) { - channel->sample = sigdata->instrument[channel->instrument-1].map_sample[channel->note]; - channel->truenote = sigdata->instrument[channel->instrument-1].map_note[channel->note]; - } else - channel->sample = 0; - } else - channel->sample = 0; - } else { - channel->sample = channel->instrument; - channel->truenote = channel->note; - } - if (!(channel->sample >= 1 && channel->sample <= sigdata->n_samples && (sigdata->sample[channel->sample-1].flags & IT_SAMPLE_EXISTS) && sigdata->sample[channel->sample-1].C5_speed)) - channel->sample = 0; -} - - - -static void fix_sample_looping(IT_PLAYING *playing) -{ - if ((playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) == - (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) { - if (playing->resampler.dir < 0) { - playing->resampler.pos = (playing->sample->sus_loop_end << 1) - 1 - playing->resampler.pos; - playing->resampler.subpos ^= 65535; - playing->resampler.dir = 1; - } - - playing->resampler.pos += playing->time_lost; - // XXX what - playing->time_lost = 0; - } -} - - - -static void it_compatible_gxx_retrigger(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) -{ - int flags = 0; - if (channel->sample) { - if (sigdata->flags & IT_USE_INSTRUMENTS) { - if (!(channel->playing->flags & IT_PLAYING_SUSTAINOFF)) { - if (channel->playing->env_instrument->volume_envelope.flags & IT_ENVELOPE_CARRY) - flags |= 1; - if (channel->playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_CARRY) - flags |= 2; - if (channel->playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_CARRY) - flags |= 4; - } - } - } - if (!(flags & 1)) { - channel->playing->volume_envelope.next_node = 0; - channel->playing->volume_envelope.tick = 0; - } - if (!(flags & 2)) { - channel->playing->pan_envelope.next_node = 0; - channel->playing->pan_envelope.tick = 0; - } - if (!(flags & 4)) { - channel->playing->pitch_envelope.next_node = 0; - channel->playing->pitch_envelope.tick = 0; - } - channel->playing->fadeoutcount = 1024; - // Should we remove IT_PLAYING_BACKGROUND? Test with sample with sustain loop... - channel->playing->flags &= ~(IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING | IT_PLAYING_DEAD); - it_playing_update_resamplers(channel->playing); - - if (!flags && channel->sample) - if (sigdata->flags & IT_USE_INSTRUMENTS) - channel->playing->env_instrument = &sigdata->instrument[channel->instrument-1]; -} - - - -static void it_note_off(IT_PLAYING *playing) -{ - if (playing) { - playing->enabled_envelopes |= IT_ENV_VOLUME; - playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF; - fix_sample_looping(playing); - it_playing_update_resamplers(playing); - if (playing->instrument) - if ((playing->instrument->volume_envelope.flags & (IT_ENVELOPE_ON | IT_ENVELOPE_LOOP_ON)) != IT_ENVELOPE_ON) - playing->flags |= IT_PLAYING_FADING; - } -} - - - -static void xm_note_off(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) -{ - if (channel->playing) { - if (!channel->instrument || channel->instrument > sigdata->n_instruments || - !(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON)) - //if (!(entry->mask & IT_ENTRY_INSTRUMENT)) - // dunno what that was there for ... - channel->volume = 0; - channel->playing->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING; - it_playing_update_resamplers(channel->playing); - } -} - - -static void recalculate_it_envelope_node(IT_PLAYING_ENVELOPE *pe, IT_ENVELOPE *e) -{ - int envpos = pe->tick; - unsigned int pt = e->n_nodes - 1; - unsigned int i; - for (i = 0; i < (unsigned int)(e->n_nodes - 1); ++i) - { - if (envpos <= e->node_t[i]) - { - pt = i; - break; - } - } - pe->next_node = pt; -} - - -static void recalculate_it_envelope_nodes(IT_PLAYING *playing) -{ - recalculate_it_envelope_node(&playing->volume_envelope, &playing->env_instrument->volume_envelope); - recalculate_it_envelope_node(&playing->pan_envelope, &playing->env_instrument->pitch_envelope); - recalculate_it_envelope_node(&playing->pitch_envelope, &playing->env_instrument->pitch_envelope); -} - - -static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel) -{ - int vol_env_tick = 0; - int pan_env_tick = 0; - int pitch_env_tick = 0; - - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - unsigned char nna = ~0; - int i, envelopes_copied = 0; - - if (channel->playing) { - if (channel->note == IT_NOTE_CUT) - nna = NNA_NOTE_CUT; - else if (channel->note == IT_NOTE_OFF) - nna = NNA_NOTE_OFF; - else if (channel->note > 120) - nna = NNA_NOTE_FADE; - else if (!channel->playing->instrument || (channel->playing->flags & IT_PLAYING_DEAD)) - nna = NNA_NOTE_CUT; - else if (channel->new_note_action != 0xFF) - { - nna = channel->new_note_action; - } - else - nna = channel->playing->instrument->new_note_action; - - if (!(channel->playing->flags & IT_PLAYING_SUSTAINOFF)) - { - if (nna != NNA_NOTE_CUT) - vol_env_tick = channel->playing->volume_envelope.tick; - pan_env_tick = channel->playing->pan_envelope.tick; - pitch_env_tick = channel->playing->pitch_envelope.tick; - envelopes_copied = 1; - } - - switch (nna) { - case NNA_NOTE_CUT: - channel->playing->declick_stage = 3; - break; - case NNA_NOTE_OFF: - it_note_off(channel->playing); - break; - case NNA_NOTE_FADE: - channel->playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING; - break; - } - } - - channel->new_note_action = 0xFF; - - if (channel->sample == 0 || channel->note > 120) - return; - - channel->destnote = IT_NOTE_OFF; - - if (channel->playing) { - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (!sigrenderer->playing[i]) { - sigrenderer->playing[i] = channel->playing; - channel->playing = NULL; - break; - } - } - - if (sigrenderer->sigdata->flags & IT_USE_INSTRUMENTS) - { - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - IT_PLAYING * playing = sigrenderer->playing[i]; - if (playing && playing->channel == channel && playing->instrument->dup_check_type) { - int match = 1; - switch (playing->instrument->dup_check_type) - { - case DCT_NOTE: - match = (channel->truenote == playing->note); - case DCT_SAMPLE: - match = match && (channel->sample == playing->sampnum); - case DCT_INSTRUMENT: - match = match && (channel->instrument == playing->instnum); - break; - } - - if (match) - { - switch (playing->instrument->dup_check_action) - { - case DCA_NOTE_CUT: - playing->declick_stage = 3; - if (channel->playing == playing) channel->playing = NULL; - break; - case DCA_NOTE_OFF: - if (!(playing->flags & IT_PLAYING_SUSTAINOFF)) - it_note_off(playing); - break; - case DCA_NOTE_FADE: - playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING; - break; - } - } - } - } - } - -/** WARNING - come up with some more heuristics for replacing old notes */ -#if 0 - if (channel->playing) { - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]->flags & IT_PLAYING_BACKGROUND) { - write_seqtime(); - sequence_c(SEQUENCE_STOP_SIGNAL); - sequence_c(i); - channel->VChannel = &module->VChannel[i]; - break; - } - } - } -#endif - } - - if (channel->playing) - free_playing(sigrenderer, channel->playing); - - channel->playing = new_playing(sigrenderer); - - if (!channel->playing) - return; - - if (!envelopes_copied && sigdata->flags & IT_USE_INSTRUMENTS) { - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - IT_PLAYING * playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - if (playing->flags & IT_PLAYING_SUSTAINOFF) continue; - if (nna != NNA_NOTE_CUT) - vol_env_tick = playing->volume_envelope.tick; - pan_env_tick = playing->pan_envelope.tick; - pitch_env_tick = playing->pitch_envelope.tick; - envelopes_copied = 1; - break; - } - } - - channel->playing->flags = 0; - channel->playing->resampling_quality = sigrenderer->resampling_quality; - channel->playing->channel = channel; - channel->playing->sample = &sigdata->sample[channel->sample-1]; - if (sigdata->flags & IT_USE_INSTRUMENTS) - channel->playing->instrument = &sigdata->instrument[channel->instrument-1]; - else - channel->playing->instrument = NULL; - channel->playing->env_instrument = channel->playing->instrument; - channel->playing->sampnum = channel->sample; - channel->playing->instnum = channel->instrument; - channel->playing->declick_stage = 0; - channel->playing->channel_volume = channel->channelvolume; - channel->playing->note = channel->truenote; - channel->playing->enabled_envelopes = 0; - channel->playing->volume_offset = 0; - channel->playing->panning_offset = 0; - //channel->playing->output = channel->output; - if (sigdata->flags & IT_USE_INSTRUMENTS) { - IT_PLAYING * playing = channel->playing; - IT_INSTRUMENT * instrument = playing->instrument; - if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_VOLUME; - if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PANNING; - if (instrument->pitch_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PITCH; - if (instrument->random_volume) playing->volume_offset = (rand() % (instrument->random_volume * 2 + 1)) - instrument->random_volume; - if (instrument->random_pan) playing->panning_offset = (rand() % (instrument->random_pan * 2 + 1)) - instrument->random_pan; - //if (instrument->output) playing->output = instrument->output; - } - channel->playing->filter_cutoff = 127; - channel->playing->filter_resonance = 0; - channel->playing->true_filter_cutoff = 127 << 8; - channel->playing->true_filter_resonance = 0; - channel->playing->vibrato_speed = 0; - channel->playing->vibrato_depth = 0; - channel->playing->vibrato_n = 0; - channel->playing->vibrato_time = 0; - channel->playing->vibrato_waveform = channel->vibrato_waveform; - channel->playing->tremolo_speed = 0; - channel->playing->tremolo_depth = 0; - channel->playing->tremolo_time = 0; - channel->playing->tremolo_waveform = channel->tremolo_waveform; - channel->playing->panbrello_speed = 0; - channel->playing->panbrello_depth = 0; - channel->playing->panbrello_time = 0; - channel->playing->panbrello_waveform = channel->panbrello_waveform; - channel->playing->panbrello_random = 0; - channel->playing->sample_vibrato_time = 0; - channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform; - channel->playing->sample_vibrato_depth = 0; - channel->playing->slide = 0; - channel->playing->finetune = channel->playing->sample->finetune; - - if (sigdata->flags & IT_USE_INSTRUMENTS) - { - if (envelopes_copied && channel->playing->env_instrument->volume_envelope.flags & IT_ENVELOPE_CARRY) { - channel->playing->volume_envelope.tick = vol_env_tick; - } else { - channel->playing->volume_envelope.tick = 0; - } - if (envelopes_copied && channel->playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_CARRY) { - channel->playing->pan_envelope.tick = pan_env_tick; - } else { - channel->playing->pan_envelope.tick = 0; - } - if (envelopes_copied && channel->playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_CARRY) { - channel->playing->pitch_envelope.tick = pitch_env_tick; - } else { - channel->playing->pitch_envelope.tick = 0; - } - recalculate_it_envelope_nodes(channel->playing); - } - channel->playing->fadeoutcount = 1024; - it_reset_filter_state(&channel->playing->filter_state[0]); - it_reset_filter_state(&channel->playing->filter_state[1]); - it_playing_reset_resamplers(channel->playing, 0); - - /** WARNING - is everything initialised? */ -} - - - -static void get_default_volpan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) -{ - if (channel->sample == 0) - return; - - channel->volume = sigdata->sample[channel->sample-1].default_volume; - - if (sigdata->flags & IT_WAS_AN_XM) { - if (!(sigdata->flags & IT_WAS_A_MOD)) - channel->truepan = 32 + sigdata->sample[channel->sample-1].default_pan*64; - return; - } - - { - int pan = sigdata->sample[channel->sample-1].default_pan; - if (pan >= 128 && pan <= 192) { - channel->pan = pan - 128; - return; - } - } - - if (sigdata->flags & IT_USE_INSTRUMENTS) { - IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1]; - if (instrument->default_pan <= 64) - channel->pan = instrument->default_pan; - if (instrument->filter_cutoff >= 128) - channel->filter_cutoff = instrument->filter_cutoff - 128; - if (instrument->filter_resonance >= 128) - channel->filter_resonance = instrument->filter_resonance - 128; - } -} - - - -static void get_true_pan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) -{ - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - - if (channel->sample && !IT_IS_SURROUND_SHIFTED(channel->truepan) && (sigdata->flags & IT_USE_INSTRUMENTS)) { - IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1]; - int truepan = channel->truepan; - truepan += (channel->note - instrument->pp_centre) * instrument->pp_separation << (IT_ENVELOPE_SHIFT - 3); - channel->truepan = (unsigned short)MID(0, truepan, 64 << IT_ENVELOPE_SHIFT); - } -} - - - -static void post_process_it_volpan(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) -{ - IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - - if (entry->mask & IT_ENTRY_VOLPAN) { - if (entry->volpan <= 84) { - /* Volume */ - /* Fine volume slide up */ - /* Fine volume slide down */ - } else if (entry->volpan <= 94) { - /* Volume slide up */ - unsigned char v = entry->volpan - 85; - if (v == 0) - v = channel->lastvolslide; - channel->lastvolslide = v; - /* = effect Dx0 where x == entry->volpan - 85 */ - channel->volslide += v; - } else if (entry->volpan <= 104) { - /* Volume slide down */ - unsigned char v = entry->volpan - 95; - if (v == 0) - v = channel->lastvolslide; - channel->lastvolslide = v; - /* = effect D0x where x == entry->volpan - 95 */ - channel->volslide -= v; - } else if (entry->volpan <= 114) { - /* Portamento down */ - unsigned char v = (entry->volpan - 105) << 2; - if (v == 0) - v = channel->lastEF; - channel->lastEF = v; - channel->portamento -= v << 4; - } else if (entry->volpan <= 124) { - /* Portamento up */ - unsigned char v = (entry->volpan - 115) << 2; - if (v == 0) - v = channel->lastEF; - channel->lastEF = v; - channel->portamento += v << 4; - } else if (entry->volpan <= 202) { - /* Pan */ - /* Tone Portamento */ - } else if (entry->volpan <= 212) { - /* Vibrato */ - /* This is unaffected by IT_OLD_EFFECTS. However, if v == 0, then any doubling of depth that happened before (with Hxy in the effect column) will be preserved. */ - unsigned char v = entry->volpan - 203; - if (v == 0) - v = channel->lastHdepth; - else { - v <<= 2; - channel->lastHdepth = v; - } - if (channel->playing) { - channel->playing->vibrato_speed = channel->lastHspeed; - channel->playing->vibrato_depth = v; - channel->playing->vibrato_n++; - } - } - } -} - - - -static void it_send_midi(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel, unsigned char midi_byte) -{ - if (sigrenderer->callbacks->midi) - if ((*sigrenderer->callbacks->midi)(sigrenderer->callbacks->midi_data, (int)(channel - sigrenderer->channel), midi_byte)) - return; - - switch (channel->midi_state) { - case 4: /* Ready to receive resonance parameter */ - if (midi_byte < 0x80) channel->filter_resonance = midi_byte; - channel->midi_state = 0; - break; - case 3: /* Ready to receive cutoff parameter */ - if (midi_byte < 0x80) channel->filter_cutoff = midi_byte; - channel->midi_state = 0; - break; - case 2: /* Ready for byte specifying which parameter will follow */ - if (midi_byte == 0) /* Cutoff */ - channel->midi_state = 3; - else if (midi_byte == 1) /* Resonance */ - channel->midi_state = 4; - else - channel->midi_state = 0; - break; - default: /* Counting initial F0 bytes */ - switch (midi_byte) { - case 0xF0: - channel->midi_state++; - break; - case 0xFA: - case 0xFC: - case 0xFF: - /* Reset filter parameters for all channels */ - { - int i; - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - sigrenderer->channel[i].filter_cutoff = 127; - sigrenderer->channel[i].filter_resonance = 0; - //// should we be resetting channel[i].playing->filter_* here? - } - } - /* Fall through */ - default: - channel->midi_state = 0; - break; - } - } -} - - - -static void xm_envelope_calculate_value(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) -{ - if (pe->next_node <= 0) - pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT; - else if (pe->next_node >= envelope->n_nodes) - pe->value = envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT; - else { - int ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT; - int ts = envelope->node_t[pe->next_node-1]; - int te = envelope->node_t[pe->next_node]; - - if (ts == te) - pe->value = ys; - else { - int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT; - int t = pe->tick; - - pe->value = ys + (ye - ys) * (t - ts) / (te - ts); - } - } -} - - - -extern const char xm_convert_vibrato[]; - -const char mod_convert_vibrato[] = { - IT_VIBRATO_SINE, - IT_VIBRATO_RAMP_UP, /* this will be inverted by IT_OLD_EFFECTS */ - IT_VIBRATO_XM_SQUARE, - IT_VIBRATO_XM_SQUARE -}; - -/* Returns 1 if a callback caused termination of playback. */ -static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) -{ - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - IT_PLAYING *playing; - int i; - - IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - - if (entry->mask & IT_ENTRY_EFFECT) { - switch (entry->effect) { -/* -Notes about effects (as compared to other module formats) - -C This is now in *HEX*. (Used to be in decimal in ST3) -E/F/G/H/U You need to check whether the song uses Amiga/Linear slides. -H/U Vibrato in Impulse Tracker is two times finer than in - any other tracker and is updated EVERY tick. - If "Old Effects" is *ON*, then the vibrato is played in the - normal manner (every non-row tick and normal depth) -E/F/G These commands ALL share the same memory. -Oxx Offsets to samples are to the 'xx00th' SAMPLE. (ie. for - 16 bit samples, the offset is xx00h*2) - Oxx past the sample end will be ignored, unless "Old Effects" - is ON, in which case the Oxx will play from the end of the - sample. -Yxy This uses a table 4 times larger (hence 4 times slower) than - vibrato or tremelo. If the waveform is set to random, then - the 'speed' part of the command is interpreted as a delay. -*/ - case IT_SET_SPEED: - if (entry->effectvalue) - { - /*if (entry->effectvalue == 255) - if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) - return 1;*/ - if (sigdata->flags & IT_WAS_AN_STM) { - int n = entry->effectvalue; - if (n >= 32) { - sigrenderer->tick = sigrenderer->speed = n; - } - } else { - sigrenderer->tick = sigrenderer->speed = entry->effectvalue; - } - } - else if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { -#ifdef BIT_ARRAY_BULLSHIT - bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); -#endif - sigrenderer->speed = 0; - if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) - return 1; - } - break; - - case IT_BREAK_TO_ROW: - if (ignore_cxx) break; - sigrenderer->breakrow = entry->effectvalue; - /* XXX jump and break on the same row */ - if ( ( ( sigrenderer->processrow | 0xC00 ) == 0xFFFE ) && - ! ( sigrenderer->processrow & 0x400 ) ) { - sigrenderer->processrow = 0xFFFE & ~0xC00; - } else { - sigrenderer->processorder = sigrenderer->order; - sigrenderer->processrow = 0xFFFE & ~0x800; - } - break; - - case IT_VOLSLIDE_VIBRATO: - for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (i < 0) playing = channel->playing; - else { - playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - } - if (playing) { - playing->vibrato_speed = channel->lastHspeed; - playing->vibrato_depth = channel->lastHdepth; - playing->vibrato_n++; - } - } - /* Fall through and process volume slide. */ - case IT_VOLUME_SLIDE: - case IT_VOLSLIDE_TONEPORTA: - /* The tone portamento component is handled elsewhere. */ - { - unsigned char v = entry->effectvalue; - if (!(sigdata->flags & IT_WAS_A_MOD)) { - if (v == 0) - v = channel->lastDKL; - channel->lastDKL = v; - } - if (!(sigdata->flags & IT_WAS_AN_XM)) { - int clip = (sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64; - if ((v & 0x0F) == 0x0F) { - if (!(v & 0xF0)) { - channel->volslide = -15; - channel->volume -= 15; - if (channel->volume > clip) channel->volume = 0; - } else { - channel->volume += v >> 4; - if (channel->volume > clip) channel->volume = clip; - } - } else if ((v & 0xF0) == 0xF0) { - if (!(v & 0x0F)) { - channel->volslide = 15; - channel->volume += 15; - if (channel->volume > clip) channel->volume = clip; - } else { - channel->volume -= v & 15; - if (channel->volume > clip) channel->volume = 0; - } - } else if (!(v & 0x0F)) { - channel->volslide = v >> 4; - } else { - channel->volslide = -(v & 15); - } - } else { - if ((v & 0x0F) == 0) { /* Dx0 */ - channel->volslide = v >> 4; - } else if ((v & 0xF0) == 0) { /* D0x */ - channel->volslide = -v; - } else if ((v & 0x0F) == 0x0F) { /* DxF */ - channel->volume += v >> 4; - if (channel->volume > 64) channel->volume = 64; - } else if ((v & 0xF0) == 0xF0) { /* DFx */ - channel->volume -= v & 15; - if (channel->volume > 64) channel->volume = 0; - } - } - } - break; - case IT_XM_FINE_VOLSLIDE_DOWN: - { - unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->xm_lastEB; - channel->xm_lastEB = v; - channel->volume -= v; - if (channel->volume > 64) channel->volume = 0; - } - break; - case IT_XM_FINE_VOLSLIDE_UP: - { - unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->xm_lastEA; - channel->xm_lastEA = v; - channel->volume += v; - if (channel->volume > 64) channel->volume = 64; - } - break; - case IT_PORTAMENTO_DOWN: - { - unsigned char v = entry->effectvalue; - if (sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_669)) { - if (!(sigdata->flags & IT_WAS_A_MOD)) { - if (v == 0xF0) - v |= channel->xm_lastE2; - else if (v >= 0xF0) - channel->xm_lastE2 = v & 15; - else if (v == 0xE0) - v |= channel->xm_lastX2; - else - channel->xm_lastX2 = v & 15; - } - } else if (sigdata->flags & IT_WAS_AN_S3M) { - if (v == 0) - v = channel->lastDKL; - channel->lastDKL = v; - } else { - if (v == 0) - v = channel->lastEF; - channel->lastEF = v; - } - for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (i < 0) playing = channel->playing; - else { - playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - } - if (playing) { - if ((v & 0xF0) == 0xF0) - playing->slide -= (v & 15) << 4; - else if ((v & 0xF0) == 0xE0) - playing->slide -= (v & 15) << 2; - else if (i < 0 && sigdata->flags & IT_WAS_A_669) - channel->portamento -= v << 3; - else if (i < 0) - channel->portamento -= v << 4; - } - } - } - break; - case IT_PORTAMENTO_UP: - { - unsigned char v = entry->effectvalue; - if (sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_669)) { - if (!(sigdata->flags & IT_WAS_A_MOD)) { - if (v == 0xF0) - v |= channel->xm_lastE1; - else if (v >= 0xF0) - channel->xm_lastE1 = v & 15; - else if (v == 0xE0) - v |= channel->xm_lastX1; - else - channel->xm_lastX1 = v & 15; - } - } else if (sigdata->flags & IT_WAS_AN_S3M) { - if (v == 0) - v = channel->lastDKL; - channel->lastDKL = v; - } else { - if (v == 0) - v = channel->lastEF; - channel->lastEF = v; - } - for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (i < 0) playing = channel->playing; - else { - playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - } - if (playing) { - if ((v & 0xF0) == 0xF0) - playing->slide += (v & 15) << 4; - else if ((v & 0xF0) == 0xE0) - playing->slide += (v & 15) << 2; - else if (i < 0 && sigdata->flags & IT_WAS_A_669) - channel->portamento += v << 3; - else if (i < 0) - channel->portamento += v << 4; - } - } - } - break; - case IT_XM_PORTAMENTO_DOWN: - { - unsigned char v = entry->effectvalue; - if (!(sigdata->flags & IT_WAS_A_MOD)) { - if (v == 0) - v = channel->lastJ; - channel->lastJ = v; - } - if (channel->playing) - channel->portamento -= v << 4; - } - break; - case IT_XM_PORTAMENTO_UP: - { - unsigned char v = entry->effectvalue; - if (!(sigdata->flags & IT_WAS_A_MOD)) { - if (v == 0) - v = channel->lastEF; - channel->lastEF = v; - } - if (channel->playing) - channel->portamento += v << 4; - } - break; - case IT_XM_KEY_OFF: - channel->key_off_count = entry->effectvalue; - if (!channel->key_off_count) xm_note_off(sigdata, channel); - break; - case IT_VIBRATO: - { - if (entry->effectvalue || !(sigdata->flags & IT_WAS_A_669)) { - unsigned char speed = entry->effectvalue >> 4; - unsigned char depth = entry->effectvalue & 15; - if (speed == 0) - speed = channel->lastHspeed; - channel->lastHspeed = speed; - if (depth == 0) - depth = channel->lastHdepth; - else { - if (sigdata->flags & IT_OLD_EFFECTS && !(sigdata->flags & IT_WAS_A_MOD)) - depth <<= 3; - else - depth <<= 2; - channel->lastHdepth = depth; - } - for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (i < 0) playing = channel->playing; - else { - playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - } - if (playing) { - playing->vibrato_speed = speed; - playing->vibrato_depth = depth; - playing->vibrato_n++; - } - } - } - } - break; - case IT_TREMOR: - { - unsigned char v = entry->effectvalue; - if (v == 0) { - if (sigdata->flags & IT_WAS_AN_S3M) - v = channel->lastDKL; - else - v = channel->lastI; - } - else if (!(sigdata->flags & IT_OLD_EFFECTS)) { - if (v & 0xF0) v -= 0x10; - if (v & 0x0F) v -= 0x01; - } - if (sigdata->flags & IT_WAS_AN_S3M) - channel->lastDKL = v; - else - channel->lastI = v; - channel->tremor_time |= 128; - } - update_tremor(channel); - break; - case IT_ARPEGGIO: - { - unsigned char v = entry->effectvalue; - /* XM files have no memory for arpeggio (000 = no effect) - * and we use lastJ for portamento down instead. - */ - if (!(sigdata->flags & IT_WAS_AN_XM)) { - if (sigdata->flags & IT_WAS_AN_S3M) { - if (v == 0) - v = channel->lastDKL; - channel->lastDKL = v; - } else { - if (v == 0) - v = channel->lastJ; - channel->lastJ = v; - } - } - channel->arpeggio_offsets[0] = 0; - channel->arpeggio_offsets[1] = (v & 0xF0) >> 4; - channel->arpeggio_offsets[2] = (v & 0x0F); - channel->arpeggio_table = (const unsigned char *)(((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD))==IT_WAS_AN_XM) ? &arpeggio_xm : &arpeggio_mod); - } - break; - case IT_SET_CHANNEL_VOLUME: - if (sigdata->flags & IT_WAS_AN_XM) - channel->volume = MIN(entry->effectvalue, 64); - else if (entry->effectvalue <= 64) - channel->channelvolume = entry->effectvalue; -#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM - else - channel->channelvolume = 64; -#endif - if (channel->playing) - channel->playing->channel_volume = channel->channelvolume; - break; - case IT_CHANNEL_VOLUME_SLIDE: - { - unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->lastN; - channel->lastN = v; - if ((v & 0x0F) == 0) { /* Nx0 */ - channel->channelvolslide = v >> 4; - } else if ((v & 0xF0) == 0) { /* N0x */ - channel->channelvolslide = -v; - } else { - if ((v & 0x0F) == 0x0F) { /* NxF */ - channel->channelvolume += v >> 4; - if (channel->channelvolume > 64) channel->channelvolume = 64; - } else if ((v & 0xF0) == 0xF0) { /* NFx */ - channel->channelvolume -= v & 15; - if (channel->channelvolume > 64) channel->channelvolume = 0; - } else - break; - if (channel->playing) - channel->playing->channel_volume = channel->channelvolume; - } - } - break; - case IT_SET_SAMPLE_OFFSET: - { - unsigned char v = entry->effectvalue; - /*if (sigdata->flags & IT_WAS_A_MOD) { - if (v == 0) break; - } else*/ { - if (v == 0) - v = channel->lastO; - channel->lastO = v; - } - /* Note: we set the offset even if tone portamento is - * specified. Impulse Tracker does the same. - */ - if (entry->mask & IT_ENTRY_NOTE) { - if (channel->playing) { - int offset = ((int)channel->high_offset << 16) | ((int)v << 8); - IT_PLAYING *playing = channel->playing; - IT_SAMPLE *sample = playing->sample; - int end; - if ((sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) - end = sample->sus_loop_end; - else if (sample->flags & IT_SAMPLE_LOOP) - end = sample->loop_end; - else { - end = sample->length; - if ( sigdata->flags & IT_WAS_PROCESSED && end > 64 ) // XXX bah damn LPC and edge case modules - end -= 64; - } - if ((sigdata->flags & IT_WAS_A_PTM) && (sample->flags & IT_SAMPLE_16BIT)) - offset >>= 1; - if (offset < end) { - it_playing_reset_resamplers(playing, offset); - playing->declick_stage = 0; - } else if (sigdata->flags & IT_OLD_EFFECTS) { - it_playing_reset_resamplers(playing, end); - playing->declick_stage = 0; - } - } - } - } - break; - case IT_PANNING_SLIDE: - /** JULIEN: guess what? the docs are wrong! (how unusual ;) - * Pxy seems to memorize its previous value... and there - * might be other mistakes like that... (sigh!) - */ - /** ENTHEH: umm... but... the docs say that Pxy memorises its - * value... don't they? :o - */ - { - unsigned char v = entry->effectvalue; - int p = channel->truepan; - if (sigdata->flags & IT_WAS_AN_XM) - { - if (IT_IS_SURROUND(channel->pan)) - { - channel->pan = 32; - p = 32 + 128 * 64; - } - p >>= 6; - } - else { - if (IT_IS_SURROUND(channel->pan)) p = 32 << 8; - p = (p + 128) >> 8; - channel->pan = p; - } - if (v == 0) - v = channel->lastP; - channel->lastP = v; - if ((v & 0x0F) == 0) { /* Px0 */ - channel->panslide = -(v >> 4); - } else if ((v & 0xF0) == 0) { /* P0x */ - channel->panslide = v; - } else if ((v & 0x0F) == 0x0F) { /* PxF */ - p -= v >> 4; - } else if ((v & 0xF0) == 0xF0) { /* PFx */ - p += v & 15; - } - if (sigdata->flags & IT_WAS_AN_XM) - channel->truepan = 32 + MID(0, p, 255) * 64; - else { - if (p < 0) p = 0; - else if (p > 64) p = 64; - channel->pan = p; - channel->truepan = p << 8; - } - } - break; - case IT_RETRIGGER_NOTE: - { - unsigned char v = entry->effectvalue; - if (sigdata->flags & IT_WAS_AN_XM) { - if ((v & 0x0F) == 0) v |= channel->lastQ & 0x0F; - if ((v & 0xF0) == 0) v |= channel->lastQ & 0xF0; - channel->lastQ = v; - } else if (sigdata->flags & IT_WAS_AN_S3M) { - if (v == 0) - v = channel->lastDKL; - channel->lastDKL = v; - } else { - if (v == 0) - v = channel->lastQ; - channel->lastQ = v; - } - if ((v & 0x0F) == 0) v |= 0x01; - channel->retrig = v; - if (entry->mask & IT_ENTRY_NOTE) { - channel->retrig_tick = v & 0x0F; - /* Emulate a bug */ - if (sigdata->flags & IT_WAS_AN_XM) - update_retrig(sigrenderer, channel); - } else - update_retrig(sigrenderer, channel); - } - break; - case IT_XM_RETRIGGER_NOTE: - channel->retrig_tick = channel->xm_retrig = entry->effectvalue; - if (entry->effectvalue == 0) - if (channel->playing) { - it_playing_reset_resamplers(channel->playing, 0); - channel->playing->declick_stage = 0; - } - break; - case IT_TREMOLO: - { - unsigned char speed, depth; - if (sigdata->flags & IT_WAS_AN_S3M) { - unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->lastDKL; - channel->lastDKL = v; - speed = v >> 4; - depth = v & 15; - } else { - speed = entry->effectvalue >> 4; - depth = entry->effectvalue & 15; - if (speed == 0) - speed = channel->lastRspeed; - channel->lastRspeed = speed; - if (depth == 0) - depth = channel->lastRdepth; - channel->lastRdepth = depth; - } - for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (i < 0) playing = channel->playing; - else { - playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - } - if (playing) { - playing->tremolo_speed = speed; - playing->tremolo_depth = depth; - } - } - } - break; - case IT_S: - { - /* channel->lastS was set in update_pattern_variables(). */ - unsigned char effectvalue = channel->lastS; - switch (effectvalue >> 4) { - //case IT_S_SET_FILTER: - /* Waveforms for commands S3x, S4x and S5x: - * 0: Sine wave - * 1: Ramp down - * 2: Square wave - * 3: Random wave - */ - case IT_S_SET_GLISSANDO_CONTROL: - channel->glissando = effectvalue & 15; - break; - - case IT_S_FINETUNE: - if (channel->playing) { - channel->playing->finetune = ((int)(effectvalue & 15) - 8) << 5; - } - break; - - case IT_S_SET_VIBRATO_WAVEFORM: - { - int waveform = effectvalue & 3; - if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; - else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; - channel->vibrato_waveform = waveform; - if (channel->playing) { - channel->playing->vibrato_waveform = waveform; - if (!(effectvalue & 4)) - channel->playing->vibrato_time = 0; - } - } - break; - case IT_S_SET_TREMOLO_WAVEFORM: - { - int waveform = effectvalue & 3; - if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; - else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; - channel->tremolo_waveform = waveform; - if (channel->playing) { - channel->playing->tremolo_waveform = waveform; - if (!(effectvalue & 4)) - channel->playing->tremolo_time = 0; - } - } - break; - case IT_S_SET_PANBRELLO_WAVEFORM: - channel->panbrello_waveform = effectvalue & 3; - if (channel->playing) { - channel->playing->panbrello_waveform = effectvalue & 3; - if (!(effectvalue & 4)) - channel->playing->panbrello_time = 0; - } - break; - - case IT_S_FINE_PATTERN_DELAY: - sigrenderer->tick += effectvalue & 15; - break; -#if 1 - case IT_S7: - { - if (sigrenderer->sigdata->flags & IT_USE_INSTRUMENTS) - { - int i; - switch (effectvalue & 15) - { - case 0: /* cut background notes */ - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - { - IT_PLAYING * playing = sigrenderer->playing[i]; - if (playing && channel == playing->channel) - { - playing->declick_stage = 3; - if (channel->playing == playing) channel->playing = NULL; - } - } - break; - case 1: /* release background notes */ - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - { - IT_PLAYING * playing = sigrenderer->playing[i]; - if (playing && channel == playing->channel && !(playing->flags & IT_PLAYING_SUSTAINOFF)) - { - it_note_off(playing); - } - } - break; - case 2: /* fade background notes */ - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - { - IT_PLAYING * playing = sigrenderer->playing[i]; - if (playing && channel == playing->channel) - { - //playing->flags &= IT_PLAYING_SUSTAINOFF; - playing->flags |= IT_PLAYING_FADING; - } - } - break; - case 3: - channel->new_note_action = NNA_NOTE_CUT; - break; - case 4: - channel->new_note_action = NNA_NOTE_CONTINUE; - break; - case 5: - channel->new_note_action = NNA_NOTE_OFF; - break; - case 6: - channel->new_note_action = NNA_NOTE_FADE; - break; - - case 7: - if (channel->playing) - channel->playing->enabled_envelopes &= ~IT_ENV_VOLUME; - break; - case 8: - if (channel->playing) - channel->playing->enabled_envelopes |= IT_ENV_VOLUME; - break; - - case 9: - if (channel->playing) - channel->playing->enabled_envelopes &= ~IT_ENV_PANNING; - break; - case 10: - if (channel->playing) - channel->playing->enabled_envelopes |= IT_ENV_PANNING; - break; - - case 11: - if (channel->playing) - channel->playing->enabled_envelopes &= ~IT_ENV_PITCH; - break; - case 12: - if (channel->playing) - channel->playing->enabled_envelopes |= IT_ENV_PITCH; - break; - } - } - } - break; -#endif - case IT_S_SET_PAN: - //ASSERT(!(sigdata->flags & IT_WAS_AN_XM)); - channel->pan = - ((effectvalue & 15) << 2) | - ((effectvalue & 15) >> 2); - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - - if (channel->playing) - channel->playing->panbrello_depth = 0; - break; - case IT_S_SET_SURROUND_SOUND: - if ((effectvalue & 15) == 15) { - if (channel->playing && channel->playing->sample && - !(channel->playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP))) { - channel->playing->flags |= IT_PLAYING_REVERSE; - it_playing_reset_resamplers( channel->playing, channel->playing->sample->length - 1 ); - } - } else if ((effectvalue & 15) == 1) { - channel->pan = IT_SURROUND; - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - } - if (channel->playing) - channel->playing->panbrello_depth = 0; - break; - case IT_S_SET_HIGH_OFFSET: - channel->high_offset = effectvalue & 15; - break; - //case IT_S_PATTERN_LOOP: - case IT_S_DELAYED_NOTE_CUT: - channel->note_cut_count = effectvalue & 15; - if (!channel->note_cut_count) { - if (sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_PTM)) - channel->volume = 0; - else - channel->note_cut_count = 1; - } - break; - case IT_S_SET_MIDI_MACRO: - if ((sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == (IT_WAS_AN_XM | IT_WAS_A_MOD)) { - channel->inv_loop_speed = effectvalue & 15; - update_invert_loop(channel, channel->playing ? channel->playing->sample : NULL); - } else channel->SFmacro = effectvalue & 15; - break; - } - } - break; - case IT_SET_SONG_TEMPO: - { - unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->lastW; - channel->lastW = v; - if (v < 0x10) - sigrenderer->temposlide = -v; - else if (v < 0x20) - sigrenderer->temposlide = v & 15; - else - sigrenderer->tempo = v; - } - break; - case IT_FINE_VIBRATO: - { - unsigned char speed = entry->effectvalue >> 4; - unsigned char depth = entry->effectvalue & 15; - if (speed == 0) - speed = channel->lastHspeed; - channel->lastHspeed = speed; - if (depth == 0) - depth = channel->lastHdepth; - else { - if (sigdata->flags & IT_OLD_EFFECTS) - depth <<= 1; - channel->lastHdepth = depth; - } - for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (i < 0) playing = channel->playing; - else { - playing = sigrenderer->playing[i]; - if (!playing || playing->channel != channel) continue; - } - if (playing) { - playing->vibrato_speed = speed; - playing->vibrato_depth = depth; - playing->vibrato_n++; - } - } - } - break; - case IT_SET_GLOBAL_VOLUME: - if ((sigdata->flags & IT_WAS_AN_S3M) && (entry->effectvalue > 64)) - break; - if (entry->effectvalue <= 128) - sigrenderer->globalvolume = entry->effectvalue; -#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM - else - sigrenderer->globalvolume = 128; -#endif - break; - case IT_GLOBAL_VOLUME_SLIDE: - { - unsigned char v = entry->effectvalue; - if (v == 0) - v = channel->lastW; - channel->lastW = v; - if ((v & 0x0F) == 0) { /* Wx0 */ - sigrenderer->globalvolslide = - (sigdata->flags & IT_WAS_AN_XM) ? (v >> 4)*2 : (v >> 4); - } else if ((v & 0xF0) == 0) { /* W0x */ - sigrenderer->globalvolslide = - (sigdata->flags & IT_WAS_AN_XM) ? (-v)*2 : (-v); - } else if ((v & 0x0F) == 0x0F) { /* WxF */ - sigrenderer->globalvolume += v >> 4; - if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 128; - } else if ((v & 0xF0) == 0xF0) { /* WFx */ - sigrenderer->globalvolume -= v & 15; - if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 0; - } - } - break; - case IT_SET_PANNING: - if (sigdata->flags & IT_WAS_AN_XM) { - channel->truepan = 32 + entry->effectvalue*64; - } else { - if (sigdata->flags & IT_WAS_AN_S3M) - channel->pan = (entry->effectvalue + 1) >> 1; - else - channel->pan = (entry->effectvalue + 2) >> 2; - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - } - if (channel->playing) - channel->playing->panbrello_depth = 0; - break; - case IT_PANBRELLO: - { - unsigned char speed = entry->effectvalue >> 4; - unsigned char depth = entry->effectvalue & 15; - if (speed == 0) - speed = channel->lastYspeed; - channel->lastYspeed = speed; - if (depth == 0) - depth = channel->lastYdepth; - channel->lastYdepth = depth; - if (channel->playing) { - channel->playing->panbrello_speed = speed; - channel->playing->panbrello_depth = depth; - } - } - break; - case IT_MIDI_MACRO: - { - const IT_MIDI *midi = sigdata->midi ? sigdata->midi : &default_midi; - if (entry->effectvalue >= 0x80) { - int n = midi->Zmacrolen[entry->effectvalue-0x80]; - int i; - for (i = 0; i < n; i++) - it_send_midi(sigrenderer, channel, midi->Zmacro[entry->effectvalue-0x80][i]); - } else { - int n = midi->SFmacrolen[channel->SFmacro]; - int i, j; - for (i = 0, j = 1; i < n; i++, j <<= 1) - it_send_midi(sigrenderer, channel, - (unsigned char)(midi->SFmacroz[channel->SFmacro] & j ? - entry->effectvalue : midi->SFmacro[channel->SFmacro][i])); - } - } - break; - case IT_XM_SET_ENVELOPE_POSITION: - if (channel->playing && channel->playing->env_instrument) { - IT_ENVELOPE *envelope = &channel->playing->env_instrument->volume_envelope; - if (envelope->flags & IT_ENVELOPE_ON) { - IT_PLAYING_ENVELOPE *pe = &channel->playing->volume_envelope; - pe->tick = entry->effectvalue; - if (pe->tick >= envelope->node_t[envelope->n_nodes-1]) - pe->tick = envelope->node_t[envelope->n_nodes-1]; - pe->next_node = 0; - while (pe->tick > envelope->node_t[pe->next_node]) pe->next_node++; - xm_envelope_calculate_value(envelope, pe); - } - } - break; - - /* uggly plain portamento for now */ - case IT_PTM_NOTE_SLIDE_DOWN: - case IT_PTM_NOTE_SLIDE_DOWN_RETRIG: - { - channel->toneslide_retrig = (entry->effect == IT_PTM_NOTE_SLIDE_DOWN_RETRIG); - - if (channel->ptm_last_toneslide) { - channel->toneslide_tick = channel->last_toneslide_tick; - - if (--channel->toneslide_tick == 0) { - channel->truenote += channel->toneslide; - if (channel->truenote >= 120) { - if (channel->toneslide < 0) channel->truenote = 0; - else channel->truenote = 119; - } - channel->note += channel->toneslide; - if (channel->note >= 120) { - if (channel->toneslide < 0) channel->note = 0; - else channel->note = 119; - } - - if (channel->playing) { - if (channel->sample) channel->playing->note = channel->truenote; - else channel->playing->note = channel->note; - it_playing_reset_resamplers(channel->playing, 0); - channel->playing->declick_stage = 0; - } - } - } - - channel->ptm_last_toneslide = 0; - - channel->toneslide = -(entry->effectvalue & 15); - channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4; - channel->toneslide_tick += channel->ptm_toneslide; - } - break; - case IT_PTM_NOTE_SLIDE_UP: - case IT_PTM_NOTE_SLIDE_UP_RETRIG: - { - channel->toneslide_retrig = (entry->effect == IT_PTM_NOTE_SLIDE_UP_RETRIG); - - if (channel->ptm_last_toneslide) { - channel->toneslide_tick = channel->last_toneslide_tick; - - if (--channel->toneslide_tick == 0) { - channel->truenote += channel->toneslide; - if (channel->truenote >= 120) { - if (channel->toneslide < 0) channel->truenote = 0; - else channel->truenote = 119; - } - channel->note += channel->toneslide; - if (channel->note >= 120) { - if (channel->toneslide < 0) channel->note = 0; - else channel->note = 119; - } - - if (channel->playing) { - if (channel->sample) channel->playing->note = channel->truenote; - else channel->playing->note = channel->note; - it_playing_reset_resamplers(channel->playing, 0); - channel->playing->declick_stage = 0; - } - } - } - - channel->ptm_last_toneslide = 0; - - channel->toneslide = -(entry->effectvalue & 15); - channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4; - channel->toneslide_tick += channel->ptm_toneslide; - } - break; - - case IT_OKT_NOTE_SLIDE_DOWN: - case IT_OKT_NOTE_SLIDE_DOWN_ROW: - channel->toneslide = -entry->effectvalue; - channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_DOWN) ? 255 : 1; - break; - - case IT_OKT_NOTE_SLIDE_UP: - case IT_OKT_NOTE_SLIDE_UP_ROW: - channel->toneslide = entry->effectvalue; - channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_UP) ? 255 : 1; - break; - - case IT_OKT_ARPEGGIO_3: - case IT_OKT_ARPEGGIO_4: - case IT_OKT_ARPEGGIO_5: - { - channel->arpeggio_offsets[0] = 0; - channel->arpeggio_offsets[1] = -(entry->effectvalue >> 4); - channel->arpeggio_offsets[2] = entry->effectvalue & 0x0F; - - switch (entry->effect) - { - case IT_OKT_ARPEGGIO_3: - channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_3; - break; - - case IT_OKT_ARPEGGIO_4: - channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_4; - break; - - case IT_OKT_ARPEGGIO_5: - channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_5; - break; - } - } - break; - - case IT_OKT_VOLUME_SLIDE_DOWN: - if ( entry->effectvalue <= 16 ) channel->volslide = -entry->effectvalue; - else - { - channel->volume -= entry->effectvalue - 16; - if (channel->volume > 64) channel->volume = 0; - } - break; - - case IT_OKT_VOLUME_SLIDE_UP: - if ( entry->effectvalue <= 16 ) channel->volslide = entry->effectvalue; - else - { - channel->volume += entry->effectvalue - 16; - if (channel->volume > 64) channel->volume = 64; - } - break; - } - } - - if (!(sigdata->flags & IT_WAS_AN_XM)) - post_process_it_volpan(sigrenderer, entry); - - return 0; -} - - - -static int process_it_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) -{ - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - - // When tone portamento and instrument are specified: - // If Gxx is off: - // - same sample, do nothing but portamento - // - diff sample, retrigger all but keep current note+slide + do porta - // - if instrument is invalid, nothing; if sample is invalid, cut - // If Gxx is on: - // - same sample or new sample invalid, retrigger envelopes and initialise note value for portamento to 'seek' to - // - diff sample/inst, start using new envelopes - // When tone portamento is specified alone, sample won't change. - // TODO: consider what happens with instrument alone after all this... - - if (entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) { - if (entry->mask & IT_ENTRY_INSTRUMENT) - channel->instrument = entry->instrument; - instrument_to_sample(sigdata, channel); - if (channel->note <= 120) { - if ((sigdata->flags & IT_USE_INSTRUMENTS) && channel->sample == 0) - it_retrigger_note(sigrenderer, channel); /* Stop the note */ /*return 1;*/ - if (entry->mask & IT_ENTRY_INSTRUMENT) - get_default_volpan(sigdata, channel); - } else - it_retrigger_note(sigrenderer, channel); /* Stop the note */ - } - - /** WARNING: This is not ideal, since channel->playing might not get allocated owing to lack of memory... */ - if (((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) || - ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA))) - { - if (channel->playing && (entry->mask & IT_ENTRY_INSTRUMENT)) { - if (sigdata->flags & IT_COMPATIBLE_GXX) - it_compatible_gxx_retrigger(sigdata, channel); - else if ((!(sigdata->flags & IT_USE_INSTRUMENTS) || - (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments)) && - channel->sample != channel->playing->sampnum) - { - unsigned char note = channel->playing->note; - int slide = channel->playing->slide; - it_retrigger_note(sigrenderer, channel); - if (channel->playing) { - channel->playing->note = note; - channel->playing->slide = slide; - // Should we be preserving sample_vibrato_time? depth? - } - } - } - - channel->toneporta = 0; - - if ((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) { - /* Tone Portamento in the volume column */ - static const unsigned char slidetable[] = {0, 1, 4, 8, 16, 32, 64, 96, 128, 255}; - unsigned char v = slidetable[entry->volpan - 193]; - if (sigdata->flags & IT_COMPATIBLE_GXX) { - if (v == 0) - v = channel->lastG; - channel->lastG = v; - } else { - if (v == 0) - v = channel->lastEF; - channel->lastEF = v; - } - channel->toneporta += v << 4; - } - - if ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA)) { - /* Tone Portamento in the effect column */ - unsigned char v; - if (entry->effect == IT_TONE_PORTAMENTO) - v = entry->effectvalue; - else - v = 0; - if (sigdata->flags & IT_COMPATIBLE_GXX) { - if (v == 0) - v = channel->lastG; - channel->lastG = v; - } else { - if (v == 0 && !(sigdata->flags & IT_WAS_A_669)) - v = channel->lastEF; - channel->lastEF = v; - } - channel->toneporta += v << 4; - } - - if ((entry->mask & IT_ENTRY_NOTE) || ((sigdata->flags & IT_COMPATIBLE_GXX) && (entry->mask & IT_ENTRY_INSTRUMENT))) { - if (channel->note <= 120) { - if (channel->sample) - channel->destnote = channel->truenote; - else - channel->destnote = channel->note; - } - } - - if (channel->playing) goto skip_start_note; - } - - if ((entry->mask & IT_ENTRY_NOTE) || - ((entry->mask & IT_ENTRY_INSTRUMENT) && (!channel->playing || entry->instrument != channel->playing->instnum))) - { - if (channel->note <= 120) { - get_true_pan(sigdata, channel); - if ((entry->mask & IT_ENTRY_NOTE) || !(sigdata->flags & (IT_WAS_AN_S3M|IT_WAS_A_PTM))) - it_retrigger_note(sigrenderer, channel); - } - } - - skip_start_note: - - if (entry->mask & IT_ENTRY_VOLPAN) { - if (entry->volpan <= 64) { - /* Volume */ - channel->volume = entry->volpan; - } else if (entry->volpan <= 74) { - /* Fine volume slide up */ - unsigned char v = entry->volpan - 65; - if (v == 0) - v = channel->lastvolslide; - channel->lastvolslide = v; - /* = effect DxF where x == entry->volpan - 65 */ - channel->volume += v; - if (channel->volume > 64) channel->volume = 64; - } else if (entry->volpan <= 84) { - /* Fine volume slide down */ - unsigned char v = entry->volpan - 75; - if (v == 0) - v = channel->lastvolslide; - channel->lastvolslide = v; - /* = effect DFx where x == entry->volpan - 75 */ - channel->volume -= v; - if (channel->volume > 64) channel->volume = 0; - } else if (entry->volpan < 128) { - /* Volume slide up */ - /* Volume slide down */ - /* Portamento down */ - /* Portamento up */ - } else if (entry->volpan <= 192) { - /* Pan */ - channel->pan = entry->volpan - 128; - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - } - /* else */ - /* Tone Portamento */ - /* Vibrato */ - } - return 0; -} - - - -static void retrigger_xm_envelopes(IT_PLAYING *playing) -{ - playing->volume_envelope.next_node = 0; - playing->volume_envelope.tick = -1; - playing->pan_envelope.next_node = 0; - playing->pan_envelope.tick = -1; - playing->fadeoutcount = 1024; -} - - - -static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) -{ - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - IT_PLAYING * playing = NULL; - - if (entry->mask & IT_ENTRY_INSTRUMENT) { - int oldsample = channel->sample; - channel->inv_loop_offset = 0; - channel->instrument = entry->instrument; - instrument_to_sample(sigdata, channel); - if (channel->playing && - !((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) && - !((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0)) { - playing = dup_playing(channel->playing, channel, channel); - if (!playing) return; - if (!(sigdata->flags & IT_WAS_A_MOD)) { - /* Retrigger vol/pan envelopes if enabled, and cancel fadeout. - * Also reset vol/pan to that of _original_ instrument. - */ - channel->playing->flags &= ~(IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING); - it_playing_update_resamplers(channel->playing); - - channel->volume = channel->playing->sample->default_volume; - channel->truepan = 32 + channel->playing->sample->default_pan*64; - - retrigger_xm_envelopes(channel->playing); - } else { - /* Switch if sample changed */ - if (oldsample != channel->sample) { - int i; - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (!sigrenderer->playing[i]) { - channel->playing->declick_stage = 3; - sigrenderer->playing[i] = channel->playing; - channel->playing = NULL; - break; - } - } - - if (!channel->sample) { - if (channel->playing) - { - free_playing(sigrenderer, channel->playing); - channel->playing = NULL; - } - } else { - if (channel->playing) { - free_playing(sigrenderer, channel->playing); - } - channel->playing = playing; - playing = NULL; - channel->playing->declick_stage = 0; - channel->playing->sampnum = channel->sample; - channel->playing->sample = &sigdata->sample[channel->sample-1]; - it_playing_reset_resamplers(channel->playing, 0); - } - } - get_default_volpan(sigdata, channel); - } - } - } - - if (!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0) && - (entry->mask & IT_ENTRY_NOTE)) - { - if (!(entry->mask & IT_ENTRY_INSTRUMENT)) - instrument_to_sample(sigdata, channel); - - if (channel->note >= 120) - xm_note_off(sigdata, channel); - else if (channel->sample == 0) { - /** If we get here, one of the following is the case: - ** 1. The instrument has never been specified on this channel. - ** 2. The specified instrument is invalid. - ** 3. The instrument has no sample mapped to the selected note. - ** What should happen? - ** - ** Experimentation shows that any existing note stops and cannot - ** be brought back. A subsequent instrument change fixes that. - **/ - if (channel->playing) { - int i; - if (playing) { - free_playing(sigrenderer, channel->playing); - channel->playing = playing; - playing = NULL; - } - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (!sigrenderer->playing[i]) { - channel->playing->declick_stage = 3; - sigrenderer->playing[i] = channel->playing; - channel->playing = NULL; - break; - } - } - if (channel->playing) { - free_playing(sigrenderer, channel->playing); - channel->playing = NULL; - } - } - if (playing) free_playing(sigrenderer, playing); - return; - } else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) { - /* Don't retrigger note; portamento in the volume column. */ - } else if (channel->playing && - (entry->mask & IT_ENTRY_EFFECT) && - (entry->effect == IT_TONE_PORTAMENTO || - entry->effect == IT_VOLSLIDE_TONEPORTA)) { - /* Don't retrigger note; portamento in the effects column. */ - } else { - channel->destnote = IT_NOTE_OFF; - - if (!channel->playing) { - channel->playing = new_playing(sigrenderer); - if (!channel->playing) { - if (playing) free_playing(sigrenderer, playing); - return; - } - // Adding the following seems to do the trick for the case where a piece starts with an instrument alone and then some notes alone. - retrigger_xm_envelopes(channel->playing); - } - else if (playing) { - /* volume rampy stuff! move note to NNA */ - int i; - IT_PLAYING * ptemp; - if (playing->sample) ptemp = playing; - else ptemp = channel->playing; - if (!ptemp) { - if (playing) free_playing(sigrenderer, playing); - return; - } - playing = NULL; - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (!sigrenderer->playing[i]) { - ptemp->declick_stage = 3; - ptemp->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING; - sigrenderer->playing[i] = ptemp; - ptemp = NULL; - break; - } - } - if (ptemp) free_playing(sigrenderer, ptemp); - } - - channel->playing->flags = 0; - channel->playing->resampling_quality = sigrenderer->resampling_quality; - channel->playing->channel = channel; - channel->playing->sample = &sigdata->sample[channel->sample-1]; - if (sigdata->flags & IT_USE_INSTRUMENTS) - channel->playing->instrument = &sigdata->instrument[channel->instrument-1]; - else - channel->playing->instrument = NULL; - channel->playing->env_instrument = channel->playing->instrument; - channel->playing->sampnum = channel->sample; - channel->playing->instnum = channel->instrument; - channel->playing->declick_stage = 0; - channel->playing->channel_volume = channel->channelvolume; - channel->playing->note = channel->truenote; - channel->playing->enabled_envelopes = 0; - channel->playing->volume_offset = 0; - channel->playing->panning_offset = 0; - //channel->playing->output = channel->output; - if (sigdata->flags & IT_USE_INSTRUMENTS) { - IT_PLAYING * playing = channel->playing; - IT_INSTRUMENT * instrument = playing->instrument; - if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_VOLUME; - if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PANNING; - //if (instrument->output) playing->output = instrument->output; - } - channel->playing->filter_cutoff = 127; - channel->playing->filter_resonance = 0; - channel->playing->true_filter_cutoff = 127 << 8; - channel->playing->true_filter_resonance = 0; - channel->playing->vibrato_speed = 0; - channel->playing->vibrato_depth = 0; - channel->playing->vibrato_n = 0; - channel->playing->vibrato_time = 0; - channel->playing->vibrato_waveform = 0; - channel->playing->tremolo_speed = 0; - channel->playing->tremolo_depth = 0; - channel->playing->tremolo_time = 0; - channel->playing->tremolo_waveform = 0; - channel->playing->panbrello_speed = 0; - channel->playing->panbrello_depth = 0; - channel->playing->panbrello_time = 0; - channel->playing->panbrello_waveform = 0; - channel->playing->panbrello_random = 0; - channel->playing->sample_vibrato_time = 0; - channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform; - channel->playing->sample_vibrato_depth = 0; - channel->playing->slide = 0; - channel->playing->finetune = channel->playing->sample->finetune; - it_reset_filter_state(&channel->playing->filter_state[0]); // Are these - it_reset_filter_state(&channel->playing->filter_state[1]); // necessary? - it_playing_reset_resamplers(channel->playing, 0); - - /** WARNING - is everything initialised? */ - } - } - - if (!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0) && - !((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) && - (entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) == (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) - { - if (channel->playing) retrigger_xm_envelopes(channel->playing); - get_default_volpan(sigdata, channel); - } - - if ((entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) { - /* Tone Portamento */ - unsigned char v = (entry->volpan & 15) << 4; - if (v == 0) - v = channel->lastG; - channel->lastG = v; - if (entry->mask & IT_ENTRY_NOTE) - if (channel->sample && channel->note < 120) - channel->destnote = channel->truenote; - channel->toneporta = v << 4; - } else if ((entry->mask & IT_ENTRY_EFFECT) && - (entry->effect == IT_TONE_PORTAMENTO || - entry->effect == IT_VOLSLIDE_TONEPORTA)) { - unsigned char v; - if (entry->effect == IT_TONE_PORTAMENTO) - v = entry->effectvalue; - else - v = 0; - if (v == 0) - v = channel->lastG; - channel->lastG = v; - if (entry->mask & IT_ENTRY_NOTE) - if (channel->sample && channel->note < 120) - channel->destnote = channel->truenote; - channel->toneporta = v << 4; - } - - if (entry->mask & IT_ENTRY_VOLPAN) { - int effect = entry->volpan >> 4; - int value = entry->volpan & 15; - switch (effect) { - case 0x6: /* Volume slide down */ - channel->xm_volslide = -value; - break; - case 0x7: /* Volume slide up */ - channel->xm_volslide = value; - break; - case 0x8: /* Fine volume slide down */ - channel->volume -= value; - if (channel->volume > 64) channel->volume = 0; - break; - case 0x9: /* Fine volume slide up */ - channel->volume += value; - if (channel->volume > 64) channel->volume = 64; - break; - case 0xA: /* Set vibrato speed */ - if (value) - channel->lastHspeed = value; - if (channel->playing) - channel->playing->vibrato_speed = channel->lastHspeed; - break; - case 0xB: /* Vibrato */ - if (value) - channel->lastHdepth = value << 2; /** WARNING: correct ? */ - if (channel->playing) { - channel->playing->vibrato_depth = channel->lastHdepth; - channel->playing->vibrato_speed = channel->lastHspeed; - channel->playing->vibrato_n++; - } - break; - case 0xC: /* Set panning */ - channel->truepan = 32 + value*(17*64); - break; - case 0xD: /* Pan slide left */ - /* -128 is a special case for emulating a 'feature' in FT2. - * As soon as effects are processed, it goes hard left. - */ - channel->panslide = value ? -value : -128; - break; - case 0xE: /* Pan slide Right */ - channel->panslide = value; - break; - case 0xF: /* Tone porta */ - break; - default: /* Volume */ - channel->volume = entry->volpan - 0x10; - break; - } - } - - if (playing) free_playing(sigrenderer, playing); -} - - - -/* This function assumes !IT_IS_END_ROW(entry). */ -static int process_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) -{ - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - - if (sigdata->flags & IT_WAS_AN_XM) - process_xm_note_data(sigrenderer, entry); - else - if (process_it_note_data(sigrenderer, entry)) return 0; - - return process_effects(sigrenderer, entry, ignore_cxx); -} - - - -static int process_entry(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) -{ - IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; - - if (entry->mask & IT_ENTRY_NOTE) - channel->note = entry->note; - - if ((entry->mask & (IT_ENTRY_NOTE|IT_ENTRY_EFFECT)) && (sigrenderer->sigdata->flags & IT_WAS_A_669)) { - reset_channel_effects(channel); - // XXX unknown - if (channel->playing) channel->playing->finetune = 0; - } - - if ((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_S) { - /* channel->lastS was set in update_pattern_variables(). */ - unsigned char effectvalue = channel->lastS; - if (effectvalue >> 4 == IT_S_NOTE_DELAY) { - channel->note_delay_count = effectvalue & 15; - if (channel->note_delay_count == 0) - channel->note_delay_count = 1; - channel->note_delay_entry = entry; - return 0; - } - } - - return process_note_data(sigrenderer, entry, ignore_cxx); -} - - - -static void update_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer) -{ - int i; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - IT_CHANNEL *channel = &sigrenderer->channel[i]; - - if (channel->key_off_count) { - channel->key_off_count--; - if (channel->key_off_count == 0) - xm_note_off(sigrenderer->sigdata, channel); - } else if (channel->note_cut_count) { - channel->note_cut_count--; - if (channel->note_cut_count == 0) { - if (sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_PTM)) - channel->volume = 0; - else if (channel->playing) { - int i; - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (!sigrenderer->playing[i]) { - channel->playing->declick_stage = 3; - sigrenderer->playing[i] = channel->playing; - channel->playing = NULL; - break; - } - } - if (channel->playing) { - free_playing(sigrenderer, channel->playing); - channel->playing = NULL; - } - } - } - } else if (channel->note_delay_count) { - channel->note_delay_count--; - if (channel->note_delay_count == 0) - process_note_data(sigrenderer, channel->note_delay_entry, 0); - /* Don't bother checking the return value; if the note - * was delayed, there can't have been a speed=0. - */ - } - } -} - - - -static int envelope_get_y(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) -{ -#if 1 - (void)envelope; //TODO: remove the parameter - return pe->value; -#else - int ys, ye; - int ts, te; - int t; - - if (pe->next_node <= 0) - return envelope->node_y[0] << IT_ENVELOPE_SHIFT; - - if (pe->next_node >= envelope->n_nodes) - return envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT; - - ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT; - ts = envelope->node_t[pe->next_node-1]; - te = envelope->node_t[pe->next_node]; - - if (ts == te) - return ys; - - ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT; - - t = pe->tick; - - return ys + (ye - ys) * (t - ts) / (te - ts); -#endif -} - - - -#if 0 -static int it_envelope_end(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) -{ - if (pe->next_node >= envelope->n_nodes) - return 1; - - if (pe->tick < envelope->node_t[pe->next_node]) return 0; - - if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && - envelope->loop_end >= pe->next_node && - envelope->node_t[envelope->loop_end] <= pe->tick) return 0; - - if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && - !(playing->flags & IT_PLAYING_SUSTAINOFF) && - envelope->sus_loop_end >= pe->next_node && - envelope->node_t[envelope->sus_loop_end] <= pe->tick) return 0; - - if (envelope->node_t[envelope->n_nodes-1] <= pe->tick) return 1; - - return 0; -} -#endif - - - -/* Returns 1 when fading should be initiated for a volume envelope. */ -static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe, int flags) -{ - if (!(playing->enabled_envelopes & flags) || !envelope->n_nodes) - return 0; - - ASSERT(envelope->n_nodes > 0); - - if (pe->tick <= 0) - pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT; - else if (pe->tick >= envelope->node_t[envelope->n_nodes-1]) { - pe->value = envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT; - } else { - int ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT; - int ts = envelope->node_t[pe->next_node-1]; - int te = envelope->node_t[pe->next_node]; - - if (ts == te) - pe->value = ys; - else { - int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT; - int t = pe->tick; - - pe->value = ys + (ye - ys) * (t - ts) / (te - ts); - } - } - - pe->tick++; - - recalculate_it_envelope_node(pe, envelope); - - if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { - if (pe->tick > envelope->node_t[envelope->sus_loop_end]) { - pe->next_node = envelope->sus_loop_start + 1; - ASSERT(pe->next_node <= envelope->n_nodes); - pe->tick = envelope->node_t[envelope->sus_loop_start]; - return 0; - } - } else if (envelope->flags & IT_ENVELOPE_LOOP_ON) { - if (pe->tick > envelope->node_t[envelope->loop_end]) { - pe->next_node = envelope->loop_start + 1; - ASSERT(pe->next_node <= envelope->n_nodes); - pe->tick = envelope->node_t[envelope->loop_start]; - return 0; - } - } - else if (pe->tick > envelope->node_t[envelope->n_nodes - 1]) - return 1; - - return 0; -} - - - -static void update_it_envelopes(IT_PLAYING *playing) -{ - IT_ENVELOPE *envelope = &playing->env_instrument->volume_envelope; - IT_PLAYING_ENVELOPE *pe = &playing->volume_envelope; - - if (update_it_envelope(playing, envelope, pe, IT_ENV_VOLUME)) { - playing->flags |= IT_PLAYING_FADING; - if (pe->value == 0) - playing->flags |= IT_PLAYING_DEAD; - } - - update_it_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope, IT_ENV_PANNING); - update_it_envelope(playing, &playing->env_instrument->pitch_envelope, &playing->pitch_envelope, IT_ENV_PITCH); -} - - - -static int xm_envelope_is_sustaining(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) -{ - if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) - if (envelope->sus_loop_start < envelope->n_nodes) - if (pe->tick == envelope->node_t[envelope->sus_loop_start]) - return 1; - return 0; -} - - - -static void update_xm_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) -{ - if (!(envelope->flags & IT_ENVELOPE_ON)) - return; - - if (xm_envelope_is_sustaining(playing, envelope, pe)) - return; - - if (pe->tick >= envelope->node_t[envelope->n_nodes-1]) - return; - - pe->tick++; - - /* pe->next_node must be kept up to date for envelope_get_y(). */ - while (pe->tick > envelope->node_t[pe->next_node]) - pe->next_node++; - - if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && envelope->loop_end < envelope->n_nodes) { - if (pe->tick == envelope->node_t[envelope->loop_end]) { - pe->next_node = MID(0, envelope->loop_start, envelope->n_nodes - 1); - pe->tick = envelope->node_t[pe->next_node]; - } - } - - xm_envelope_calculate_value(envelope, pe); -} - - - -static void update_xm_envelopes(IT_PLAYING *playing) -{ - update_xm_envelope(playing, &playing->env_instrument->volume_envelope, &playing->volume_envelope); - update_xm_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope); -} - - - -static void update_fadeout(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing) -{ - if (playing->flags & IT_PLAYING_FADING) { - playing->fadeoutcount -= playing->env_instrument->fadeout; - if (playing->fadeoutcount <= 0) { - playing->fadeoutcount = 0; - if (!(sigdata->flags & IT_WAS_AN_XM)) - playing->flags |= IT_PLAYING_DEAD; - } - } -} - -static int apply_pan_envelope(IT_PLAYING *playing); -static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, double volume); - -static void playing_volume_setup(DUMB_IT_SIGRENDERER * sigrenderer, IT_PLAYING * playing, float invt2g) -{ - DUMB_IT_SIGDATA * sigdata = sigrenderer->sigdata; - int pan; - float vol, span; - float rampScale; - int ramp_style = sigrenderer->ramp_style; - - pan = apply_pan_envelope(playing); - - if ((sigrenderer->n_channels >= 2) && (sigdata->flags & IT_STEREO) && (sigrenderer->n_channels != 3 || !IT_IS_SURROUND_SHIFTED(pan))) { - if (!IT_IS_SURROUND_SHIFTED(pan)) { - span = (pan - (32<<8)) * sigdata->pan_separation * (1.0f / ((32<<8) * 128)); - vol = 0.5f * (1.0f - span); - playing->float_volume[0] = vol; - playing->float_volume[1] = 1.0f - vol; - } else { - playing->float_volume[0] = -0.5f; - playing->float_volume[1] = 0.5f; - } - } else { - playing->float_volume[0] = 1.0f; - playing->float_volume[1] = 1.0f; - } - - vol = calculate_volume(sigrenderer, playing, 1.0f); - playing->float_volume[0] *= vol; - playing->float_volume[1] *= vol; - - rampScale = 4; - - if (ramp_style > 0 && playing->declick_stage == 2) { - if ((playing->ramp_volume[0] == 0 && playing->ramp_volume[1] == 0) || vol == 0) - rampScale = 48; - } - - if (ramp_style == 0 || (ramp_style < 2 && playing->declick_stage == 2)) { - if (playing->declick_stage <= 2) { - playing->ramp_volume[0] = playing->float_volume[0]; - playing->ramp_volume[1] = playing->float_volume[1]; - playing->declick_stage = 2; - } else { - playing->float_volume[0] = 0; - playing->float_volume[1] = 0; - playing->ramp_volume[0] = 0; - playing->ramp_volume[1] = 0; - playing->declick_stage = 5; - } - playing->ramp_delta[0] = 0; - playing->ramp_delta[1] = 0; - } else { - if (playing->declick_stage == 0) { - playing->ramp_volume[0] = 0; - playing->ramp_volume[1] = 0; - rampScale = 48; - playing->declick_stage++; - } else if (playing->declick_stage == 1) { - rampScale = 48; - } else if (playing->declick_stage >= 3) { - playing->float_volume[0] = 0; - playing->float_volume[1] = 0; - if (playing->declick_stage == 3) - playing->declick_stage++; - rampScale = 48; - } - playing->ramp_delta[0] = rampScale * invt2g * (playing->float_volume[0] - playing->ramp_volume[0]); - playing->ramp_delta[1] = rampScale * invt2g * (playing->float_volume[1] - playing->ramp_volume[1]); - } -} - -static void process_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float invt2g) -{ - DUMB_IT_SIGDATA * sigdata = sigrenderer->sigdata; - - if (playing->instrument) { - if (sigdata->flags & IT_WAS_AN_XM) - update_xm_envelopes(playing); - else - update_it_envelopes(playing); - update_fadeout(sigdata, playing); - } - - playing_volume_setup(sigrenderer, playing, invt2g); - - if (sigdata->flags & IT_WAS_AN_XM) { - /* 'depth' is used to store the tick number for XM files. */ - if (playing->sample_vibrato_depth < playing->sample->vibrato_rate) - playing->sample_vibrato_depth++; - } else { - playing->sample_vibrato_depth += playing->sample->vibrato_rate; - if (playing->sample_vibrato_depth > playing->sample->vibrato_depth << 8) - playing->sample_vibrato_depth = playing->sample->vibrato_depth << 8; - } - - playing->sample_vibrato_time += playing->sample->vibrato_speed; -} - -// Apparently some GCCs have problems here so renaming the function sounds like a better idea. -//#if defined(_MSC_VER) && _MSC_VER < 1800 -static double mylog2(double x) {return log(x)/log(2.0);} -//#endif - -static int delta_to_note(float delta, int base) -{ - double note; - note = mylog2(delta * 65536.f / (float)base)*12.0f+60.5f; - if (note > 119) note = 119; - else if (note < 0) note = 0; - return (int)note; -} - -#if 0 -// Period table for Protracker octaves 0-5: -static const unsigned short ProTrackerPeriodTable[6*12] = -{ - 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907, - 856,808,762,720,678,640,604,570,538,508,480,453, - 428,404,381,360,339,320,302,285,269,254,240,226, - 214,202,190,180,170,160,151,143,135,127,120,113, - 107,101,95,90,85,80,75,71,67,63,60,56, - 53,50,47,45,42,40,37,35,33,31,30,28 -}; - - -static const unsigned short ProTrackerTunedPeriods[16*12] = -{ - 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907, - 1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900, - 1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894, - 1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888, - 1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882, - 1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874, - 1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868, - 1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862, - 1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960, - 1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954, - 1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948, - 1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940, - 1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934, - 1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926, - 1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920, - 1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914 -}; -#endif - -static void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer) -{ - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - int i; - - float invt2g = 1.0f / ((float)TICK_TIME_DIVIDEND / (float)sigrenderer->tempo / 256.0f); - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - IT_CHANNEL *channel = &sigrenderer->channel[i]; - IT_PLAYING *playing = channel->playing; - - if (playing) { - int vibrato_shift; - switch (playing->vibrato_waveform) - { - default: - vibrato_shift = it_sine[playing->vibrato_time]; - break; - case 1: - vibrato_shift = it_sawtooth[playing->vibrato_time]; - break; - case 2: - vibrato_shift = it_squarewave[playing->vibrato_time]; - break; - case 3: - vibrato_shift = (rand() % 129) - 64; - break; - case 4: - vibrato_shift = it_xm_squarewave[playing->vibrato_time]; - break; - case 5: - vibrato_shift = it_xm_ramp[playing->vibrato_time]; - break; - case 6: - vibrato_shift = it_xm_ramp[255-playing->vibrato_time]; - break; - } - vibrato_shift *= playing->vibrato_n; - vibrato_shift *= playing->vibrato_depth; - vibrato_shift >>= 4; - - if (sigdata->flags & IT_OLD_EFFECTS) - vibrato_shift = -vibrato_shift; - - playing->volume = channel->volume; - playing->pan = channel->truepan; - - if (playing->volume_offset) { - playing->volume += (playing->volume_offset * playing->volume) >> 7; - if (playing->volume > 64) { - if (playing->volume_offset < 0) playing->volume = 0; - else playing->volume = 64; - } - } - - if (playing->panning_offset && !IT_IS_SURROUND_SHIFTED(playing->pan)) { - playing->pan += playing->panning_offset << IT_ENVELOPE_SHIFT; - if (playing->pan > 64 << IT_ENVELOPE_SHIFT) { - if (playing->panning_offset < 0) playing->pan = 0; - else playing->pan = 64 << IT_ENVELOPE_SHIFT; - } - } - - if (sigdata->flags & IT_LINEAR_SLIDES) { - int currpitch = ((playing->note - 60) << 8) + playing->slide - + vibrato_shift - + playing->finetune; - - /* We add a feature here, which is that of keeping the pitch - * within range. Otherwise it crashes. Trust me. It happened. - * The limit 32768 gives almost 11 octaves either way. - */ - if (currpitch < -32768) - currpitch = -32768; - else if (currpitch > 32767) - currpitch = 32767; - - playing->delta = (float)pow(DUMB_PITCH_BASE, currpitch); - playing->delta *= playing->sample->C5_speed * (1.f / 65536.0f); - } else { - int slide = playing->slide + vibrato_shift; - - playing->delta = (float)pow(DUMB_PITCH_BASE, ((60 - playing->note) << 8) - playing->finetune ); - /* playing->delta is 1.0 for C-5, 0.5 for C-6, etc. */ - - playing->delta *= 1.0f / playing->sample->C5_speed; - - playing->delta -= slide / AMIGA_DIVISOR; - - if (playing->delta < (1.0f / 65536.0f) / 32768.0f) { - // Should XM notes die if Amiga slides go out of range? - playing->flags |= IT_PLAYING_DEAD; - playing->delta = 1. / 32768.; - continue; - } - - playing->delta = (1.0f / 65536.0f) / playing->delta; - } - - if (playing->channel->glissando && playing->channel->toneporta && playing->channel->destnote < 120) { - playing->delta = (float)pow(DUMB_SEMITONE_BASE, delta_to_note(playing->delta, playing->sample->C5_speed) - 60) - * playing->sample->C5_speed * (1.f / 65536.f); - } - - /* - if ( channel->arpeggio ) { // another FT2 bug... - if ((sigdata->flags & (IT_LINEAR_SLIDES|IT_WAS_AN_XM|IT_WAS_A_MOD)) == (IT_WAS_AN_XM|IT_LINEAR_SLIDES) && - playing->flags & IT_PLAYING_SUSTAINOFF) - { - if ( channel->arpeggio > 0xFF ) - playing->delta = playing->sample->C5_speed * (1.f / 65536.f); - } - else*/ - { - int tick = sigrenderer->tick - 1; - if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD))!=IT_WAS_AN_XM) - tick = sigrenderer->speed - tick - 1; - else if (tick == sigrenderer->speed - 1) - tick = 0; - else - ++tick; - playing->delta *= (float)pow(DUMB_SEMITONE_BASE, channel->arpeggio_offsets[channel->arpeggio_table[tick&31]]); - } - /* - }*/ - - playing->filter_cutoff = channel->filter_cutoff; - playing->filter_resonance = channel->filter_resonance; - } - } - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing) { - process_playing(sigrenderer, sigrenderer->channel[i].playing, invt2g); - if (!(sigdata->flags & IT_WAS_AN_XM)) { - //if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) { - // This change was made so Gxx would work correctly when a note faded out or whatever. Let's hope nothing else was broken by it. - if (sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD) { - free_playing(sigrenderer, sigrenderer->channel[i].playing); - sigrenderer->channel[i].playing = NULL; - } - } - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]) { - process_playing(sigrenderer, sigrenderer->playing[i], invt2g); - if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) { - free_playing(sigrenderer, sigrenderer->playing[i]); - sigrenderer->playing[i] = NULL; - } - } - } -} - - - -static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) -{ - DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; - - // Set note vol/freq to vol/freq set for each channel - - if (sigrenderer->speed && --sigrenderer->tick == 0) { - reset_tick_counts(sigrenderer); - sigrenderer->tick = sigrenderer->speed; - sigrenderer->rowcount--; - if (sigrenderer->rowcount == 0) { - sigrenderer->rowcount = 1; - -#ifdef BIT_ARRAY_BULLSHIT - if (sigrenderer->n_rows) - { -#if 1 - /* - if (bit_array_test(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row)) - { - if (sigrenderer->callbacks->loop) { - if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data)) - return 1; - bit_array_reset(sigrenderer->played); - if (sigrenderer->speed == 0) - goto speed0; // I love goto - } - } - */ -#endif - bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); - { - int n; - for (n = 0; n < DUMB_IT_N_CHANNELS; n++) - { - IT_CHANNEL * channel = &sigrenderer->channel[n]; - if (channel->played_patjump) - { - if (channel->played_patjump_order == sigrenderer->order) - { - bit_array_set(channel->played_patjump, sigrenderer->row); - } - /* - else if ((channel->played_patjump_order & 0x7FFF) == sigrenderer->order) - { - channel->played_patjump_order |= 0x4000; - } - else if ((channel->played_patjump_order & 0x3FFF) == sigrenderer->order) - { - if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) - { - // joy, was XM, pattern loop bug triggered break to row in same order - bit_array_mask(sigrenderer->played, channel->played_patjump, sigrenderer->order * 256); - } - bit_array_destroy(channel->played_patjump); - channel->played_patjump = 0; - channel->played_patjump_order = 0xFFFE; - } - */ - else - { - bit_array_destroy(channel->played_patjump); - channel->played_patjump = 0; - channel->played_patjump_order = 0xFFFE; - } - } - } - } - } -#endif - - sigrenderer->processrow++; - - if (sigrenderer->processrow >= sigrenderer->n_rows) { - IT_PATTERN *pattern; - int n; - int processorder = sigrenderer->processorder; - - if ((sigrenderer->processrow|0xC00) == 0xFFFE + 1) { /* It was incremented above! */ - sigrenderer->processrow = sigrenderer->breakrow; - sigrenderer->breakrow = 0; - for (n = 0; n < DUMB_IT_N_CHANNELS; n++) sigrenderer->channel[n].pat_loop_end_row = 0; - } else { - sigrenderer->processrow = sigrenderer->breakrow; - sigrenderer->breakrow = 0; // XXX lolwut - } - - if (sigrenderer->processorder == 0xFFFF) - sigrenderer->processorder = sigrenderer->order - 1; - - for (;;) { - sigrenderer->processorder++; - - if (sigrenderer->processorder >= sigdata->n_orders) { - sigrenderer->processorder = sigrenderer->restart_position; - if (sigrenderer->processorder >= sigdata->n_orders) { - /* Restarting beyond end. We'll loop for now. */ - sigrenderer->processorder = -1; - continue; - } - if (sigdata->flags & IT_WAS_AN_OKT) { - /* Reset some things */ - sigrenderer->speed = sigdata->speed; - sigrenderer->tempo = sigdata->tempo; - for (n = 0; n < DUMB_IT_N_CHANNELS; n++) { - xm_note_off(sigdata, &sigrenderer->channel[n]); - } - } - } - - n = sigdata->order[sigrenderer->processorder]; - - if (n < sigdata->n_patterns) - break; - -#ifdef INVALID_ORDERS_END_SONG - if (n != IT_ORDER_SKIP) -#else - if (n == IT_ORDER_END) -#endif - { - sigrenderer->processorder = sigrenderer->restart_position - 1; - } - -#ifdef BIT_ARRAY_BULLSHIT - /* Fix play tracking and timekeeping for orders containing skip commands */ - for (n = 0; n < 256; n++) { - bit_array_set(sigrenderer->played, sigrenderer->processorder * 256 + n); - } -#endif - } - - pattern = &sigdata->pattern[n]; - - n = sigrenderer->n_rows; - sigrenderer->n_rows = pattern->n_rows; - - if (sigrenderer->processrow >= sigrenderer->n_rows) - sigrenderer->processrow = 0; - -/** WARNING - everything pertaining to a new pattern initialised? */ - - sigrenderer->entry = sigrenderer->entry_start = pattern->entry; - sigrenderer->entry_end = sigrenderer->entry + pattern->n_entries; - - /* If n_rows was 0, we're only just starting. Don't do anything weird here. */ - /* added: process row check, for break to row spooniness */ - if (n && (processorder == 0xFFFF ? sigrenderer->order > sigrenderer->processorder : sigrenderer->order >= sigrenderer->processorder) -#ifdef BIT_ARRAY_BULLSHIT - && bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow) -#endif - ) { - if (sigrenderer->callbacks->loop) { - if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data)) - return 1; -#ifdef BIT_ARRAY_BULLSHIT - bit_array_reset(sigrenderer->played); -#endif - if (sigrenderer->speed == 0) - goto speed0; /* I love goto */ - } - } - sigrenderer->order = sigrenderer->processorder; - - n = sigrenderer->processrow; - while (n) { - while (sigrenderer->entry < sigrenderer->entry_end) { - if (IT_IS_END_ROW(sigrenderer->entry)) { - sigrenderer->entry++; - break; - } - sigrenderer->entry++; - } - n--; - } - sigrenderer->row = sigrenderer->processrow; - } else { - if (sigrenderer->entry) { - while (sigrenderer->entry < sigrenderer->entry_end) { - if (IT_IS_END_ROW(sigrenderer->entry)) { - sigrenderer->entry++; - break; - } - sigrenderer->entry++; - } - sigrenderer->row++; - } else { -#ifdef BIT_ARRAY_BULLSHIT - bit_array_clear(sigrenderer->played, sigrenderer->order * 256); -#endif - sigrenderer->entry = sigrenderer->entry_start; - sigrenderer->row = 0; - } - } - - if (!(sigdata->flags & IT_WAS_A_669)) - reset_effects(sigrenderer); - - { - IT_ENTRY *entry = sigrenderer->entry; - int ignore_cxx = 0; - - while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry)) - ignore_cxx |= update_pattern_variables(sigrenderer, entry++); - - entry = sigrenderer->entry; - - while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry)) - if (process_entry(sigrenderer, entry++, sigdata->flags & IT_WAS_AN_XM ? 0 : ignore_cxx)) - return 1; - } - - if (sigdata->flags & IT_WAS_AN_OKT) - update_effects(sigrenderer); - else if (!(sigdata->flags & IT_OLD_EFFECTS)) - update_smooth_effects(sigrenderer); - } else { - { - IT_ENTRY *entry = sigrenderer->entry; - - while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry)) { - if (entry->mask & IT_ENTRY_EFFECT && entry->effect != IT_SET_SAMPLE_OFFSET) - process_effects(sigrenderer, entry, 0); - /* Don't bother checking the return value; if there - * was a pattern delay, there can't be a speed=0. - */ - entry++; - } - } - - update_effects(sigrenderer); - } - } else { - if ( !(sigdata->flags & IT_WAS_AN_STM) || !(sigrenderer->tick & 15)) { - speed0: - update_effects(sigrenderer); - update_tick_counts(sigrenderer); - } - } - - if (sigrenderer->globalvolume == 0) { - if (sigrenderer->callbacks->global_volume_zero) { - LONG_LONG t = sigrenderer->gvz_sub_time + ((TICK_TIME_DIVIDEND / (sigrenderer->tempo << 8)) << 16); - sigrenderer->gvz_time += (int)(t >> 16); - sigrenderer->gvz_sub_time = (int)t & 65535; - if (sigrenderer->gvz_time >= 65536 * 12) { - if ((*sigrenderer->callbacks->global_volume_zero)(sigrenderer->callbacks->global_volume_zero_data)) - return 1; - } - } - } else { - if (sigrenderer->callbacks->global_volume_zero) { - sigrenderer->gvz_time = 0; - sigrenderer->gvz_sub_time = 0; - } - } - - process_all_playing(sigrenderer); - - { - LONG_LONG t = (TICK_TIME_DIVIDEND / (sigrenderer->tempo << 8)) << 16; - if ( sigrenderer->sigdata->flags & IT_WAS_AN_STM ) { - t /= 16; - } - t += sigrenderer->sub_time_left; - sigrenderer->time_left += (int)(t >> 16); - sigrenderer->sub_time_left = (int)t & 65535; - } - - return 0; -} - - - -int dumb_it_max_to_mix = 64; - -#if 0 -static const int aiMODVol[] = -{ - 0, - 16, 24, 32, 48, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 208, 224, 240, - 256, 272, 288, 304, 320, 336, 352, 368, - 384, 400, 416, 432, 448, 464, 480, 496, - 529, 545, 561, 577, 593, 609, 625, 641, - 657, 673, 689, 705, 721, 737, 753, 769, - 785, 801, 817, 833, 849, 865, 881, 897, - 913, 929, 945, 961, 977, 993, 1009, 1024 -}; -#endif - -static const int aiPTMVolScaled[] = -{ - 0, - 31, 54, 73, 96, 111, 130, 153, 172, - 191, 206, 222, 237, 252, 275, 298, 317, - 336, 351, 370, 386, 401, 416, 428, 443, - 454, 466, 477, 489, 512, 531, 553, 573, - 592, 611, 626, 645, 660, 679, 695, 710, - 725, 740, 756, 767, 782, 798, 809, 820, - 836, 847, 859, 870, 881, 897, 908, 916, - 927, 939, 950, 962, 969, 983, 1005, 1024 -}; - -static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, double volume) -{ - if (volume != 0) { - int vol; - - if (playing->channel->flags & IT_CHANNEL_MUTED) - return 0; - - if ((playing->channel->tremor_time & 192) == 128) - return 0; - - switch (playing->tremolo_waveform) - { - default: - vol = it_sine[playing->tremolo_time]; - break; - case 1: - vol = it_sawtooth[playing->tremolo_time]; - break; - case 2: - vol = it_squarewave[playing->tremolo_time]; - break; - case 3: - vol = (rand() % 129) - 64; - break; - case 4: - vol = it_xm_squarewave[playing->tremolo_time]; - break; - case 5: - vol = it_xm_ramp[playing->tremolo_time]; - break; - case 6: - vol = it_xm_ramp[255-((sigrenderer->sigdata->flags & IT_WAS_A_MOD)?playing->vibrato_time:playing->tremolo_time)]; - break; - } - vol *= playing->tremolo_depth; - - vol = (playing->volume << 5) + vol; - - if (vol <= 0) - return 0; - - if (vol > 64 << 5) - vol = 64 << 5; - - if ( sigrenderer->sigdata->flags & IT_WAS_A_PTM ) - { - int v = aiPTMVolScaled[ vol >> 5 ]; - if ( vol < 64 << 5 ) - { - int f = vol & ( ( 1 << 5 ) - 1 ); - int f2 = ( 1 << 5 ) - f; - int v2 = aiPTMVolScaled[ ( vol >> 5 ) + 1 ]; - v = ( v * f2 + v2 * f ) >> 5; - } - vol = v << 1; - } - - volume *= vol; /* 64 << 5 */ - volume *= playing->sample->global_volume; /* 64 */ - volume *= playing->channel_volume; /* 64 */ - volume *= sigrenderer->globalvolume; /* 128 */ - volume *= sigrenderer->sigdata->mixing_volume; /* 128 */ - volume *= 1.0f / ((64 << 5) * 64.0f * 64.0f * 128.0f * 128.0f); - - if (volume && playing->instrument) { - if (playing->enabled_envelopes & IT_ENV_VOLUME && playing->env_instrument->volume_envelope.n_nodes) { - volume *= envelope_get_y(&playing->env_instrument->volume_envelope, &playing->volume_envelope); - volume *= 1.0f / (64 << IT_ENVELOPE_SHIFT); - } - volume *= playing->instrument->global_volume; /* 128 */ - volume *= playing->fadeoutcount; /* 1024 */ - volume *= 1.0f / (128.0f * 1024.0f); - } - } - - return (float)volume; -} - - - -static int apply_pan_envelope(IT_PLAYING *playing) -{ - if (playing->pan <= 64 << IT_ENVELOPE_SHIFT) { - int pan; - if (playing->panbrello_depth) { - switch (playing->panbrello_waveform) { - default: - pan = it_sine[playing->panbrello_time]; - break; - case 1: - pan = it_sawtooth[playing->panbrello_time]; - break; - case 2: - pan = it_squarewave[playing->panbrello_time]; - break; - case 3: - pan = playing->panbrello_random; - break; - } - pan *= playing->panbrello_depth << 3; - - pan += playing->pan; - if (pan < 0) pan = 0; - else if (pan > 64 << IT_ENVELOPE_SHIFT) pan = 64 << IT_ENVELOPE_SHIFT; - } else { - pan = playing->pan; - } - - if (playing->env_instrument && (playing->enabled_envelopes & IT_ENV_PANNING)) { - int p = envelope_get_y(&playing->env_instrument->pan_envelope, &playing->pan_envelope); - if (pan > 32 << IT_ENVELOPE_SHIFT) - p *= (64 << IT_ENVELOPE_SHIFT) - pan; - else - p *= pan; - pan += p >> (5 + IT_ENVELOPE_SHIFT); - } - return pan; - } - return playing->pan; -} - - -/* Note: if a click remover is provided, and store_end_sample is set, then - * the end point will be computed twice. This situation should not arise. - */ -static int32 render_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, double volume, double main_delta, double delta, int32 pos, int32 size, sample_t **samples, int store_end_sample, int *left_to_mix) -{ - int bits; - - int32 size_rendered; - - DUMB_VOLUME_RAMP_INFO lvol, rvol; - - if (playing->flags & IT_PLAYING_DEAD) - return 0; - - if (*left_to_mix <= 0) - volume = 0; - - { - int quality = sigrenderer->resampling_quality; - if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality) - quality = playing->sample->max_resampling_quality; - playing->resampler.quality = quality; - resampler_set_quality(playing->resampler.fir_resampler[0], quality - DUMB_RESAMPLER_BASE); - resampler_set_quality(playing->resampler.fir_resampler[1], quality - DUMB_RESAMPLER_BASE); - } - - bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8; - - if (volume == 0) { - if (playing->sample->flags & IT_SAMPLE_STEREO) - size_rendered = dumb_resample_n_2_2(bits, &playing->resampler, NULL, size, 0, 0, delta); - else - size_rendered = dumb_resample_n_1_2(bits, &playing->resampler, NULL, size, 0, 0, delta); - } else { - lvol.volume = playing->ramp_volume [0]; - rvol.volume = playing->ramp_volume [1]; - lvol.delta = (float)(playing->ramp_delta [0] * main_delta); - rvol.delta = (float)(playing->ramp_delta [1] * main_delta); - lvol.target = playing->float_volume [0]; - rvol.target = playing->float_volume [1]; - rvol.mix = lvol.mix = (float)volume; - lvol.declick_stage = rvol.declick_stage = playing->declick_stage; - if (sigrenderer->n_channels >= 2) { - if (playing->sample->flags & IT_SAMPLE_STEREO) { - if (sigrenderer->click_remover) { - sample_t click[2]; - dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click); - dumb_record_click(sigrenderer->click_remover[0], pos, click[0]); - dumb_record_click(sigrenderer->click_remover[1], pos, click[1]); - } - size_rendered = dumb_resample_n_2_2(bits, &playing->resampler, samples[0] + pos*2, size, &lvol, &rvol, delta); - if (store_end_sample) { - sample_t click[2]; - dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click); - samples[0][(pos + size_rendered) * 2] = click[0]; - samples[0][(pos + size_rendered) * 2 + 1] = click[1]; - } - if (sigrenderer->click_remover) { - sample_t click[2]; - dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click); - dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]); - dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]); - } - } else { - if (sigrenderer->click_remover) { - sample_t click[2]; - dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click); - dumb_record_click(sigrenderer->click_remover[0], pos, click[0]); - dumb_record_click(sigrenderer->click_remover[1], pos, click[1]); - } - size_rendered = dumb_resample_n_1_2(bits, &playing->resampler, samples[0] + pos*2, size, &lvol, &rvol, delta); - if (store_end_sample) { - sample_t click[2]; - dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click); - samples[0][(pos + size_rendered) * 2] = click[0]; - samples[0][(pos + size_rendered) * 2 + 1] = click[1]; - } - if (sigrenderer->click_remover) { - sample_t click[2]; - dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click); - dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]); - dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]); - } - } - } -#if 0 // [RH] Don't need mono output - else { - if (playing->sample->flags & IT_SAMPLE_STEREO) { - if (sigrenderer->click_remover) { - sample_t click; - dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &click); - dumb_record_click(sigrenderer->click_remover[0], pos, click); - } - size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, &rvol, delta); - if (store_end_sample) - dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &samples[0][pos + size_rendered]); - if (sigrenderer->click_remover) { - sample_t click; - dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &click); - dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click); - } - } else { - if (sigrenderer->click_remover) { - sample_t click; - dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &click); - dumb_record_click(sigrenderer->click_remover[0], pos, click); - } - size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, delta); - if (store_end_sample) - dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &samples[0][pos + size_rendered]); - if (sigrenderer->click_remover) { - sample_t click; - dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &click); - dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click); - } - } - } -#endif - playing->ramp_volume [0] = lvol.volume; - playing->ramp_volume [1] = rvol.volume; - playing->declick_stage = (lvol.declick_stage > rvol.declick_stage) ? lvol.declick_stage : rvol.declick_stage; - if (playing->declick_stage >= 4) - playing->flags |= IT_PLAYING_DEAD; - (*left_to_mix)--; - } - - if (playing->resampler.dir == 0) - playing->flags |= IT_PLAYING_DEAD; - - return size_rendered; -} - -typedef struct IT_TO_MIX -{ - IT_PLAYING *playing; - float volume; -} -IT_TO_MIX; - - - -static int CDECL it_to_mix_compare(const void *e1, const void *e2) -{ - if (((const IT_TO_MIX *)e1)->volume > ((const IT_TO_MIX *)e2)->volume) - return -1; - - if (((const IT_TO_MIX *)e1)->volume < ((const IT_TO_MIX *)e2)->volume) - return 1; - - return 0; -} - - - -static void apply_pitch_modifications(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing, double *delta, int *cutoff) -{ - { - int sample_vibrato_shift; - switch (playing->sample_vibrato_waveform) - { - default: - sample_vibrato_shift = it_sine[playing->sample_vibrato_time]; - break; - case 1: - sample_vibrato_shift = it_sawtooth[playing->sample_vibrato_time]; - break; - case 2: - sample_vibrato_shift = it_squarewave[playing->sample_vibrato_time]; - break; - case 3: - sample_vibrato_shift = (rand() % 129) - 64; - break; - case 4: - sample_vibrato_shift = it_xm_squarewave[playing->sample_vibrato_time]; - break; - case 5: - sample_vibrato_shift = it_xm_ramp[playing->sample_vibrato_time]; - break; - case 6: - sample_vibrato_shift = it_xm_ramp[255-playing->sample_vibrato_time]; - break; - } - - if (sigdata->flags & IT_WAS_AN_XM) { - int depth = playing->sample->vibrato_depth; /* True depth */ - if (playing->sample->vibrato_rate) { - depth *= playing->sample_vibrato_depth; /* Tick number */ - depth /= playing->sample->vibrato_rate; /* XM sweep */ - } - sample_vibrato_shift *= depth; - } else - sample_vibrato_shift *= playing->sample_vibrato_depth >> 8; - - sample_vibrato_shift >>= 4; - - if (sample_vibrato_shift) { - if ((sigdata->flags & IT_LINEAR_SLIDES) || !(sigdata->flags & IT_WAS_AN_XM)) - *delta *= (float)pow(DUMB_PITCH_BASE, sample_vibrato_shift); - else { - /* complicated! */ - double scale = *delta / playing->delta; - - *delta = (1.0f / 65536.0f) / playing->delta; - - *delta -= sample_vibrato_shift / AMIGA_DIVISOR; - - if (*delta < (1.0f / 65536.0f) / 32767.0f) { - *delta = (1.0f / 65536.0f) / 32767.0f; - } - - *delta = (1.0f / 65536.0f) / *delta * scale; - } - } - } - - if (playing->env_instrument && - (playing->enabled_envelopes & IT_ENV_PITCH)) - { - int p = envelope_get_y(&playing->env_instrument->pitch_envelope, &playing->pitch_envelope); - if (playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_PITCH_IS_FILTER) - *cutoff = (*cutoff * (p+(32<> (6 + IT_ENVELOPE_SHIFT); - else - *delta *= (float)pow(DUMB_PITCH_BASE, p >> (IT_ENVELOPE_SHIFT - 7)); - } -} - - - -static void render_normal(DUMB_IT_SIGRENDERER *sigrenderer, double volume, double delta, int32 pos, int32 size, sample_t **samples) -{ - int i; - - int n_to_mix = 0; - IT_TO_MIX to_mix[DUMB_IT_TOTAL_CHANNELS]; - int left_to_mix = dumb_it_max_to_mix; - - sample_t **samples_to_filter = NULL; - - //int max_output = sigrenderer->max_output; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing && !(sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) { - to_mix[n_to_mix].playing = sigrenderer->channel[i].playing; - to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->channel[i].playing, volume); - n_to_mix++; - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]) { /* Won't be dead; it would have been freed. */ - to_mix[n_to_mix].playing = sigrenderer->playing[i]; - to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->playing[i], volume); - n_to_mix++; - } - } - - if (volume != 0) - qsort(to_mix, n_to_mix, sizeof(IT_TO_MIX), &it_to_mix_compare); - - for (i = 0; i < n_to_mix; i++) { - IT_PLAYING *playing = to_mix[i].playing; - double note_delta = delta * playing->delta; - int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT; - //int output = min( playing->output, max_output ); - - apply_pitch_modifications(sigrenderer->sigdata, playing, ¬e_delta, &cutoff); - - if (cutoff != 127 << IT_ENVELOPE_SHIFT || playing->filter_resonance != 0) { - playing->true_filter_cutoff = cutoff; - playing->true_filter_resonance = playing->filter_resonance; - } - - if (volume && (playing->true_filter_cutoff != 127 << IT_ENVELOPE_SHIFT || playing->true_filter_resonance != 0)) { - if (!samples_to_filter) { - samples_to_filter = allocate_sample_buffer(sigrenderer->n_channels, size + 1); - if (!samples_to_filter) { - render_playing(sigrenderer, playing, 0, delta, note_delta, pos, size, NULL, 0, &left_to_mix); - continue; - } - } - { - int32 size_rendered; - DUMB_CLICK_REMOVER **cr = sigrenderer->click_remover; - dumb_silence(samples_to_filter[0], sigrenderer->n_channels * (size + 1)); - sigrenderer->click_remover = NULL; - size_rendered = render_playing(sigrenderer, playing, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix); - sigrenderer->click_remover = cr; - if (sigrenderer->n_channels == 2) { - it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered, - 2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance); - it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[0 /*output*/]+1, pos, samples_to_filter[0]+1, size_rendered, - 2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance); - } else { - it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered, - 1, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance); - } - // FIXME: filtering is not prevented by low left_to_mix! - // FIXME: change 'warning' to 'FIXME' everywhere - } - } else { - it_reset_filter_state(&playing->filter_state[0]); - it_reset_filter_state(&playing->filter_state[1]); - render_playing(sigrenderer, playing, volume, delta, note_delta, pos, size, samples /*&samples[output]*/, 0, &left_to_mix); - } - } - - destroy_sample_buffer(samples_to_filter); - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing) { - //if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) { - // This change was made so Gxx would work correctly when a note faded out or whatever. Let's hope nothing else was broken by it. - if (sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD) { - free_playing(sigrenderer, sigrenderer->channel[i].playing); - sigrenderer->channel[i].playing = NULL; - } - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]) { - if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) { - free_playing(sigrenderer, sigrenderer->playing[i]); - sigrenderer->playing[i] = NULL; - } - } - } -} - - - -static void render_surround(DUMB_IT_SIGRENDERER *sigrenderer, double volume, double delta, int32 pos, int32 size, sample_t **samples) -{ - int i; - - int n_to_mix = 0, n_to_mix_surround = 0; - IT_TO_MIX to_mix[DUMB_IT_TOTAL_CHANNELS]; - IT_TO_MIX to_mix_surround[DUMB_IT_TOTAL_CHANNELS]; - int left_to_mix = dumb_it_max_to_mix; - - int saved_channels = sigrenderer->n_channels; - - sample_t **samples_to_filter = NULL; - - DUMB_CLICK_REMOVER **saved_cr = sigrenderer->click_remover; - - //int max_output = sigrenderer->max_output; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing && !(sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) { - IT_PLAYING *playing = sigrenderer->channel[i].playing; - IT_TO_MIX *_to_mix = IT_IS_SURROUND_SHIFTED(playing->pan) ? to_mix_surround + n_to_mix_surround++ : to_mix + n_to_mix++; - _to_mix->playing = playing; - _to_mix->volume = volume == 0 ? 0 : calculate_volume(sigrenderer, playing, volume); - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]) { /* Won't be dead; it would have been freed. */ - IT_PLAYING *playing = sigrenderer->playing[i]; - IT_TO_MIX *_to_mix = IT_IS_SURROUND_SHIFTED(playing->pan) ? to_mix_surround + n_to_mix_surround++ : to_mix + n_to_mix++; - _to_mix->playing = playing; - _to_mix->volume = volume == 0 ? 0 : calculate_volume(sigrenderer, playing, volume); - } - } - - if (volume != 0) { - qsort(to_mix, n_to_mix, sizeof(IT_TO_MIX), &it_to_mix_compare); - qsort(to_mix_surround, n_to_mix_surround, sizeof(IT_TO_MIX), &it_to_mix_compare); - } - - sigrenderer->n_channels = 2; - - for (i = 0; i < n_to_mix; i++) { - IT_PLAYING *playing = to_mix[i].playing; - double note_delta = delta * playing->delta; - int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT; - //int output = min( playing->output, max_output ); - - apply_pitch_modifications(sigrenderer->sigdata, playing, ¬e_delta, &cutoff); - - if (cutoff != 127 << IT_ENVELOPE_SHIFT || playing->filter_resonance != 0) { - playing->true_filter_cutoff = cutoff; - playing->true_filter_resonance = playing->filter_resonance; - } - - if (volume && (playing->true_filter_cutoff != 127 << IT_ENVELOPE_SHIFT || playing->true_filter_resonance != 0)) { - if (!samples_to_filter) { - samples_to_filter = allocate_sample_buffer(sigrenderer->n_channels, size + 1); - if (!samples_to_filter) { - render_playing(sigrenderer, playing, 0, delta, note_delta, pos, size, NULL, 0, &left_to_mix); - continue; - } - } - { - long size_rendered; - DUMB_CLICK_REMOVER **cr = sigrenderer->click_remover; - dumb_silence(samples_to_filter[0], sigrenderer->n_channels * (size + 1)); - sigrenderer->click_remover = NULL; - size_rendered = render_playing(sigrenderer, playing, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix); - sigrenderer->click_remover = cr; - it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered, - 2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance); - it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[0 /*output*/]+1, pos, samples_to_filter[0]+1, size_rendered, - 2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance); - } - } else { - it_reset_filter_state(&playing->filter_state[0]); - it_reset_filter_state(&playing->filter_state[1]); - render_playing(sigrenderer, playing, volume, delta, note_delta, pos, size, samples /*&samples[output]*/, 0, &left_to_mix); - } - } - - sigrenderer->n_channels = 1; - sigrenderer->click_remover = saved_cr ? saved_cr + 2 : 0; - - for (i = 0; i < n_to_mix_surround; i++) { - IT_PLAYING *playing = to_mix_surround[i].playing; - double note_delta = delta * playing->delta; - int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT; - //int output = min( playing->output, max_output ); - - apply_pitch_modifications(sigrenderer->sigdata, playing, ¬e_delta, &cutoff); - - if (cutoff != 127 << IT_ENVELOPE_SHIFT || playing->filter_resonance != 0) { - playing->true_filter_cutoff = cutoff; - playing->true_filter_resonance = playing->filter_resonance; - } - - if (volume && (playing->true_filter_cutoff != 127 << IT_ENVELOPE_SHIFT || playing->true_filter_resonance != 0)) { - if (!samples_to_filter) { - samples_to_filter = allocate_sample_buffer(sigrenderer->n_channels, size + 1); - if (!samples_to_filter) { - render_playing(sigrenderer, playing, 0, delta, note_delta, pos, size, NULL, 0, &left_to_mix); - continue; - } - } - { - long size_rendered; - DUMB_CLICK_REMOVER **cr = sigrenderer->click_remover; - dumb_silence(samples_to_filter[0], size + 1); - sigrenderer->click_remover = NULL; - size_rendered = render_playing(sigrenderer, playing, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix); - sigrenderer->click_remover = cr; - it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[1 /*output*/], pos, samples_to_filter[0], size_rendered, - 1, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance); - // FIXME: filtering is not prevented by low left_to_mix! - // FIXME: change 'warning' to 'FIXME' everywhere - } - } else { - it_reset_filter_state(&playing->filter_state[0]); - it_reset_filter_state(&playing->filter_state[1]); - render_playing(sigrenderer, playing, volume, delta, note_delta, pos, size, &samples[1], 0, &left_to_mix); - } - } - - sigrenderer->n_channels = saved_channels; - sigrenderer->click_remover = saved_cr; - - destroy_sample_buffer(samples_to_filter); - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing) { - //if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) { - // This change was made so Gxx would work correctly when a note faded out or whatever. Let's hope nothing else was broken by it. - if (sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD) { - free_playing(sigrenderer, sigrenderer->channel[i].playing); - sigrenderer->channel[i].playing = NULL; - } - } - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]) { - if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) { - free_playing(sigrenderer, sigrenderer->playing[i]); - sigrenderer->playing[i] = NULL; - } - } - } -} - - - -static void render(DUMB_IT_SIGRENDERER *sigrenderer, double volume, double delta, int32 pos, int32 size, sample_t **samples) -{ - if (size == 0) return; - if (sigrenderer->n_channels == 1 || sigrenderer->n_channels == 2) - render_normal(sigrenderer, volume, delta, pos, size, samples); - else if (sigrenderer->n_channels == 3) - render_surround(sigrenderer, volume, delta, pos, size, samples); -} - - - -static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder, IT_CALLBACKS *callbacks, DUMB_CLICK_REMOVER **cr) -{ - DUMB_IT_SIGRENDERER *sigrenderer; - int i; - - /* [RH] Mono destination mixers are disabled. */ - if (n_channels != 2) { - return NULL; - } - - if (startorder > sigdata->n_orders) { - free(callbacks); - dumb_destroy_click_remover_array(n_channels, cr); - return NULL; - } - - sigrenderer = malloc(sizeof(*sigrenderer)); - if (!sigrenderer) { - free(callbacks); - dumb_destroy_click_remover_array(n_channels, cr); - return NULL; - } - - sigrenderer->free_playing = NULL; - sigrenderer->callbacks = callbacks; - sigrenderer->click_remover = cr; - - sigrenderer->sigdata = sigdata; - sigrenderer->n_channels = n_channels; - sigrenderer->resampling_quality = dumb_resampling_quality; - sigrenderer->ramp_style = DUMB_IT_RAMP_FULL; - sigrenderer->globalvolume = sigdata->global_volume; - sigrenderer->tempo = sigdata->tempo; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - IT_CHANNEL *channel = &sigrenderer->channel[i]; -#if IT_CHANNEL_MUTED != 1 -#error this is wrong -#endif - channel->flags = sigdata->channel_pan[i] >> 7; - channel->volume = (sigdata->flags & IT_WAS_AN_XM) ? 0 : 64; - channel->pan = sigdata->channel_pan[i] & 0x7F; - channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; - channel->channelvolume = sigdata->channel_volume[i]; - channel->instrument = 0; - channel->sample = 0; - channel->note = IT_NOTE_OFF; - channel->SFmacro = 0; - channel->filter_cutoff = 127; - channel->filter_resonance = 0; - channel->new_note_action = 0xFF; - channel->xm_retrig = 0; - channel->retrig_tick = 0; - channel->tremor_time = 0; - channel->vibrato_waveform = 0; - channel->tremolo_waveform = 0; - channel->panbrello_waveform = 0; - channel->glissando = 0; - channel->toneslide = 0; - channel->ptm_toneslide = 0; - channel->ptm_last_toneslide = 0; - channel->okt_toneslide = 0; - channel->midi_state = 0; - channel->lastvolslide = 0; - channel->lastDKL = 0; - channel->lastEF = 0; - channel->lastG = 0; - channel->lastHspeed = 0; - channel->lastHdepth = 0; - channel->lastRspeed = 0; - channel->lastRdepth = 0; - channel->lastYspeed = 0; - channel->lastYdepth = 0; - channel->lastI = 0; - channel->lastJ = 0; - channel->lastN = 0; - channel->lastO = 0; - channel->high_offset = 0; - channel->lastP = 0; - channel->lastQ = 0; - channel->lastS = 0; - channel->pat_loop_row = 0; - channel->pat_loop_count = 0; - channel->pat_loop_end_row = 0; - channel->lastW = 0; - channel->xm_lastE1 = 0; - channel->xm_lastE2 = 0; - channel->xm_lastEA = 0; - channel->xm_lastEB = 0; - channel->xm_lastX1 = 0; - channel->xm_lastX2 = 0; - channel->inv_loop_delay = 0; - channel->inv_loop_speed = 0; - channel->inv_loop_offset = 0; - channel->playing = NULL; -#ifdef BIT_ARRAY_BULLSHIT - channel->played_patjump = NULL; - channel->played_patjump_order = 0xFFFE; -#endif - //channel->output = 0; - } - - if (sigdata->flags & IT_WAS_A_669) - reset_effects(sigrenderer); - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - sigrenderer->playing[i] = NULL; - - sigrenderer->speed = sigdata->speed; - - sigrenderer->processrow = 0xFFFE; - sigrenderer->n_rows = 0; - sigrenderer->breakrow = 0; - sigrenderer->rowcount = 1; - sigrenderer->order = startorder; - /* meh! - if (startorder > 0) { - int n; - for (n = startorder - 1; n >= 0; n--) { - if (sigdata->order[n] > sigdata->n_patterns) { - sigrenderer->restart_position = n + 1; - break; - } - } - } - */ - if (startorder > 0) { - sigrenderer->restart_position = startorder; - } else { - sigrenderer->restart_position = sigdata->restart_position; - } - - sigrenderer->row = 0; - sigrenderer->processorder = startorder - 1; - sigrenderer->tick = 1; - -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->played = bit_array_create(sigdata->n_orders * 256); -#endif - - { - int order; - for (order = 0; order < sigdata->n_orders; order++) { - int n = sigdata->order[order]; - if (n < sigdata->n_patterns) goto found_valid_order; -#ifdef INVALID_ORDERS_END_SONG - if (n != IT_ORDER_SKIP) -#else - if (n == IT_ORDER_END) -#endif - break; - -#ifdef BIT_ARRAY_BULLSHIT - /* Fix for played order detection for songs which have skips at the start of the orders list */ - for (n = 0; n < 256; n++) { - bit_array_set(sigrenderer->played, order * 256 + n); - } -#endif - } - /* If we get here, there were no valid orders in the song. */ - _dumb_it_end_sigrenderer(sigrenderer); - return NULL; - } - found_valid_order: - - sigrenderer->time_left = 0; - sigrenderer->sub_time_left = 0; - -#ifdef BIT_ARRAY_BULLSHIT - sigrenderer->played = bit_array_create(sigdata->n_orders * 256); -#endif - - sigrenderer->gvz_time = 0; - sigrenderer->gvz_sub_time = 0; - - //sigrenderer->max_output = 0; - - if ( !(sigdata->flags & IT_WAS_PROCESSED) ) { - dumb_it_add_lpc( sigdata ); - - sigdata->flags |= IT_WAS_PROCESSED; - } - - return sigrenderer; -} - - -void DUMBEXPORT dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality) -{ - if (sigrenderer && quality >= 0 && quality < DUMB_RQ_N_LEVELS) - { - int i; - sigrenderer->resampling_quality = quality; - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing) - { - IT_PLAYING * playing = sigrenderer->channel[i].playing; - playing->resampling_quality = quality; - playing->resampler.quality = quality; - resampler_set_quality(playing->resampler.fir_resampler[0], quality - DUMB_RESAMPLER_BASE); - resampler_set_quality(playing->resampler.fir_resampler[1], quality - DUMB_RESAMPLER_BASE); - } - } - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { - if (sigrenderer->playing[i]) { - IT_PLAYING * playing = sigrenderer->playing[i]; - playing->resampling_quality = quality; - playing->resampler.quality = quality; - resampler_set_quality(playing->resampler.fir_resampler[0], quality - DUMB_RESAMPLER_BASE); - resampler_set_quality(playing->resampler.fir_resampler[1], quality - DUMB_RESAMPLER_BASE); - } - } - } -} - - -void DUMBEXPORT dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER * sigrenderer, int ramp_style) { - if (sigrenderer && ramp_style >= 0 && ramp_style <= 2) { - sigrenderer->ramp_style = ramp_style; - } -} - - -void DUMBEXPORT dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data) -{ - if (sigrenderer) { - sigrenderer->callbacks->loop = callback; - sigrenderer->callbacks->loop_data = data; - } -} - - - -void DUMBEXPORT dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data) -{ - if (sigrenderer) { - sigrenderer->callbacks->xm_speed_zero = callback; - sigrenderer->callbacks->xm_speed_zero_data = data; - } -} - - - -void DUMBEXPORT dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data, int channel, unsigned char midi_byte), void *data) -{ - if (sigrenderer) { - sigrenderer->callbacks->midi = callback; - sigrenderer->callbacks->midi_data = data; - } -} - - - -void DUMBEXPORT dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (DUMBCALLBACK *callback)(void *data), void *data) -{ - if (sigrenderer) { - sigrenderer->callbacks->global_volume_zero = callback; - sigrenderer->callbacks->global_volume_zero_data = data; - } -} - - - -static IT_CALLBACKS *create_callbacks(void) -{ - IT_CALLBACKS *callbacks = malloc(sizeof(*callbacks)); - if (!callbacks) return NULL; - callbacks->loop = NULL; - callbacks->xm_speed_zero = NULL; - callbacks->midi = NULL; - callbacks->global_volume_zero = NULL; - return callbacks; -} - - - -static DUMB_IT_SIGRENDERER *dumb_it_init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder) -{ - IT_CALLBACKS *callbacks; - - if (!sigdata) return NULL; - - callbacks = create_callbacks(); - if (!callbacks) return NULL; - - return init_sigrenderer(sigdata, n_channels, startorder, callbacks, - dumb_create_click_remover_array(n_channels)); -} - - - -DUH_SIGRENDERER *DUMBEXPORT dumb_it_start_at_order(DUH *duh, int n_channels, int startorder) -{ - DUMB_IT_SIGDATA *itsd = duh_get_it_sigdata(duh); - DUMB_IT_SIGRENDERER *itsr = dumb_it_init_sigrenderer(itsd, n_channels, startorder); - /*duh->length = dumb_it_build_checkpoints(itsd, startorder);*/ - return duh_encapsulate_it_sigrenderer(itsr, n_channels, 0); -} - - - -static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_channels, int32 pos) -{ - DUMB_IT_SIGDATA *sigdata = vsigdata; - DUMB_IT_SIGRENDERER *sigrenderer; - - (void)duh; - - { - IT_CALLBACKS *callbacks = create_callbacks(); - if (!callbacks) return NULL; - - if (sigdata->checkpoint) { - IT_CHECKPOINT *checkpoint = sigdata->checkpoint; - while (checkpoint->next && checkpoint->next->time < pos) - checkpoint = checkpoint->next; - sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, n_channels, callbacks); - if (!sigrenderer) return NULL; - sigrenderer->click_remover = dumb_create_click_remover_array(n_channels); - pos -= checkpoint->time; - } else { - sigrenderer = init_sigrenderer(sigdata, n_channels, 0, callbacks, - dumb_create_click_remover_array(n_channels)); - if (!sigrenderer) return NULL; - } - } - - while (pos > 0 && pos >= sigrenderer->time_left) { - render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL); - - pos -= sigrenderer->time_left; - sigrenderer->time_left = 0; - - if (process_tick(sigrenderer)) { - _dumb_it_end_sigrenderer(sigrenderer); - return NULL; - } - } - - render(sigrenderer, 0, 1.0f, 0, pos, NULL); - sigrenderer->time_left -= pos; - - return sigrenderer; -} - - - -static int32 it_sigrenderer_get_samples( - sigrenderer_t *vsigrenderer, - double volume, double delta, - int32 size, sample_t **samples -) -{ - DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer; - int32 pos; - int dt; - int32 todo; - LONG_LONG t; - - if (sigrenderer->order < 0) return 0; // problematic - - pos = 0; - dt = (int)(delta * 65536.0f + 0.5f); - - /* When samples is finally used in render_playing(), it won't be used if - * volume is 0. - */ - if (!samples) volume = 0; - - for (;;) { - todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt); - - if (todo >= size) - break; - - render(sigrenderer, volume, delta, pos, todo, samples); - - pos += todo; - size -= todo; - - t = sigrenderer->sub_time_left - (LONG_LONG)todo * dt; - sigrenderer->sub_time_left = (int32)t & 65535; - sigrenderer->time_left += (int32)(t >> 16); - - if (process_tick(sigrenderer)) { - sigrenderer->order = -1; - sigrenderer->row = -1; - return pos; - } - } - - render(sigrenderer, volume, delta, pos, size, samples); - - pos += size; - - t = sigrenderer->sub_time_left - (LONG_LONG)size * dt; - sigrenderer->sub_time_left = (int32)t & 65535; - sigrenderer->time_left += (int32)(t >> 16); - - if (samples) - dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta); - - return pos; -} - - - -static void it_sigrenderer_get_current_sample(sigrenderer_t *vsigrenderer, double volume, sample_t *samples) -{ - DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer; - (void)volume; // for consideration: in any of these such functions, is 'volume' going to be required? - dumb_click_remover_get_offset_array(sigrenderer->n_channels, sigrenderer->click_remover, samples); -} - - - -void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer) -{ - DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer; - - int i; - - if (sigrenderer) { - IT_PLAYING *playing, *next; - - for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { - if (sigrenderer->channel[i].playing) - free_playing_orig(sigrenderer->channel[i].playing); -#ifdef BIT_ARRAY_BULLSHIT - bit_array_destroy(sigrenderer->channel[i].played_patjump); -#endif - } - - for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - if (sigrenderer->playing[i]) - free_playing_orig(sigrenderer->playing[i]); - - for (playing = sigrenderer->free_playing; playing != NULL; playing = next) - { - next = playing->next; - free_playing_orig(playing); - } - - dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover); - - if (sigrenderer->callbacks) - free(sigrenderer->callbacks); - -#ifdef BIT_ARRAY_BULLSHIT - bit_array_destroy(sigrenderer->played); -#endif - - free(vsigrenderer); - } -} - - - -DUH_SIGTYPE_DESC _dumb_sigtype_it = { - SIGTYPE_IT, - NULL, - &it_start_sigrenderer, - NULL, - &it_sigrenderer_get_samples, - &it_sigrenderer_get_current_sample, - &_dumb_it_end_sigrenderer, - &_dumb_it_unload_sigdata -}; - - - -DUH_SIGRENDERER *DUMBEXPORT duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, int32 pos) -{ - return duh_encapsulate_raw_sigrenderer(it_sigrenderer, &_dumb_sigtype_it, n_channels, pos); -} - - - -DUMB_IT_SIGRENDERER *DUMBEXPORT duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer) -{ - return duh_get_raw_sigrenderer(sigrenderer, SIGTYPE_IT); -} - - - -/* Values of 64 or more will access NNA channels here. */ -void DUMBEXPORT dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state) -{ - IT_PLAYING *playing; - int t; /* temporary var for holding accurate pan and filter cutoff */ - double delta; - ASSERT(channel < DUMB_IT_TOTAL_CHANNELS); - if (!sr) { state->sample = 0; return; } - if (channel >= DUMB_IT_N_CHANNELS) { - playing = sr->playing[channel - DUMB_IT_N_CHANNELS]; - if (!playing) { state->sample = 0; return; } - } else { - playing = sr->channel[channel].playing; - if (!playing) { state->sample = 0; return; } - } - - if (playing->flags & IT_PLAYING_DEAD) { state->sample = 0; return; } - - state->channel = (int)(playing->channel - sr->channel); - state->sample = playing->sampnum; - state->volume = calculate_volume(sr, playing, 1.0f); - - t = apply_pan_envelope(playing); - state->pan = (unsigned char)((t + 128) >> IT_ENVELOPE_SHIFT); - state->subpan = (signed char)t; - - delta = playing->delta * 65536.0f; - t = playing->filter_cutoff << IT_ENVELOPE_SHIFT; - apply_pitch_modifications(sr->sigdata, playing, &delta, &t); - state->freq = (int)delta; - if (t == 127 << IT_ENVELOPE_SHIFT && playing->filter_resonance == 0) { - state->filter_resonance = playing->true_filter_resonance; - t = playing->true_filter_cutoff; - } else - state->filter_resonance = playing->filter_resonance; - state->filter_cutoff = (unsigned char)(t >> 8); - state->filter_subcutoff = (unsigned char)t; -} - - - -int DUMBCALLBACK dumb_it_callback_terminate(void *data) -{ - (void)data; - return 1; -} - - - -int DUMBCALLBACK dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte) -{ - (void)data; - (void)channel; - (void)midi_byte; - return 1; -} - - - -#define IT_CHECKPOINT_INTERVAL (30 * 65536) /* Half a minute */ - -#define FUCKIT_THRESHOLD (120 * 60 * 65536) /* two hours? probably a pattern loop mess... */ - -/* Returns the length of the module, up until it first loops. */ -int32 DUMBEXPORT dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder) -{ - IT_CHECKPOINT *checkpoint; - if (!sigdata) return 0; - checkpoint = sigdata->checkpoint; - while (checkpoint) { - IT_CHECKPOINT *next = checkpoint->next; - _dumb_it_end_sigrenderer(checkpoint->sigrenderer); - free(checkpoint); - checkpoint = next; - } - sigdata->checkpoint = NULL; - checkpoint = malloc(sizeof(*checkpoint)); - if (!checkpoint) return 0; - checkpoint->time = 0; - checkpoint->sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, startorder); - if (!checkpoint->sigrenderer) { - free(checkpoint); - return 0; - } - checkpoint->sigrenderer->callbacks->loop = &dumb_it_callback_terminate; - checkpoint->sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate; - checkpoint->sigrenderer->callbacks->global_volume_zero = &dumb_it_callback_terminate; - - if (sigdata->checkpoint) - { - IT_CHECKPOINT *checkpoint = sigdata->checkpoint; - while (checkpoint) { - IT_CHECKPOINT *next = checkpoint->next; - _dumb_it_end_sigrenderer(checkpoint->sigrenderer); - free(checkpoint); - checkpoint = next; - } - } - - sigdata->checkpoint = checkpoint; - - for (;;) { - int32 l; - DUMB_IT_SIGRENDERER *sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, 0, checkpoint->sigrenderer->callbacks); - checkpoint->sigrenderer->callbacks = NULL; - if (!sigrenderer) { - checkpoint->next = NULL; - return checkpoint->time; - } - - l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL); - if (l < IT_CHECKPOINT_INTERVAL) { - _dumb_it_end_sigrenderer(sigrenderer); - checkpoint->next = NULL; - return checkpoint->time + l; - } - - checkpoint->next = malloc(sizeof(*checkpoint->next)); - if (!checkpoint->next) { - _dumb_it_end_sigrenderer(sigrenderer); - return checkpoint->time + IT_CHECKPOINT_INTERVAL; - } - - checkpoint->next->time = checkpoint->time + IT_CHECKPOINT_INTERVAL; - checkpoint = checkpoint->next; - checkpoint->sigrenderer = sigrenderer; - - if (checkpoint->time >= FUCKIT_THRESHOLD) { - checkpoint->next = NULL; - return 0; - } - } -} - - - -void DUMBEXPORT dumb_it_do_initial_runthrough(DUH *duh) -{ - if (duh) { - DUMB_IT_SIGDATA *sigdata = duh_get_it_sigdata(duh); - - if (sigdata) - duh_set_length(duh, dumb_it_build_checkpoints(sigdata, 0)); - } -} - -static int is_pattern_silent(IT_PATTERN * pattern, int order) { - int ret = 1; - IT_ENTRY * entry, * end; - if (!pattern || !pattern->n_rows || !pattern->n_entries || !pattern->entry) return 2; - - if ( pattern->n_entries == pattern->n_rows ) { - int n; - entry = pattern->entry; - for ( n = 0; n < pattern->n_entries; ++n, ++entry ) { - if ( !IT_IS_END_ROW(entry) ) break; - } - if ( n == pattern->n_entries ) return 2; - // broken? - } - - entry = pattern->entry; - end = entry + pattern->n_entries; - - while (entry < end) { - if (!IT_IS_END_ROW(entry)) { - if (entry->mask & (IT_ENTRY_INSTRUMENT | IT_ENTRY_VOLPAN)) - return 0; - if (entry->mask & IT_ENTRY_NOTE && entry->note < 120) - return 0; - if (entry->mask & IT_ENTRY_EFFECT) { - switch (entry->effect) { - case IT_SET_GLOBAL_VOLUME: - if (entry->effectvalue) return 0; - break; - - case IT_SET_SPEED: - if (entry->effectvalue > 64) ret++; - break; - - case IT_SET_SONG_TEMPO: - case IT_XM_KEY_OFF: - break; - - case IT_JUMP_TO_ORDER: - if (entry->effectvalue != order) - return 0; - break; - - case IT_S: - switch (entry->effectvalue >> 4) { - case 0: // meh bastard - if ( entry->effectvalue != 0 ) return 0; - break; - - case IT_S_FINE_PATTERN_DELAY: - case IT_S_PATTERN_LOOP: - case IT_S_PATTERN_DELAY: - ret++; - break; - - case IT_S7: - if ((entry->effectvalue & 15) > 2) - return 0; - break; - - default: - return 0; - } - break; - - // clever idiot with his S L O W crap; do nothing - case IT_VOLSLIDE_TONEPORTA: - case IT_SET_SAMPLE_OFFSET: - case IT_GLOBAL_VOLUME_SLIDE: - if ( entry->effectvalue != 0 ) return 0; - break; - - // genius also uses this instead of jump to order by mistake, meh, and it's bloody BCD - case IT_BREAK_TO_ROW: - if ( ( ( entry->effectvalue >> 4 ) * 10 + ( entry->effectvalue & 15 ) ) != order ) return 0; - break; - - default: - return 0; - } - } - } - entry++; - } - - return ret; -} - -int DUMBEXPORT dumb_it_trim_silent_patterns(DUH * duh) { - int n; - DUMB_IT_SIGDATA *sigdata; - - if (!duh) return -1; - - sigdata = duh_get_it_sigdata(duh); - - if (!sigdata || !sigdata->order || !sigdata->pattern) return -1; - - for (n = 0; n < sigdata->n_orders; n++) { - int p = sigdata->order[n]; - if (p < sigdata->n_patterns) { - IT_PATTERN * pattern = &sigdata->pattern[p]; - if (is_pattern_silent(pattern, n) > 1) { - pattern->n_rows = 1; - pattern->n_entries = 0; - if (pattern->entry) - { - free(pattern->entry); - pattern->entry = NULL; - } - } else - break; - } - } - - if (n == sigdata->n_orders) return -1; - - for (n = sigdata->n_orders - 1; n >= 0; n--) { - int p = sigdata->order[n]; - if (p < sigdata->n_patterns) { - IT_PATTERN * pattern = &sigdata->pattern[p]; - if (is_pattern_silent(pattern, n) > 1) { - pattern->n_rows = 1; - pattern->n_entries = 0; - if (pattern->entry) - { - free(pattern->entry); - pattern->entry = NULL; - } - } else - break; - } - } - - if (n < 0) return -1; - - /*duh->length = dumb_it_build_checkpoints(sigdata, 0);*/ - - return 0; -} - -int DUMBEXPORT dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void * callback_data) -{ - int n; - int32 length; - void * ba_played; - DUMB_IT_SIGRENDERER * sigrenderer; - - if (!sigdata->n_orders || !sigdata->order) return -1; - - ba_played = bit_array_create(sigdata->n_orders * 256); - if (!ba_played) return -1; - - /* Skip the first order, it should always be played */ - for (n = 1; n < sigdata->n_orders; n++) { - if ((sigdata->order[n] >= sigdata->n_patterns) || - (is_pattern_silent(&sigdata->pattern[sigdata->order[n]], n) > 1)) - bit_array_set(ba_played, n * 256); - } - - for (;;) { - for (n = 0; n < sigdata->n_orders; n++) { - if (!bit_array_test_range(ba_played, n * 256, 256)) break; - } - - if (n == sigdata->n_orders) break; - - sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, n); - if (!sigrenderer) { - bit_array_destroy(ba_played); - return -1; - } - sigrenderer->callbacks->loop = &dumb_it_callback_terminate; - sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate; - sigrenderer->callbacks->global_volume_zero = &dumb_it_callback_terminate; - - length = 0; - - for (;;) { - int32 l; - - l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL); - length += l; - if (l < IT_CHECKPOINT_INTERVAL || length >= FUCKIT_THRESHOLD) { - /* SONG OVA! */ - break; - } - } - - if ((*callback)(callback_data, n, length) < 0) return -1; - - bit_array_merge(ba_played, sigrenderer->played, 0); - - _dumb_it_end_sigrenderer(sigrenderer); - } - - bit_array_destroy(ba_played); - - return 0; -} diff --git a/libraries/dumb/src/it/itunload.c b/libraries/dumb/src/it/itunload.c deleted file mode 100644 index efed192a6..000000000 --- a/libraries/dumb/src/it/itunload.c +++ /dev/null @@ -1,72 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * itunload.c - Code to free an Impulse Tracker / / \ \ - * module from memory. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include - -#include "dumb.h" -#include "internal/it.h" - - - -void _dumb_it_unload_sigdata(sigdata_t *vsigdata) -{ - if (vsigdata) { - DUMB_IT_SIGDATA *sigdata = vsigdata; - int n; - - if (sigdata->song_message) - free(sigdata->song_message); - - if (sigdata->order) - free(sigdata->order); - - if (sigdata->instrument) - free(sigdata->instrument); - - if (sigdata->sample) { - for (n = 0; n < sigdata->n_samples; n++) - if (sigdata->sample[n].data) - free(sigdata->sample[n].data); - - free(sigdata->sample); - } - - if (sigdata->pattern) { - for (n = 0; n < sigdata->n_patterns; n++) - if (sigdata->pattern[n].entry) - free(sigdata->pattern[n].entry); - free(sigdata->pattern); - } - - if (sigdata->midi) - free(sigdata->midi); - - { - IT_CHECKPOINT *checkpoint = sigdata->checkpoint; - while (checkpoint) { - IT_CHECKPOINT *next = checkpoint->next; - _dumb_it_end_sigrenderer(checkpoint->sigrenderer); - free(checkpoint); - checkpoint = next; - } - } - - free(vsigdata); - } -} diff --git a/libraries/dumb/src/it/load669.c b/libraries/dumb/src/it/load669.c deleted file mode 100644 index 38343be29..000000000 --- a/libraries/dumb/src/it/load669.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadmod.c - Code to read a 669 Composer module / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_669_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_669_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/load6692.c b/libraries/dumb/src/it/load6692.c deleted file mode 100644 index 1f41c7aa0..000000000 --- a/libraries/dumb/src/it/load6692.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadmod2.c - Code to read a 669 Composer module / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer - * to the DUH struct. When you have finished with it, you must pass the - * pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_669(const char *filename) -{ - DUH *duh = dumb_load_669_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadamf.c b/libraries/dumb/src/it/loadamf.c deleted file mode 100644 index 2be50f7f5..000000000 --- a/libraries/dumb/src/it/loadamf.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadamf.c - Code to read a DSMI AMF module file, / / \ \ - * opening and closing it for you. | < / \_ - * | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_amf_quick(): loads a AMF file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_amf_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_amf_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadamf2.c b/libraries/dumb/src/it/loadamf2.c deleted file mode 100644 index 83ed76810..000000000 --- a/libraries/dumb/src/it/loadamf2.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadamf2.c - Code to read a DSMI AMF module file, / / \ \ - * opening and closing it for you, and | < / \_ - * do an initial run-through. | \/ /\ / - * \_ / > / - * | \ / / - * By Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_amf(): loads a AMF file into a DUH struct, returning a pointer - * to the DUH struct. When you have finished with it, you must pass the - * pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_amf(const char *filename) -{ - DUH *duh = dumb_load_amf_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadany.c b/libraries/dumb/src/it/loadany.c deleted file mode 100644 index 910e86a77..000000000 --- a/libraries/dumb/src/it/loadany.c +++ /dev/null @@ -1,38 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadany.c - Code to detect and read any of the / / \ \ - * module formats supported by DUMB, | < / \_ - * opening and closing the file for you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -DUH *DUMBEXPORT dumb_load_any_quick(const char *filename, int restrict_, int subsong) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_any_quick(f, restrict_, subsong); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadany2.c b/libraries/dumb/src/it/loadany2.c deleted file mode 100644 index 71590a0bf..000000000 --- a/libraries/dumb/src/it/loadany2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadany2.c - Code to detect and read any of the / / \ \ - * module formats supported by DUMB, | < / \_ - * opening and closing the file for | \/ /\ / - * you, and do an initial run-through. \_ / > / - * | \ / / - * by Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_any(const char *filename, int restrict_, int subsong) -{ - DUH *duh = dumb_load_any_quick(filename, restrict_, subsong); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadasy.c b/libraries/dumb/src/it/loadasy.c deleted file mode 100644 index 5e9b2dd1d..000000000 --- a/libraries/dumb/src/it/loadasy.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadasy.c - Code to read an ASYLUM Music Format / / \ \ - * module file, opening and closing it | < / \_ - * for you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_asy_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_asy_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadasy2.c b/libraries/dumb/src/it/loadasy2.c deleted file mode 100644 index ecbc1ecbd..000000000 --- a/libraries/dumb/src/it/loadasy2.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadasy2.c - Code to read an ASYLUM Music Format / / \ \ - * module file, opening and closing it | < / \_ - * for you, and do an initial run- | \/ /\ / - * through. \_ / > / - * | \ / / - * By Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer - * to the DUH struct. When you have finished with it, you must pass the - * pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_asy(const char *filename) -{ - DUH *duh = dumb_load_asy_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadmod.c b/libraries/dumb/src/it/loadmod.c deleted file mode 100644 index c2239ccb2..000000000 --- a/libraries/dumb/src/it/loadmod.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadmod.c - Code to read a good old-fashioned / / \ \ - * Amiga module file, opening and | < / \_ - * closing it for you. | \/ /\ / - * \_ / > / - * By entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_mod_quick(const char *filename, int restrict_) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_mod_quick(f, restrict_); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadmod2.c b/libraries/dumb/src/it/loadmod2.c deleted file mode 100644 index 1051f1a8d..000000000 --- a/libraries/dumb/src/it/loadmod2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadmod2.c - Function to read a good old- / / \ \ - * fashioned Amiga module file, | < / \_ - * opening and closing it for you, | \/ /\ / - * and do an initial run-through. \_ / > / - * | \ / / - * Split off from loadmod.c by entheh. | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_mod(const char *filename, int restrict_) -{ - DUH *duh = dumb_load_mod_quick(filename, restrict_); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadmtm.c b/libraries/dumb/src/it/loadmtm.c deleted file mode 100644 index 5ce44249b..000000000 --- a/libraries/dumb/src/it/loadmtm.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadmtm.c - Code to read a MultiTracker Module / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_mtm_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_mtm_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadmtm2.c b/libraries/dumb/src/it/loadmtm2.c deleted file mode 100644 index 13d303203..000000000 --- a/libraries/dumb/src/it/loadmtm2.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadmtm2.c - Code to read a MultiTracker Module / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer - * to the DUH struct. When you have finished with it, you must pass the - * pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_mtm(const char *filename) -{ - DUH *duh = dumb_load_mtm_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadokt.c b/libraries/dumb/src/it/loadokt.c deleted file mode 100644 index b1c73b8af..000000000 --- a/libraries/dumb/src/it/loadokt.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadokt.c - Code to read an Oktalyzer module / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_okt_quick(): loads an OKT file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_okt_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_okt_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadokt2.c b/libraries/dumb/src/it/loadokt2.c deleted file mode 100644 index f58da163a..000000000 --- a/libraries/dumb/src/it/loadokt2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadokt2.c - Function to read an Oktalyzer / / \ \ - * module file, opening and closing | < / \_ - * it for you, and do an initial run- | \/ /\ / - * through. \_ / > / - * | \ / / - * By Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_okt(const char *filename) -{ - DUH *duh = dumb_load_okt_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadoldpsm.c b/libraries/dumb/src/it/loadoldpsm.c deleted file mode 100644 index 2460d871a..000000000 --- a/libraries/dumb/src/it/loadoldpsm.c +++ /dev/null @@ -1,43 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadoldpsm.c - Code to read a ProTracker Studio / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct, - * returning a pointer to the DUH struct. When you have finished with it, - * you must pass the pointer to unload_duh() so that the memory can be - * freed. - */ -DUH *DUMBEXPORT dumb_load_old_psm_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_old_psm_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadoldpsm2.c b/libraries/dumb/src/it/loadoldpsm2.c deleted file mode 100644 index edd10db56..000000000 --- a/libraries/dumb/src/it/loadoldpsm2.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadoldpsm2.c - Code to read a ProTracker Studio / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run- | \/ /\ / - * through. \_ / > / - * | \ / / - * By Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning - * a pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_old_psm(const char *filename) -{ - DUH *duh = dumb_load_old_psm_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadpsm.c b/libraries/dumb/src/it/loadpsm.c deleted file mode 100644 index 7e2405c61..000000000 --- a/libraries/dumb/src/it/loadpsm.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadpsm.c - Code to read a ProTracker Studio / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_psm_quick(const char *filename, int subsong) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_psm_quick(f, subsong); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadpsm2.c b/libraries/dumb/src/it/loadpsm2.c deleted file mode 100644 index c4b5132ff..000000000 --- a/libraries/dumb/src/it/loadpsm2.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadpsm2.c - Code to read a ProTracker Studio / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer - * to the DUH struct. When you have finished with it, you must pass the - * pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_psm(const char *filename, int subsong) -{ - DUH *duh = dumb_load_psm_quick(filename, subsong); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadptm.c b/libraries/dumb/src/it/loadptm.c deleted file mode 100644 index 1ff066b45..000000000 --- a/libraries/dumb/src/it/loadptm.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadptm.c - Code to read a Poly Tracker v2.03 / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_ptm_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_ptm_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadptm2.c b/libraries/dumb/src/it/loadptm2.c deleted file mode 100644 index 3e50735d0..000000000 --- a/libraries/dumb/src/it/loadptm2.c +++ /dev/null @@ -1,34 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadptm2.c - Code to read a Poly Tracker v2.03 / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer - * to the DUH struct. When you have finished with it, you must pass the - * pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_ptm(const char *filename) -{ - DUH *duh = dumb_load_ptm_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadriff.c b/libraries/dumb/src/it/loadriff.c deleted file mode 100644 index 84a8a4358..000000000 --- a/libraries/dumb/src/it/loadriff.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadriff.c - Code to read a RIFF module file / / \ \ - * opening and closing it for you. | < / \_ - * | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning - * a pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_riff_quick( const char *filename ) -{ - DUH * duh; - DUMBFILE * f = dumbfile_open( filename ); - - if ( ! f ) - return NULL; - - duh = dumb_read_riff_quick( f ); - - dumbfile_close( f ); - - return duh; -} diff --git a/libraries/dumb/src/it/loadriff2.c b/libraries/dumb/src/it/loadriff2.c deleted file mode 100644 index 53466f1a5..000000000 --- a/libraries/dumb/src/it/loadriff2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadriff2.c - Code to read a RIFF module file / / \ \ - * opening and closing it for you, | < / \_ - * and do an initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_riff(const char *filename) -{ - DUH *duh = dumb_load_riff_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loads3m.c b/libraries/dumb/src/it/loads3m.c deleted file mode 100644 index 09deb0f26..000000000 --- a/libraries/dumb/src/it/loads3m.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loads3m.c - Code to read a ScreamTracker 3 / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning - * a pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_s3m_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_s3m_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loads3m2.c b/libraries/dumb/src/it/loads3m2.c deleted file mode 100644 index 7907775a8..000000000 --- a/libraries/dumb/src/it/loads3m2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loads3m2.c - Function to read a ScreamTracker 3 / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * Split off from loads3m.c by entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_s3m(const char *filename) -{ - DUH *duh = dumb_load_s3m_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadstm.c b/libraries/dumb/src/it/loadstm.c deleted file mode 100644 index 2a533adb3..000000000 --- a/libraries/dumb/src/it/loadstm.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadstm.c - Code to read a ScreamTracker 2 / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_stm_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_stm_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadstm2.c b/libraries/dumb/src/it/loadstm2.c deleted file mode 100644 index 491542bf3..000000000 --- a/libraries/dumb/src/it/loadstm2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadstm2.c - Function to read a ScreamTracker 2 / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_stm(const char *filename) -{ - DUH *duh = dumb_load_stm_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/loadxm.c b/libraries/dumb/src/it/loadxm.c deleted file mode 100644 index 98ccd9301..000000000 --- a/libraries/dumb/src/it/loadxm.c +++ /dev/null @@ -1,42 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadxm.c - Code to read a Fast Tracker II / / \ \ - * file, opening and closing it for | < / \_ - * you. | \/ /\ / - * \_ / > / - * By entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" - - - -/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must - * pass the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_load_xm_quick(const char *filename) -{ - DUH *duh; - DUMBFILE *f = dumbfile_open(filename); - - if (!f) - return NULL; - - duh = dumb_read_xm_quick(f); - - dumbfile_close(f); - - return duh; -} diff --git a/libraries/dumb/src/it/loadxm2.c b/libraries/dumb/src/it/loadxm2.c deleted file mode 100644 index 61459b5b8..000000000 --- a/libraries/dumb/src/it/loadxm2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * loadxm2.c - Function to read a Fast Tracker II / / \ \ - * file, opening and closing it for | < / \_ - * you, and do an initial run-through. | \/ /\ / - * \_ / > / - * Split off from loadxm.c by entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_load_xm(const char *filename) -{ - DUH *duh = dumb_load_xm_quick(filename); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/ptmeffect.c b/libraries/dumb/src/it/ptmeffect.c deleted file mode 100644 index cbc2e90cf..000000000 --- a/libraries/dumb/src/it/ptmeffect.c +++ /dev/null @@ -1,125 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * ptmeffect.c - Code for converting PTM / / \ \ - * effects to IT effects. | < / \_ - * | \/ /\ / - * By Chris Moeller. Based on xmeffect.c \_ / > / - * by Julien Cugniere. | \ / / - * | ' / - * \__/ - */ - - - -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry) -{ - if (effect >= PTM_N_EFFECTS) - return; - - /* Linearisation of the effect number... */ - if (effect == PTM_E) { - effect = PTM_EBASE + HIGH(value); - value = LOW(value); - } - - /* convert effect */ - entry->mask |= IT_ENTRY_EFFECT; - switch (effect) { - - case PTM_APPREGIO: effect = IT_ARPEGGIO; break; - case PTM_PORTAMENTO_UP: effect = IT_PORTAMENTO_UP; break; - case PTM_PORTAMENTO_DOWN: effect = IT_PORTAMENTO_DOWN; break; - case PTM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break; - case PTM_VIBRATO: effect = IT_VIBRATO; break; - case PTM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; - case PTM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; - case PTM_TREMOLO: effect = IT_TREMOLO; break; - case PTM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break; - case PTM_VOLUME_SLIDE: effect = IT_VOLUME_SLIDE; break; - case PTM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break; - case PTM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; - case PTM_PATTERN_BREAK: effect = IT_BREAK_TO_ROW; break; - case PTM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; break; - case PTM_RETRIGGER: effect = IT_RETRIGGER_NOTE; break; - case PTM_FINE_VIBRATO: effect = IT_FINE_VIBRATO; break; - - /* TODO properly */ - case PTM_NOTE_SLIDE_UP: effect = IT_PTM_NOTE_SLIDE_UP; break; - case PTM_NOTE_SLIDE_DOWN: effect = IT_PTM_NOTE_SLIDE_DOWN; break; - case PTM_NOTE_SLIDE_UP_RETRIG: effect = IT_PTM_NOTE_SLIDE_UP_RETRIG; break; - case PTM_NOTE_SLIDE_DOWN_RETRIG: effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG; break; - - case PTM_SET_TEMPO_BPM: - effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO); - break; - - case PTM_EBASE+PTM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */ - case PTM_EBASE+PTM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break; - case PTM_EBASE+PTM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break; - case PTM_EBASE+PTM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break; - case PTM_EBASE+PTM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break; - case PTM_EBASE+PTM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break; - - case PTM_EBASE+PTM_E_FINE_VOLSLIDE_UP: - effect = IT_VOLUME_SLIDE; - value = EFFECT_VALUE(value, 0xF); - break; - - case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN: - effect = IT_VOLUME_SLIDE; - value = EFFECT_VALUE(0xF, value); - break; - - case PTM_EBASE + PTM_E_FINE_PORTA_UP: - effect = IT_PORTAMENTO_UP; - value = EFFECT_VALUE(0xF, value); - break; - - case PTM_EBASE + PTM_E_FINE_PORTA_DOWN: - effect = IT_PORTAMENTO_DOWN; - value = EFFECT_VALUE(0xF, value); - break; - - case PTM_EBASE + PTM_E_RETRIG_NOTE: - effect = IT_XM_RETRIGGER_NOTE; - value = EFFECT_VALUE(0, value); - break; - - case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL: - effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM; - value &= ~4; /** TODO: value&4 -> don't retrig wave */ - break; - - case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL: - effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM; - value &= ~4; /** TODO: value&4 -> don't retrig wave */ - break; - - default: - /* user effect (often used in demos for synchronisation) */ - entry->mask &= ~IT_ENTRY_EFFECT; - } - - /* Inverse linearisation... */ - if (effect >= SBASE && effect < SBASE+16) { - value = EFFECT_VALUE(effect-SBASE, value); - effect = IT_S; - } - - entry->effect = effect; - entry->effectvalue = value; -} diff --git a/libraries/dumb/src/it/read669.c b/libraries/dumb/src/it/read669.c deleted file mode 100644 index 53332b497..000000000 --- a/libraries/dumb/src/it/read669.c +++ /dev/null @@ -1,448 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * read669.c - Code to read a 669 Composer module / / \ \ - * from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - - - -static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int breakpoint, unsigned char *buffer, int * used_channels) -{ - int pos; - int channel; - int row; - IT_ENTRY *entry; - - pattern->n_rows = 64; - - if (dumbfile_getnc((char *)buffer, 64 * 3 * 8, f) < 64 * 3 * 8) - return -1; - - /* compute number of entries */ - pattern->n_entries = 64 + 1; /* Account for the row end markers, speed command */ - if (breakpoint < 63) pattern->n_entries++; /* and break to row 0 */ - - pos = 0; - for (row = 0; row < 64; row++) { - for (channel = 0; channel < 8; channel++) { - if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) - pattern->n_entries++; - pos += 3; - } - } - - pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); - if (!pattern->entry) - return -1; - - if (breakpoint == 63) breakpoint++; - - entry = pattern->entry; - - entry->channel = 8; - entry->mask = IT_ENTRY_EFFECT; - entry->effect = IT_SET_SPEED; - entry->effectvalue = tempo; - entry++; - - pos = 0; - for (row = 0; row < 64; row++) { - - if (row == breakpoint) { - entry->channel = 8; - entry->mask = IT_ENTRY_EFFECT; - entry->effect = IT_BREAK_TO_ROW; - entry->effectvalue = 0; - entry++; - } - - for (channel = 0; channel < 8; channel++) { - if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) { - entry->channel = channel; - entry->mask = 0; - - if (buffer[pos+0] < 0xFE) { - entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT; - entry->note = (buffer[pos+0] >> 2) + 36; - entry->instrument = (((buffer[pos+0] << 4) | (buffer[pos+1] >> 4)) & 0x3F) + 1; - } - if (buffer[pos+0] <= 0xFE) { - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = ((buffer[pos+1] & 15) << 6) / 15; - if (*used_channels < channel + 1) *used_channels = channel + 1; - } - if (buffer[pos+2] != 0xFF) { - entry->mask |= IT_ENTRY_EFFECT; - entry->effectvalue = buffer[pos+2] & 15; - switch (buffer[pos+2] >> 4) { - case 0: - entry->effect = IT_PORTAMENTO_UP; - break; - case 1: - entry->effect = IT_PORTAMENTO_DOWN; - break; - case 2: - entry->effect = IT_TONE_PORTAMENTO; - break; - case 3: - entry->effect = IT_S; - entry->effectvalue += IT_S_FINETUNE * 16 + 8; - break; - case 4: - entry->effect = IT_VIBRATO; - // XXX speed unknown - entry->effectvalue |= 0x10; - break; - case 5: - if (entry->effectvalue) { - entry->effect = IT_SET_SPEED; - } else { - entry->mask &= ~IT_ENTRY_EFFECT; - } - break; -#if 0 - /* dunno about this, really... */ - case 6: - if (entry->effectvalue == 0) { - entry->effect = IT_PANNING_SLIDE; - entry->effectvalue = 0xFE; - } else if (entry->effectvalue == 1) { - entry->effect = IT_PANNING_SLIDE; - entry->effectvalue = 0xEF; - } else { - entry->mask &= ~IT_ENTRY_EFFECT; - } - break; -#endif - default: - entry->mask &= ~IT_ENTRY_EFFECT; - break; - } - if (*used_channels < channel + 1) *used_channels = channel + 1; - } - - entry++; - } - pos += 3; - } - IT_SET_END_ROW(entry); - entry++; - } - - return 0; -} - - - -static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) -{ - dumbfile_getnc((char *)sample->name, 13, f); - sample->name[13] = 0; - - sample->filename[0] = 0; - - sample->length = dumbfile_igetl(f); - sample->loop_start = dumbfile_igetl(f); - sample->loop_end = dumbfile_igetl(f); - - if (dumbfile_error(f)) - return -1; - - if (sample->length <= 0) { - sample->flags = 0; - return 0; - } - - sample->flags = IT_SAMPLE_EXISTS; - - sample->global_volume = 64; - sample->default_volume = 64; - - sample->default_pan = 0; - sample->C5_speed = 8363; - // the above line might be wrong - - if ((sample->loop_end > sample->length) && !(sample->loop_start)) - sample->loop_end = 0; - - if (sample->loop_end > sample->length) - sample->loop_end = sample->length; - - if (sample->loop_end - sample->loop_start > 2) - sample->flags |= IT_SAMPLE_LOOP; - - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; // do we have to set _all_ these? - sample->finetune = 0; - sample->max_resampling_quality = -1; - - return 0; -} - - - -static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) -{ - int32 i; - int32 truncated_size; - - /* let's get rid of the sample data coming after the end of the loop */ - if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { - truncated_size = sample->length - sample->loop_end; - sample->length = sample->loop_end; - } else { - truncated_size = 0; - } - - sample->data = malloc(sample->length); - - if (!sample->data) - return -1; - - if (sample->length) - { - i = dumbfile_getnc(sample->data, sample->length, f); - - if (i < sample->length) { - //return -1; - // ficking truncated files - if (i <= 0) { - sample->flags = 0; - return 0; - } - sample->length = i; - if (sample->loop_end > i) sample->loop_end = i; - } else { - /* skip truncated data */ - dumbfile_skip(f, truncated_size); - // Should we be truncating it? - if (dumbfile_error(f)) - return -1; - } - - for (i = 0; i < sample->length; i++) - ((signed char *)sample->data)[i] ^= 0x80; - } - - return 0; -} - - -static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext) -{ - DUMB_IT_SIGDATA *sigdata; - int n_channels; - int i; - unsigned char tempolist[128]; - unsigned char breaklist[128]; - - i = dumbfile_igetw(f); - if (i != 0x6669 && i != 0x4E4A) return NULL; - - *ext = (i == 0x4E4A); - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) { - return NULL; - } - - if (dumbfile_getnc((char *)sigdata->name, 36, f) < 36) { - free(sigdata); - return NULL; - } - sigdata->name[36] = 0; - - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - sigdata->sample = NULL; - - sigdata->n_instruments = 0; - - sigdata->song_message = malloc(72 + 2 + 1); - if (!sigdata->song_message) { - free(sigdata); - return NULL; - } - if (dumbfile_getnc((char *)sigdata->song_message, 36, f) < 36) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - sigdata->song_message[36] = 13; - sigdata->song_message[36 + 1] = 10; - if (dumbfile_getnc((char *)sigdata->song_message + 38, 36, f) < 36) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - sigdata->song_message[38 + 36] = 0; - - sigdata->n_samples = dumbfile_getc(f); - sigdata->n_patterns = dumbfile_getc(f); - sigdata->restart_position = dumbfile_getc(f); - - if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->order = malloc(128); /* We may need to scan the extra ones! */ - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (i = 0; i < 128; i++) { - if (sigdata->order[i] == 255) break; - if (sigdata->order[i] >= sigdata->n_patterns) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - if (!i) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - sigdata->n_orders = i; - - if (dumbfile_getnc((char *)tempolist, 128, f) < 128) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (dumbfile_getnc((char *)breaklist, 128, f) < 128) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (i = 0; i < sigdata->n_samples; i++) - sigdata->sample[i].data = NULL; - - for (i = 0; i < sigdata->n_samples; i++) { - if (it_669_read_sample_header(&sigdata->sample[i], f)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - - /* May as well try to save a tiny bit of memory. */ - if (sigdata->n_orders < 128) { - unsigned char *order = realloc(sigdata->order, sigdata->n_orders); - if (order) sigdata->order = order; - } - - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) - sigdata->pattern[i].entry = NULL; - - n_channels = 0; - - /* Read in the patterns */ - { - unsigned char *buffer = malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */ - if (!buffer) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) { - if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i], breaklist[i], buffer, &n_channels) != 0) { - free(buffer); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - free(buffer); - } - - sigdata->n_pchannels = n_channels; - - /* And finally, the sample data */ - for (i = 0; i < sigdata->n_samples; i++) { - if (it_669_read_sample_data(&sigdata->sample[i], f)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - - /* Now let's initialise the remaining variables, and we're done! */ - sigdata->flags = IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - sigdata->speed = 4; - sigdata->tempo = 78; - sigdata->pan_separation = 128; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[i+0] = 32 + sep; - sigdata->channel_pan[i+1] = 32 - sep; - } - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - - - -DUH *DUMBEXPORT dumb_read_669_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - int ext; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_669_load_sigdata(f, &ext); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = ext ? "669 Extended" : "669"; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/read6692.c b/libraries/dumb/src/it/read6692.c deleted file mode 100644 index a9911d3ec..000000000 --- a/libraries/dumb/src/it/read6692.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * read6692.c - Code to read a 669 Composer module / / \ \ - * from an open file, and do an initial | < / \_ - * run-through. | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_669(DUMBFILE *f) -{ - DUH *duh = dumb_read_669_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readam.c b/libraries/dumb/src/it/readam.c deleted file mode 100644 index be99f1934..000000000 --- a/libraries/dumb/src/it/readam.c +++ /dev/null @@ -1,788 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readam.c - Code to read a RIFF AM module / / \ \ - * from a parsed RIFF structure. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" -#include "internal/it.h" -#include "internal/riff.h" - -static int it_riff_am_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len, int ver ) -{ - int header_length; - int default_pan; - int default_volume; - int flags; - int length; - int length_bytes; - int loop_start; - int loop_end; - int sample_rate; - - int32 start = dumbfile_pos( f ); - - if ( ver == 0 ) - { - if ( len < 0x38 ) - return -1; - - header_length = 0x38; - - dumbfile_getnc( (char *) sample->name, 28, f ); - sample->name[ 28 ] = 0; - - default_pan = dumbfile_getc( f ); - default_volume = dumbfile_getc( f ); - flags = dumbfile_igetw( f ); - length = dumbfile_igetl( f ); - loop_start = dumbfile_igetl( f ); - loop_end = dumbfile_igetl( f ); - sample_rate = dumbfile_igetl( f ); - } - else - { - if (len < 4) return -1; - - header_length = dumbfile_igetl( f ); - if ( header_length < 0x40 ) - return -1; - if ( header_length + 4 > len ) - return -1; - - start += 4; - len -= 4; - - dumbfile_getnc( (char *) sample->name, 32, f ); - - default_pan = dumbfile_igetw( f ); - default_volume = dumbfile_igetw( f ); - flags = dumbfile_igetw( f ); - dumbfile_skip( f, 2 ); - length = dumbfile_igetl( f ); - loop_start = dumbfile_igetl( f ); - loop_end = dumbfile_igetl( f ); - sample_rate = dumbfile_igetl( f ); - - if ( default_pan > 0x7FFF || default_volume > 0x7FFF ) - return -1; - - default_pan = default_pan * 64 / 32767; - default_volume = default_volume * 64 / 32767; - } - - if ( ! length ) { - sample->flags &= ~IT_SAMPLE_EXISTS; - return 0; - } - - if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) ) - return -1; - - length_bytes = length << ( ( flags & 0x04 ) >> 2 ); - - if ( length_bytes + header_length > len ) - return -1; - - sample->flags = 0; - - if ( flags & 0x80 ) sample->flags |= IT_SAMPLE_EXISTS; - if ( flags & 0x04 ) sample->flags |= IT_SAMPLE_16BIT; - - sample->length = length; - sample->loop_start = loop_start; - sample->loop_end = loop_end; - sample->C5_speed = sample_rate; - sample->default_volume = default_volume; - sample->default_pan = default_pan | ( ( flags & 0x20 ) << 2 ); - sample->filename[0] = 0; - sample->global_volume = 64; - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = IT_VIBRATO_SINE; - sample->finetune = 0; - sample->max_resampling_quality = -1; - - if ( flags & 0x08 ) - { - if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && - ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) - { - sample->length = sample->loop_end; - sample->flags |= IT_SAMPLE_LOOP; - if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; - } - } - - length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 ); - - sample->data = malloc( length_bytes ); - if ( ! sample->data ) - return -1; - - if ( dumbfile_seek( f, start + header_length, DFS_SEEK_SET ) ) - return -1; - - dumbfile_getnc( sample->data, length_bytes, f ); - - return 0; -} - -static int it_riff_am_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len, int ver ) -{ - int nrows, row; - long start, end; - unsigned flags; - int p, q, r; - IT_ENTRY * entry; - - nrows = dumbfile_getc( f ) + 1; - - pattern->n_rows = nrows; - - len -= 1; - - pattern->n_entries = 0; - - row = 0; - - start = dumbfile_pos( f ); - end = start + len; - - while ( (row < nrows) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) { - p = dumbfile_getc( f ); - if ( ! p ) { - ++ row; - continue; - } - - flags = p & 0xE0; - - if (flags) { - ++ pattern->n_entries; - if (flags & 0x80) dumbfile_skip( f, 2 ); - if (flags & 0x40) dumbfile_skip( f, 2 ); - if (flags & 0x20) dumbfile_skip( f, 1 ); - } - } - - if ( ! pattern->n_entries ) return 0; - - pattern->n_entries += nrows; - - pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) ); - if ( ! pattern->entry ) return -1; - - entry = pattern->entry; - - row = 0; - - dumbfile_seek( f, start, DFS_SEEK_SET ); - - while ( ( row < nrows ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) ) - { - p = dumbfile_getc( f ); - - if ( ! p ) - { - IT_SET_END_ROW( entry ); - ++ entry; - ++ row; - continue; - } - - flags = p; - entry->channel = flags & 0x1F; - entry->mask = 0; - - if (flags & 0xE0) - { - if ( flags & 0x80 ) - { - q = dumbfile_getc( f ); - r = dumbfile_getc( f ); - _dumb_it_xm_convert_effect( r, q, entry, 0 ); - } - - if ( flags & 0x40 ) - { - q = dumbfile_getc( f ); - r = dumbfile_getc( f ); - if ( q ) - { - entry->mask |= IT_ENTRY_INSTRUMENT; - entry->instrument = q; - } - if ( r ) - { - entry->mask |= IT_ENTRY_NOTE; - entry->note = r - 1; - } - } - - if ( flags & 0x20 ) - { - q = dumbfile_getc( f ); - entry->mask |= IT_ENTRY_VOLPAN; - if ( ver == 0 ) entry->volpan = q; - else entry->volpan = q * 64 / 127; - } - - if (entry->mask) entry++; - } - } - - while ( row < nrows ) - { - IT_SET_END_ROW( entry ); - ++ entry; - ++ row; - } - - pattern->n_entries = (int)(entry - pattern->entry); - if ( ! pattern->n_entries ) return -1; - - return 0; -} - -static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( DUMBFILE * f, struct riff * stream ) -{ - DUMB_IT_SIGDATA *sigdata; - - int n, o, p, found; - - if ( ! stream ) goto error; - - if ( stream->type != DUMB_ID( 'A', 'M', 'F', 'F' ) ) goto error; - - sigdata = malloc( sizeof( *sigdata ) ); - if ( ! sigdata ) goto error; - - sigdata->n_patterns = 0; - sigdata->n_samples = 0; - sigdata->name[0] = 0; - - found = 0; - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch( c->type ) - { - case DUMB_ID( 'M', 'A', 'I', 'N' ): - /* initialization data */ - if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd; - found |= 1; - break; - - case DUMB_ID( 'O', 'R', 'D', 'R' ): - if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd; - found |= 2; - break; - - case DUMB_ID( 'P', 'A', 'T', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_sd; - o = dumbfile_getc( f ); - if ( o >= sigdata->n_patterns ) sigdata->n_patterns = o + 1; - o = dumbfile_igetl( f ); - if ( (unsigned)o + 5 > c->size ) goto error_sd; - break; - - case DUMB_ID( 'I', 'N', 'S', 'T' ): - { - if ( c->size < 0xE1 ) goto error_sd; - if ( dumbfile_seek( f, c->offset + 1, DFS_SEEK_SET ) ) goto error_sd; - o = dumbfile_getc( f ); - if ( o >= sigdata->n_samples ) sigdata->n_samples = o + 1; - if ( c->size >= 0x121 ) - { - if ( dumbfile_seek( f, c->offset + 0xE1, DFS_SEEK_SET ) ) goto error_sd; - if ( dumbfile_mgetl( f ) == DUMB_ID('S','A','M','P') ) - { - unsigned size = dumbfile_igetl( f ); - if ( size + 0xE1 + 8 > c->size ) goto error_sd; - } - } - } - break; - } - } - - if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; - - if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - sigdata->n_instruments = 0; - sigdata->n_orders = 0; - sigdata->restart_position = 0; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[n ] = 32 - sep; - sigdata->channel_pan[n+1] = 32 + sep; - sigdata->channel_pan[n+2] = 32 + sep; - sigdata->channel_pan[n+3] = 32 - sep; - } - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch ( c->type ) - { - case DUMB_ID( 'M', 'A', 'I', 'N' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - dumbfile_getnc( (char *) sigdata->name, 64, f ); - sigdata->name[ 64 ] = 0; - sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; - o = dumbfile_getc( f ); - if ( ! ( o & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES; - if ( ( o & ~3 ) || ! ( o & 2 ) ) goto error_usd; // unknown flags - sigdata->n_pchannels = dumbfile_getc( f ); - sigdata->speed = dumbfile_getc( f ); - sigdata->tempo = dumbfile_getc( f ); - - dumbfile_skip( f, 4 ); - - sigdata->global_volume = dumbfile_getc( f ); - - if ( c->size < 0x48 + (unsigned)sigdata->n_pchannels ) goto error_usd; - - for ( o = 0; o < sigdata->n_pchannels; ++o ) - { - p = dumbfile_getc( f ); - sigdata->channel_pan[ o ] = p; - if ( p >= 128 ) - { - sigdata->channel_volume[ o ] = 0; - } - } - break; - } - } - - sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); - if ( ! sigdata->pattern ) goto error_usd; - for ( n = 0; n < sigdata->n_patterns; ++n ) - sigdata->pattern[ n ].entry = NULL; - - sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); - if ( ! sigdata->sample ) goto error_usd; - for ( n = 0; n < sigdata->n_samples; ++n ) - { - IT_SAMPLE * sample = sigdata->sample + n; - sample->data = NULL; - sample->flags = 0; - sample->name[ 0 ] = 0; - } - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch ( c->type ) - { - case DUMB_ID( 'O', 'R', 'D', 'R' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - sigdata->n_orders = dumbfile_getc( f ) + 1; - if ( (unsigned)sigdata->n_orders + 1 > c->size ) goto error_usd; - sigdata->order = malloc( sigdata->n_orders ); - if ( ! sigdata->order ) goto error_usd; - dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f ); - break; - - case DUMB_ID( 'P', 'A', 'T', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - o = dumbfile_getc( f ); - p = dumbfile_igetl( f ); - if ( it_riff_am_process_pattern( sigdata->pattern + o, f, p, 0 ) ) goto error_usd; - break; - - case DUMB_ID( 'I', 'N', 'S', 'T' ): - { - IT_SAMPLE * sample; - if ( dumbfile_seek( f, c->offset + 1, DFS_SEEK_SET ) ) goto error_usd; - sample = sigdata->sample + dumbfile_getc( f ); - if ( c->size >= 0x121 ) - { - if ( dumbfile_seek( f, c->offset + 0xE1, DFS_SEEK_SET ) ) goto error_usd; - if ( dumbfile_mgetl( f ) == DUMB_ID('S','A','M','P') ) - { - unsigned size = dumbfile_igetl( f ); - if ( it_riff_am_process_sample( sample, f, size, 0 ) ) goto error_usd; - break; - } - } - dumbfile_seek( f, c->offset + 2, DFS_SEEK_SET ); - dumbfile_getnc( (char *) sample->name, 28, f ); - sample->name[ 28 ] = 0; - } - break; - } - } - - _dumb_it_fix_invalid_orders( sigdata ); - - return sigdata; - -error_usd: - _dumb_it_unload_sigdata( sigdata ); - goto error; -error_sd: - free( sigdata ); -error: - return NULL; -} - -static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( DUMBFILE * f, struct riff * stream ) -{ - DUMB_IT_SIGDATA *sigdata; - - int n, o, p, found; - - if ( ! f || ! stream ) goto error; - - if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error; - - sigdata = malloc(sizeof(*sigdata)); - if ( ! sigdata ) goto error; - - sigdata->n_patterns = 0; - sigdata->n_samples = 0; - sigdata->name[0] = 0; - - found = 0; - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch( c->type ) - { - case DUMB_ID( 'I' ,'N' ,'I' ,'T' ): - /* initialization data */ - if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd; - found |= 1; - break; - - case DUMB_ID( 'O', 'R', 'D', 'R' ): - if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd; - found |= 2; - break; - - case DUMB_ID( 'P', 'A', 'T', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_sd; - o = dumbfile_getc( f ); - if ( o >= sigdata->n_patterns ) sigdata->n_patterns = o + 1; - o = dumbfile_igetl( f ); - if ( (unsigned)o + 5 > c->size ) goto error_sd; - break; - - case DUMB_ID( 'R', 'I', 'F', 'F' ): - { - struct riff * str = c->nested; - switch ( str->type ) - { - case DUMB_ID( 'A', 'I', ' ', ' ' ): - for ( o = 0; (unsigned)o < str->chunk_count; ++o ) - { - struct riff_chunk * chk = str->chunks + o; - switch( chk->type ) - { - case DUMB_ID( 'I', 'N', 'S', 'T' ): - { - struct riff * temp; - unsigned size; - unsigned sample_found; - if ( dumbfile_seek( f, chk->offset, DFS_SEEK_SET ) ) goto error_sd; - size = dumbfile_igetl( f ); - if ( size < 0x142 ) goto error_sd; - sample_found = 0; - dumbfile_skip( f, 1 ); - p = dumbfile_getc( f ); - if ( p >= sigdata->n_samples ) sigdata->n_samples = p + 1; - temp = riff_parse( f, chk->offset + 4 + size, chk->size - size - 4, 1 ); - if ( temp ) - { - if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) ) - { - for ( p = 0; (unsigned)p < temp->chunk_count; ++p ) - { - if ( temp->chunks[ p ].type == DUMB_ID( 'S', 'A', 'M', 'P' ) ) - { - if ( sample_found ) - { - riff_free( temp ); - goto error_sd; - } - sample_found = 1; - } - } - } - riff_free( temp ); - } - } - } - } - } - } - break; - } - } - - if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; - - if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - sigdata->n_instruments = 0; - sigdata->n_orders = 0; - sigdata->restart_position = 0; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[n ] = 32 - sep; - sigdata->channel_pan[n+1] = 32 + sep; - sigdata->channel_pan[n+2] = 32 + sep; - sigdata->channel_pan[n+3] = 32 - sep; - } - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch ( c->type ) - { - case DUMB_ID( 'I', 'N', 'I', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - dumbfile_getnc( (char *) sigdata->name, 64, f ); - sigdata->name[ 64 ] = 0; - sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; - o = dumbfile_getc( f ); - if ( ! ( o & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES; - if ( ( o & ~3 ) || ! ( o & 2 ) ) goto error_usd; // unknown flags - sigdata->n_pchannels = dumbfile_getc( f ); - sigdata->speed = dumbfile_getc( f ); - sigdata->tempo = dumbfile_getc( f ); - - dumbfile_skip( f, 4 ); - - sigdata->global_volume = dumbfile_getc( f ); - - if ( c->size < 0x48 + (unsigned)sigdata->n_pchannels ) goto error_usd; - - for ( o = 0; o < sigdata->n_pchannels; ++o ) - { - p = dumbfile_getc( f ); - if ( p <= 128 ) - { - sigdata->channel_pan[ o ] = p / 2; - } - else - { - sigdata->channel_volume[ o ] = 0; - } - } - break; - } - } - - sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); - if ( ! sigdata->pattern ) goto error_usd; - for ( n = 0; n < sigdata->n_patterns; ++n ) - sigdata->pattern[ n ].entry = NULL; - - sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); - if ( ! sigdata->sample ) goto error_usd; - for ( n = 0; n < sigdata->n_samples; ++n ) - { - IT_SAMPLE * sample = sigdata->sample + n; - sample->data = NULL; - sample->flags = 0; - sample->name[ 0 ] = 0; - } - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch ( c->type ) - { - case DUMB_ID( 'O', 'R', 'D', 'R' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - sigdata->n_orders = dumbfile_getc( f ) + 1; - if ( (unsigned)sigdata->n_orders + 1 > c->size ) goto error_usd; - sigdata->order = malloc( sigdata->n_orders ); - if ( ! sigdata->order ) goto error_usd; - dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f ); - break; - - case DUMB_ID( 'P', 'A', 'T', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - o = dumbfile_getc( f ); - p = dumbfile_igetl( f ); - if ( it_riff_am_process_pattern( sigdata->pattern + o, f, p, 1 ) ) goto error_usd; - break; - - case DUMB_ID( 'R', 'I', 'F', 'F' ): - { - struct riff * str = c->nested; - switch ( str->type ) - { - case DUMB_ID('A', 'I', ' ', ' '): - for ( o = 0; (unsigned)o < str->chunk_count; ++o ) - { - struct riff_chunk * chk = str->chunks + o; - switch( chk->type ) - { - case DUMB_ID( 'I', 'N', 'S', 'T' ): - { - struct riff * temp; - unsigned size; - unsigned sample_found; - IT_SAMPLE * sample; - if ( dumbfile_seek( f, chk->offset, DFS_SEEK_SET ) ) goto error_usd; - size = dumbfile_igetl( f ); - dumbfile_skip( f, 1 ); - p = dumbfile_getc( f ); - temp = riff_parse( f, chk->offset + 4 + size, chk->size - size - 4, 1 ); - sample_found = 0; - sample = sigdata->sample + p; - if ( temp ) - { - if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) ) - { - for ( p = 0; (unsigned)p < temp->chunk_count; ++p ) - { - struct riff_chunk * c = temp->chunks + p; - if ( c->type == DUMB_ID( 'S', 'A', 'M', 'P' ) ) - { - if ( sample_found ) - { - riff_free( temp ); - goto error_usd; - } - { - riff_free( temp ); - goto error_usd; - } - if ( it_riff_am_process_sample( sample, f, c->size, 1 ) ) - { - riff_free( temp ); - goto error_usd; - } - sample_found = 1; - } - } - } - riff_free( temp ); - } - if ( ! sample_found ) - { - dumbfile_seek( f, chk->offset + 6, DFS_SEEK_SET ); - dumbfile_getnc( (char *) sample->name, 32, f ); - sample->name[ 32 ] = 0; - } - } - } - } - } - } - break; - } - } - - _dumb_it_fix_invalid_orders( sigdata ); - - return sigdata; - -error_usd: - _dumb_it_unload_sigdata( sigdata ); - goto error; -error_sd: - free( sigdata ); -error: - return NULL; -} - -DUH *dumb_read_riff_amff( DUMBFILE * f, struct riff * stream ) -{ - sigdata_t *sigdata; - long length; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_riff_amff_load_sigdata( f, stream ); - - if (!sigdata) - return NULL; - - length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/ - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "RIFF AMFF"; - return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata ); - } -} - -DUH *dumb_read_riff_am( DUMBFILE * f, struct riff * stream ) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_riff_am_load_sigdata( f, stream ); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "RIFF AM"; - return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata ); - } -} diff --git a/libraries/dumb/src/it/readamf.c b/libraries/dumb/src/it/readamf.c deleted file mode 100644 index 7b72467e0..000000000 --- a/libraries/dumb/src/it/readamf.c +++ /dev/null @@ -1,559 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readamf.c - Code to read a DSMI AMF module from / / \ \ - * an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - - - -static void it_amf_process_track( IT_ENTRY *entry_table, unsigned char *track, int rows, int channels ) -{ - int last_instrument = 0; - int tracksize = track[ 0 ] + ( track[ 1 ] << 8 ) + ( track[ 2 ] << 16 ); - track += 3; - while ( tracksize-- ) { - unsigned int row = track[ 0 ]; - unsigned int command = track[ 1 ]; - unsigned int argument = track[ 2 ]; - IT_ENTRY * entry = entry_table + row * channels; - if ( row >= ( unsigned int ) rows ) break; - if ( command < 0x7F ) { - entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT | IT_ENTRY_VOLPAN; - entry->note = command; - if ( ! entry->instrument ) entry->instrument = last_instrument; - entry->volpan = argument; - } - else if ( command == 0x7F ) { - signed char row_delta = ( signed char ) argument; - int row_source = ( int ) row + ( int ) row_delta; - if ( row_source >= 0 && row_source < ( int ) rows ) { - *entry = entry_table[ row_source * channels ]; - } - } - else if ( command == 0x80 ) { - entry->mask |= IT_ENTRY_INSTRUMENT; - last_instrument = argument + 1; - entry->instrument = last_instrument; - } - else if ( command == 0x83 ) { - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = argument; - } - else { - unsigned int effect = command & 0x7F; - unsigned int effectvalue = argument; - switch (effect) { - case 0x01: effect = IT_SET_SPEED; break; - - case 0x02: effect = IT_VOLUME_SLIDE; - case 0x0A: if ( effect == 0x0A ) effect = IT_VOLSLIDE_TONEPORTA; - case 0x0B: if ( effect == 0x0B ) effect = IT_VOLSLIDE_VIBRATO; - if ( effectvalue & 0x80 ) effectvalue = ( -( signed char ) effectvalue ) & 0x0F; - else effectvalue = ( effectvalue & 0x0F ) << 4; - break; - - case 0x04: - if ( effectvalue & 0x80 ) { - effect = IT_PORTAMENTO_UP; - effectvalue = ( -( signed char ) effectvalue ) & 0x7F; - } - else { - effect = IT_PORTAMENTO_DOWN; - } - break; - - case 0x06: effect = IT_TONE_PORTAMENTO; break; - - case 0x07: effect = IT_TREMOR; break; - - case 0x08: effect = IT_ARPEGGIO; break; - - case 0x09: effect = IT_VIBRATO; break; - - case 0x0C: effect = IT_BREAK_TO_ROW; break; - - case 0x0D: effect = IT_JUMP_TO_ORDER; break; - - case 0x0F: effect = IT_RETRIGGER_NOTE; break; - - case 0x10: effect = IT_SET_SAMPLE_OFFSET; break; - - case 0x11: - if ( effectvalue ) { - effect = IT_VOLUME_SLIDE; - if ( effectvalue & 0x80 ) - effectvalue = 0xF0 | ( ( -( signed char ) effectvalue ) & 0x0F ); - else - effectvalue = 0x0F | ( ( effectvalue & 0x0F ) << 4 ); - } - else - effect = 0; - break; - - case 0x12: - case 0x16: - if ( effectvalue ) { - int mask = ( effect == 0x16 ) ? 0xE0 : 0xF0; - effect = ( effectvalue & 0x80 ) ? IT_PORTAMENTO_UP : IT_PORTAMENTO_DOWN; - if ( effectvalue & 0x80 ) - effectvalue = mask | ( ( -( signed char ) effectvalue ) & 0x0F ); - else - effectvalue = mask | ( effectvalue & 0x0F ); - } - else - effect = 0; - break; - - case 0x13: - effect = IT_S; - effectvalue = EFFECT_VALUE( IT_S_NOTE_DELAY, effectvalue & 0x0F ); - break; - - case 0x14: - effect = IT_S; - effectvalue = EFFECT_VALUE( IT_S_DELAYED_NOTE_CUT, effectvalue & 0x0F ); - break; - - case 0x15: effect = IT_SET_SONG_TEMPO; break; - - case 0x17: - effectvalue = ( effectvalue + 64 ) & 0x7F; - if ( entry->mask & IT_ENTRY_EFFECT ) { - if ( !( entry->mask & IT_ENTRY_VOLPAN ) ) { - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = ( effectvalue / 2 ) + 128; - } - effect = 0; - } - else { - effect = IT_SET_PANNING; - } - break; - - default: effect = effectvalue = 0; - } - if ( effect ) { - entry->mask |= IT_ENTRY_EFFECT; - entry->effect = effect; - entry->effectvalue = effectvalue; - } - } - track += 3; - } -} - -static int it_amf_process_pattern( IT_PATTERN *pattern, IT_ENTRY *entry_table, int rows, int channels ) -{ - int i, j; - int n_entries = rows; - IT_ENTRY * entry; - - pattern->n_rows = rows; - - for ( i = 0, j = channels * rows; i < j; i++ ) { - if ( entry_table[ i ].mask ) { - n_entries++; - } - } - - pattern->n_entries = n_entries; - - pattern->entry = entry = malloc( n_entries * sizeof( IT_ENTRY ) ); - if ( !entry ) { - return -1; - } - - for ( i = 0; i < rows; i++ ) { - for ( j = 0; j < channels; j++ ) { - if ( entry_table[ i * channels + j ].mask ) { - *entry = entry_table[ i * channels + j ]; - entry->channel = j; - entry++; - } - } - IT_SET_END_ROW( entry ); - entry++; - } - - return 0; -} - -static int it_amf_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, int * offset, int ver ) -{ - int exists; - - exists = dumbfile_getc( f ); - - dumbfile_getnc( (char *) sample->name, 32, f ); - sample->name[32] = 0; - - dumbfile_getnc( (char *) sample->filename, 13, f ); - sample->filename[13] = 0; - - *offset = dumbfile_igetl( f ); - sample->length = dumbfile_igetl( f ); - sample->C5_speed = dumbfile_igetw( f ); - sample->default_volume = dumbfile_getc( f ); - sample->global_volume = 64; - if ( sample->default_volume > 64 ) sample->default_volume = 64; - - if ( ver >= 11 ) { - sample->loop_start = dumbfile_igetl( f ); - sample->loop_end = dumbfile_igetl( f ); - } else { - sample->loop_start = dumbfile_igetw( f ); - sample->loop_end = sample->length; - } - - if ( sample->length <= 0 ) { - sample->flags = 0; - return 0; - } - - sample->flags = exists == 1 ? IT_SAMPLE_EXISTS : 0; - - sample->default_pan = 0; - sample->finetune = 0; - - if ( sample->loop_end > sample->loop_start + 2 && sample->loop_end <= sample->length ) - sample->flags |= IT_SAMPLE_LOOP; - - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; // do we have to set _all_ these? - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - - - -static int it_amf_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f ) -{ - int i, read_length = 0; - - sample->data = malloc( sample->length ); - - if ( !sample->data ) - return -1; - - if ( sample->length ) - read_length = dumbfile_getnc( sample->data, sample->length, f ); - - for ( i = 0; i < read_length; i++ ) { - ( ( char * ) sample->data )[ i ] ^= 0x80; - } - - for ( i = read_length; i < sample->length; i++ ) { - ( ( char * ) sample->data )[ i ] = 0; - } - - return 0; /* Sometimes the last sample is truncated :( */ -} - -static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int * version) -{ - DUMB_IT_SIGDATA *sigdata; - int i, j, ver, ntracks, realntracks, nchannels; - - int maxsampleseekpos = 0; - int sampleseekpos[256]; - - unsigned short *orderstotracks; - unsigned short *trackmap; - unsigned int tracksize[256]; - - unsigned char **track; - - static const char sig[] = "AMF"; - - char signature [3]; - - if ( dumbfile_getnc( signature, 3, f ) != 3 || - memcmp( signature, sig, 3 ) ) { - return NULL; - } - - *version = ver = dumbfile_getc( f ); - if ( ver < 10 || ver > 14) { - return NULL; - } - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) { - return NULL; - } - - dumbfile_getnc( (char *) sigdata->name, 32, f ); - sigdata->name[ 32 ] = 0; - sigdata->n_samples = dumbfile_getc( f ); - sigdata->n_orders = dumbfile_getc( f ); - ntracks = dumbfile_igetw( f ); - nchannels = dumbfile_getc( f ); - - if ( dumbfile_error( f ) || - sigdata->n_samples < 1 || sigdata->n_samples > 255 || - sigdata->n_orders < 1 || sigdata->n_orders > 255 || - ! ntracks || - nchannels < 1 || nchannels > 32 ) { - free( sigdata ); - return NULL; - } - - sigdata->n_pchannels = nchannels; - - memset( sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS ); - - if ( ver >= 11 ) { - int nchannels = ( ver >= 13 ) ? 32 : 16; - for ( i = 0; i < nchannels; i++ ) { - signed char panpos = dumbfile_getc( f ); - int pan = ( panpos + 64 ) / 2; - if ( pan < 0 ) pan = 0; - else if ( pan > 64 ) pan = IT_SURROUND; - sigdata->channel_pan[ i ] = pan; - } - } - else { - int sep = 32 * dumb_it_default_panning_separation / 100; - for ( i = 0; i < 16; i++ ) { - sigdata->channel_pan[ i ] = ( dumbfile_getc( f ) & 1 ) ? 32 - sep : 32 + sep; - } - } - - sigdata->tempo = 125; - sigdata->speed = 6; - if ( ver >= 13 ) { - i = dumbfile_getc( f ); - if ( i >= 32 ) sigdata->tempo = i; - i = dumbfile_getc( f ); - if ( i <= 32 ) sigdata->speed = i; - } - - sigdata->order = malloc( sigdata->n_orders ); - if ( !sigdata->order ) { - free( sigdata ); - return NULL; - } - - orderstotracks = malloc( sigdata->n_orders * nchannels * sizeof( unsigned short ) ); - if ( !orderstotracks ) { - free( sigdata->order ); - free( sigdata ); - return NULL; - } - - for ( i = 0; i < sigdata->n_orders; i++ ) { - sigdata->order[ i ] = i; - tracksize[ i ] = 64; - if ( ver >= 14 ) { - tracksize[ i ] = dumbfile_igetw( f ); - } - for ( j = 0; j < nchannels; j++ ) { - orderstotracks[ i * nchannels + j ] = dumbfile_igetw( f ); - } - } - - if ( dumbfile_error( f ) ) { - free( orderstotracks ); - free( sigdata->order ); - free( sigdata ); - return NULL; - } - - sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); - if ( !sigdata->sample ) { - free( orderstotracks ); - free( sigdata->order ); - free( sigdata ); - return NULL; - } - - sigdata->restart_position = 0; - - sigdata->song_message = NULL; - sigdata->instrument = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - - for ( i = 0; i < sigdata->n_samples; ++i ) - sigdata->sample[i].data = NULL; - - for ( i = 0; i < sigdata->n_samples; ++i ) { - int offset; - if ( it_amf_read_sample_header( &sigdata->sample[i], f, &offset, ver ) ) { - goto error_ott; - } - sampleseekpos[ i ] = offset; - if ( offset > maxsampleseekpos ) maxsampleseekpos = offset; - } - - sigdata->n_patterns = sigdata->n_orders; - - sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); - if ( !sigdata->pattern ) { - goto error_ott; - } - for (i = 0; i < sigdata->n_patterns; ++i) - sigdata->pattern[i].entry = NULL; - - trackmap = malloc( ntracks * sizeof( unsigned short ) ); - if ( !trackmap ) { - goto error_ott; - } - - if ( dumbfile_getnc( ( char * ) trackmap, ntracks * sizeof( unsigned short ), f ) != (long)(ntracks * sizeof( unsigned short )) ) { - goto error_tm; - } - - realntracks = 0; - - for ( i = 0; i < ntracks; i++ ) { - if ( trackmap[ i ] > realntracks ) realntracks = trackmap[ i ]; - } - - track = calloc( realntracks, sizeof( unsigned char * ) ); - if ( !track ) { - goto error_tm; - } - - for ( i = 0; i < realntracks; i++ ) { - int tracksize = dumbfile_igetw( f ); - tracksize += dumbfile_getc( f ) << 16; - track[ i ] = malloc( tracksize * 3 + 3 ); - if ( !track[ i ] ) { - goto error_all; - } - track[ i ][ 0 ] = tracksize & 255; - track[ i ][ 1 ] = ( tracksize >> 8 ) & 255; - track[ i ][ 2 ] = ( tracksize >> 16 ) & 255; - if ( dumbfile_getnc( (char *) track[ i ] + 3, tracksize * 3, f ) != tracksize * 3 ) { - goto error_all; - } - } - - for ( i = 1; i <= maxsampleseekpos; i++ ) { - for ( j = 0; j < sigdata->n_samples; j++ ) { - if ( sampleseekpos[ j ] == i ) { - if ( it_amf_read_sample_data( &sigdata->sample[ j ], f ) ) { - goto error_all; - } - break; - } - } - } - - /* Process tracks into patterns */ - for ( i = 0; i < sigdata->n_patterns; i++ ) { - IT_ENTRY * entry_table = calloc( tracksize[ i ] * nchannels, sizeof( IT_ENTRY ) ); - if ( !entry_table ) { - goto error_all; - } - for ( j = 0; j < nchannels; j++ ) { - int ntrack = orderstotracks[ i * nchannels + j ]; - if ( ntrack && ntrack <= ntracks ) { - int realtrack = trackmap[ ntrack - 1 ]; - if ( realtrack ) { - realtrack--; - if ( realtrack < realntracks && track[ realtrack ] ) { - it_amf_process_track( entry_table + j, track[ realtrack ], tracksize[ i ], nchannels ); - } - } - } - } - if ( it_amf_process_pattern( &sigdata->pattern[ i ], entry_table, tracksize[ i ], nchannels ) ) { - free( entry_table ); - goto error_all; - } - free( entry_table ); - } - - /* Now let's initialise the remaining variables, and we're done! */ - sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_WAS_AN_S3M; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - _dumb_it_fix_invalid_orders(sigdata); - - for ( i = 0; i < realntracks; i++ ) { - if ( track[ i ] ) { - free( track[ i ] ); - } - } - free( track ); - free( trackmap ); - free( orderstotracks ); - - return sigdata; - -error_all: - for ( i = 0; i < realntracks; i++ ) { - if ( track[ i ] ) { - free( track[ i ] ); - } - } - free( track ); -error_tm: - free( trackmap ); -error_ott: - free( orderstotracks ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; -} - - - -DUH *DUMBEXPORT dumb_read_amf_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - int version; - - sigdata = it_amf_load_sigdata(f, &version); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - char ver_string[14]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - memcpy( ver_string, "DSMI AMF v", 10 ); - ver_string[10] = '0' + version / 10; - ver_string[11] = '.'; - ver_string[12] = '0' + version % 10; - ver_string[13] = 0; - tag[1][1] = ver_string; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readamf2.c b/libraries/dumb/src/it/readamf2.c deleted file mode 100644 index 3c8732227..000000000 --- a/libraries/dumb/src/it/readamf2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readamf2.c - Function to read a DSMI AMF module / / \ \ - * from an open file and do an initial | < / \_ - * run-through. | \/ /\ / - * \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_amf(DUMBFILE *f) -{ - DUH *duh = dumb_read_amf_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readany.c b/libraries/dumb/src/it/readany.c deleted file mode 100644 index 9d90776ff..000000000 --- a/libraries/dumb/src/it/readany.c +++ /dev/null @@ -1,132 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readany.c - Code to detect and read any of the / / \ \ - * module formats supported by DUMB. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" - -#ifdef _MSC_VER - #define strnicmp _strnicmp -#else - #if defined(unix) || defined(__unix__) || defined(__unix) - #include - #endif - #define strnicmp strncasecmp -#endif - -enum { maximum_signature_size = 0x30 }; - -DUH *DUMBEXPORT dumb_read_any_quick(DUMBFILE *f, int restrict_, int subsong) -{ - unsigned char signature[ maximum_signature_size ]; - unsigned long signature_size; - DUH * duh = NULL; - - signature_size = dumbfile_get_size(f); - - signature_size = dumbfile_getnc( (char *)signature, maximum_signature_size, f ); - dumbfile_seek( f, 0, DFS_SEEK_SET ); - - if (signature_size >= 4 && - signature[0] == 'I' && signature[1] == 'M' && - signature[2] == 'P' && signature[3] == 'M') - { - duh = dumb_read_it_quick( f ); - } - else if (signature_size >= 17 && !memcmp(signature, "Extended Module: ", 17)) - { - duh = dumb_read_xm_quick( f ); - } - else if (signature_size >= 0x30 && - signature[0x2C] == 'S' && signature[0x2D] == 'C' && - signature[0x2E] == 'R' && signature[0x2F] == 'M') - { - duh = dumb_read_s3m_quick( f ); - } - else if (signature_size >= 30 && - /*signature[28] == 0x1A &&*/ signature[29] == 2 && - ( ! strnicmp( ( const char * ) signature + 20, "!Scream!", 8 ) || - ! strnicmp( ( const char * ) signature + 20, "BMOD2STM", 8 ) || - ! strnicmp( ( const char * ) signature + 20, "WUZAMOD!", 8 ) ) ) - { - duh = dumb_read_stm_quick( f ); - } - else if (signature_size >= 2 && - ((signature[0] == 0x69 && signature[1] == 0x66) || - (signature[0] == 0x4A && signature[1] == 0x4E))) - { - duh = dumb_read_669_quick( f ); - } - else if (signature_size >= 0x30 && - signature[0x2C] == 'P' && signature[0x2D] == 'T' && - signature[0x2E] == 'M' && signature[0x2F] == 'F') - { - duh = dumb_read_ptm_quick( f ); - } - else if (signature_size >= 4 && - signature[0] == 'P' && signature[1] == 'S' && - signature[2] == 'M' && signature[3] == ' ') - { - duh = dumb_read_psm_quick( f, subsong ); - } - else if (signature_size >= 4 && - signature[0] == 'P' && signature[1] == 'S' && - signature[2] == 'M' && signature[3] == 254) - { - duh = dumb_read_old_psm_quick( f ); - } - else if (signature_size >= 3 && - signature[0] == 'M' && signature[1] == 'T' && - signature[2] == 'M') - { - duh = dumb_read_mtm_quick( f ); - } - else if ( signature_size >= 4 && - signature[0] == 'R' && signature[1] == 'I' && - signature[2] == 'F' && signature[3] == 'F') - { - duh = dumb_read_riff_quick( f ); - } - else if ( signature_size >= 24 && - !memcmp( signature, "ASYLUM Music Format", 19 ) && - !memcmp( signature + 19, " V1.0", 5 ) ) - { - duh = dumb_read_asy_quick( f ); - } - else if ( signature_size >= 3 && - signature[0] == 'A' && signature[1] == 'M' && - signature[2] == 'F') - { - duh = dumb_read_amf_quick( f ); - } - else if ( signature_size >= 8 && - !memcmp( signature, "OKTASONG", 8 ) ) - { - duh = dumb_read_okt_quick( f ); - } - - if ( !duh ) - { - dumbfile_seek( f, 0, DFS_SEEK_SET ); - duh = dumb_read_mod_quick( f, restrict_ ); - } - - return duh; -} diff --git a/libraries/dumb/src/it/readany2.c b/libraries/dumb/src/it/readany2.c deleted file mode 100644 index bd0102cab..000000000 --- a/libraries/dumb/src/it/readany2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readany2.c - Code to detect and read any of the / / \ \ - * module formats supported by DUMB | < / \_ - * from an open file and do an initial | \/ /\ / - * run-through. \_ / > / - * | \ / / - * by Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_any(DUMBFILE *f, int restrict_, int subsong) -{ - DUH *duh = dumb_read_any_quick(f, restrict_, subsong); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readasy.c b/libraries/dumb/src/it/readasy.c deleted file mode 100644 index cc77dc39a..000000000 --- a/libraries/dumb/src/it/readasy.c +++ /dev/null @@ -1,339 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readasy.c - Code to read an ASYLUM Music Format / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - - - -static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer ) -{ - int pos; - int channel; - int row; - IT_ENTRY *entry; - - pattern->n_rows = 64; - - if ( dumbfile_getnc( (char *) buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 ) - return -1; - - /* compute number of entries */ - pattern->n_entries = 64; /* Account for the row end markers */ - pos = 0; - for ( row = 0; row < 64; ++row ) { - for ( channel = 0; channel < 8; ++channel ) { - if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) - ++pattern->n_entries; - pos += 4; - } - } - - pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) ); - if ( !pattern->entry ) - return -1; - - entry = pattern->entry; - pos = 0; - for ( row = 0; row < 64; ++row ) { - for ( channel = 0; channel < 8; ++channel ) { - if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) { - entry->channel = channel; - entry->mask = 0; - - if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) { - entry->note = buffer[ pos + 0 ]; - entry->mask |= IT_ENTRY_NOTE; - } - - if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) { - entry->instrument = buffer[ pos + 1 ]; - entry->mask |= IT_ENTRY_INSTRUMENT; - } - - _dumb_it_xm_convert_effect( buffer[ pos + 2 ], buffer[ pos + 3 ], entry, 1 ); - - // fixup - switch ( entry->effect ) { - case IT_SET_PANNING: - entry->effectvalue <<= 1; - break; - } - - if ( entry->mask ) ++entry; - } - pos += 4; - } - IT_SET_END_ROW( entry ); - ++entry; - } - - pattern->n_entries = (int)(entry - pattern->entry); - - return 0; -} - - - -static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f ) -{ - int finetune, key_offset; - -/** - 21 22 Chars Sample 1 name. If the name is not a full - 22 chars in length, it will be null - terminated. - -If -the sample name begins with a '#' character (ASCII $23 (35)) then this is -assumed not to be an instrument name, and is probably a message. -*/ - dumbfile_getnc( (char *) sample->name, 22, f ); - sample->name[22] = 0; - - sample->filename[0] = 0; - -/** Each finetune step changes the note 1/8th of a semitone. */ - finetune = ( signed char ) ( dumbfile_getc( f ) << 4 ) >> 4; /* signed nibble */ - sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead? - sample->global_volume = 64; - if ( sample->default_volume > 64 ) sample->default_volume = 64; - key_offset = ( signed char ) dumbfile_getc( f ); /* base key offset */ - sample->length = dumbfile_igetl( f ); - sample->loop_start = dumbfile_igetl( f ); - sample->loop_end = sample->loop_start + dumbfile_igetl( f ); - - if ( sample->length <= 0 ) { - sample->flags = 0; - return 0; - } - - sample->flags = IT_SAMPLE_EXISTS; - - sample->default_pan = 0; - sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 * pow( DUMB_SEMITONE_BASE, key_offset ) );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) ); - sample->finetune = finetune * 32; - // the above line might be wrong - - if ( ( sample->loop_end - sample->loop_start > 2 ) && ( sample->loop_end <= sample->length ) ) - sample->flags |= IT_SAMPLE_LOOP; - - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; // do we have to set _all_ these? - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - - - -static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f ) -{ - int32 truncated_size; - - /* let's get rid of the sample data coming after the end of the loop */ - if ( ( sample->flags & IT_SAMPLE_LOOP ) && sample->loop_end < sample->length ) { - truncated_size = sample->length - sample->loop_end; - sample->length = sample->loop_end; - } else { - truncated_size = 0; - } - - sample->data = malloc( sample->length ); - - if ( !sample->data ) - return -1; - - if ( sample->length ) - dumbfile_getnc( sample->data, sample->length, f ); - - dumbfile_skip( f, truncated_size ); - - return dumbfile_error( f ); -} - - - -static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f) -{ - DUMB_IT_SIGDATA *sigdata; - int i; - - static const char sig_part[] = "ASYLUM Music Format"; - static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */ - - char signature [32]; - - if ( dumbfile_getnc( signature, 32, f ) != 32 || - memcmp( signature, sig_part, 19 ) || - memcmp( signature + 19, sig_rest, 5 ) ) { - return NULL; - } - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) { - return NULL; - } - - sigdata->speed = dumbfile_getc( f ); /* XXX seems to fit the files I have */ - sigdata->tempo = dumbfile_getc( f ); /* ditto */ - sigdata->n_samples = dumbfile_getc( f ); /* ditto */ - sigdata->n_patterns = dumbfile_getc( f ); - sigdata->n_orders = dumbfile_getc( f ); - sigdata->restart_position = dumbfile_getc( f ); - - if ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns || - !sigdata->n_orders ) { - free( sigdata ); - return NULL; - } - - if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */ - sigdata->restart_position = 0; - - sigdata->order = malloc( sigdata->n_orders ); - if ( !sigdata->order ) { - free( sigdata ); - return NULL; - } - - if ( dumbfile_getnc( (char *) sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders || - dumbfile_skip( f, 256 - sigdata->n_orders ) ) { - free( sigdata->order ); - free( sigdata ); - return NULL; - } - - sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); - if ( !sigdata->sample ) { - free( sigdata->order ); - free( sigdata ); - return NULL; - } - - sigdata->song_message = NULL; - sigdata->instrument = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - - for ( i = 0; i < sigdata->n_samples; ++i ) - sigdata->sample[i].data = NULL; - - for ( i = 0; i < sigdata->n_samples; ++i ) { - if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - } - - if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - - sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); - if ( !sigdata->pattern ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; ++i) - sigdata->pattern[i].entry = NULL; - - /* Read in the patterns */ - { - unsigned char *buffer = malloc( 64 * 8 * 4 ); /* 64 rows * 8 channels * 4 bytes */ - if ( !buffer ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - for ( i = 0; i < sigdata->n_patterns; ++i ) { - if ( it_asy_read_pattern( &sigdata->pattern[i], f, buffer ) != 0 ) { - free( buffer ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - } - free( buffer ); - } - - /* And finally, the sample data */ - for ( i = 0; i < sigdata->n_samples; ++i ) { - if ( it_asy_read_sample_data( &sigdata->sample[i], f ) ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - } - - /* Now let's initialise the remaining variables, and we're done! */ - sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - sigdata->n_pchannels = 8; - - sigdata->name[0] = 0; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[i+0] = 32 - sep; - sigdata->channel_pan[i+1] = 32 + sep; - sigdata->channel_pan[i+2] = 32 + sep; - sigdata->channel_pan[i+3] = 32 - sep; - } - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - - - -DUH *DUMBEXPORT dumb_read_asy_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_asy_load_sigdata(f); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "ASYLUM Music Format"; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readdsmf.c b/libraries/dumb/src/it/readdsmf.c deleted file mode 100644 index d64d87950..000000000 --- a/libraries/dumb/src/it/readdsmf.c +++ /dev/null @@ -1,383 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readam.c - Code to read a RIFF DSMF module / / \ \ - * from a parsed RIFF structure. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" -#include "internal/it.h" -#include "internal/riff.h" - -static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, DUMBFILE * f, int len ) -{ - int flags; - - dumbfile_getnc( (char *) sample->filename, 13, f ); - sample->filename[ 14 ] = 0; - - flags = dumbfile_igetw( f ); - sample->default_volume = dumbfile_getc( f ); - sample->length = dumbfile_igetl( f ); - sample->loop_start = dumbfile_igetl( f ); - sample->loop_end = dumbfile_igetl( f ); - dumbfile_skip( f, 32 - 28 ); - sample->C5_speed = dumbfile_igetw( f ) * 2; - dumbfile_skip( f, 36 - 34 ); - dumbfile_getnc( (char *) sample->name, 28, f ); - sample->name[ 28 ] = 0; - - /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] ) - return -1;*/ - - if ( ! sample->length ) { - sample->flags &= ~IT_SAMPLE_EXISTS; - return 0; - } - - /*if ( flags & ~( 2 | 1 ) ) - return -1;*/ - - if ( sample->length + 64 > len ) - return -1; - - sample->flags = IT_SAMPLE_EXISTS; - - sample->default_pan = 0; - sample->global_volume = 64; - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = IT_VIBRATO_SINE; - sample->finetune = 0; - sample->max_resampling_quality = -1; - - if ( flags & 1 ) - { - if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && - ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) - { - sample->length = sample->loop_end; - sample->flags |= IT_SAMPLE_LOOP; - if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; - } - } - - sample->data = malloc( sample->length ); - if ( ! sample->data ) - return -1; - - dumbfile_getnc( sample->data, sample->length, f ); - - if ( ! ( flags & 2 ) ) - { - for ( flags = 0; flags < sample->length; ++flags ) - ( ( signed char * ) sample->data ) [ flags ] ^= 0x80; - } - - return 0; -} - -static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, DUMBFILE * f, int len ) -{ - int length, row; - unsigned flags; - long start, end; - int p, q, r; - IT_ENTRY * entry; - - length = dumbfile_igetw( f ); - if ( length > len ) return -1; - - len = length - 2; - - pattern->n_rows = 64; - pattern->n_entries = 64; - - row = 0; - - start = dumbfile_pos( f ); - end = start + len; - - while ( (row < 64) && !dumbfile_error( f ) && (dumbfile_pos( f ) < end) ) { - p = dumbfile_getc( f ); - if ( ! p ) { - ++ row; - continue; - } - - flags = p & 0xF0; - - if (flags) { - ++ pattern->n_entries; - if (flags & 0x80) dumbfile_skip( f, 1 ); - if (flags & 0x40) dumbfile_skip( f, 1 ); - if (flags & 0x20) dumbfile_skip( f, 1 ); - if (flags & 0x10) dumbfile_skip( f, 2 ); - } - } - - if ( pattern->n_entries == 64 ) return 0; - - pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) ); - if ( ! pattern->entry ) return -1; - - entry = pattern->entry; - - row = 0; - - if ( dumbfile_seek( f, start, DFS_SEEK_SET ) ) return -1; - - while ( ( row < 64 ) && !dumbfile_error( f ) && ( dumbfile_pos( f ) < end ) ) - { - p = dumbfile_getc( f ); - if ( ! p ) - { - IT_SET_END_ROW( entry ); - ++ entry; - ++ row; - continue; - } - - flags = p; - entry->channel = flags & 0x0F; - entry->mask = 0; - - if ( flags & 0xF0 ) - { - if ( flags & 0x80 ) - { - q = dumbfile_getc( f ); - if ( q ) - { - entry->mask |= IT_ENTRY_NOTE; - entry->note = q - 1; - } - } - - if ( flags & 0x40 ) - { - q = dumbfile_getc( f ); - if ( q ) - { - entry->mask |= IT_ENTRY_INSTRUMENT; - entry->instrument = q; - } - } - - if ( flags & 0x20 ) - { - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = dumbfile_getc( f ); - } - - if ( flags & 0x10 ) - { - q = dumbfile_getc( f ); - r = dumbfile_getc( f ); - _dumb_it_xm_convert_effect( q, r, entry, 0 ); - } - - if (entry->mask) entry++; - } - } - - while ( row < 64 ) - { - IT_SET_END_ROW( entry ); - ++ entry; - ++ row; - } - - pattern->n_entries = (int)(entry - pattern->entry); - if ( ! pattern->n_entries ) return -1; - - return 0; -} - -static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( DUMBFILE * f, struct riff * stream ) -{ - DUMB_IT_SIGDATA *sigdata; - - int n, o, found; - - if ( ! stream ) goto error; - - if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error; - - sigdata = malloc(sizeof(*sigdata)); - if ( ! sigdata ) goto error; - - sigdata->n_patterns = 0; - sigdata->n_samples = 0; - sigdata->name[0] = 0; - - found = 0; - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch( c->type ) - { - case DUMB_ID( 'S' ,'O' ,'N' ,'G' ): - /* initialization data */ - if ( ( found ) || ( c->size < 192 ) ) goto error_sd; - found = 1; - break; - - case DUMB_ID( 'P', 'A', 'T', 'T' ): - ++ sigdata->n_patterns; - break; - - case DUMB_ID( 'I', 'N', 'S', 'T' ): - ++ sigdata->n_samples; - break; - } - } - - if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; - - if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - sigdata->n_instruments = 0; - sigdata->n_orders = 0; - sigdata->restart_position = 0; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[n ] = 32 - sep; - sigdata->channel_pan[n+1] = 32 + sep; - sigdata->channel_pan[n+2] = 32 + sep; - sigdata->channel_pan[n+3] = 32 - sep; - } - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch ( c->type ) - { - case DUMB_ID( 'S', 'O', 'N', 'G' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - dumbfile_getnc( (char *) sigdata->name, 28, f ); - sigdata->name[ 28 ] = 0; - sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; - dumbfile_skip( f, 36 - 28 ); - sigdata->n_orders = dumbfile_igetw( f ); - //sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever - //sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 ); - dumbfile_skip( f, 42 - 38 ); - sigdata->n_pchannels = dumbfile_igetw( f ); - sigdata->global_volume = dumbfile_getc( f ); - sigdata->mixing_volume = dumbfile_getc( f ); - sigdata->speed = dumbfile_getc( f ); - sigdata->tempo = dumbfile_getc( f ); - - for ( o = 0; o < 16; ++o ) - { - sigdata->channel_pan[ o ] = dumbfile_getc( f ) / 2; - } - - sigdata->order = malloc( 128 ); - if ( ! sigdata->order ) goto error_usd; - dumbfile_getnc( (char *) sigdata->order, 128, f ); - - break; - } - } - - sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); - if ( ! sigdata->pattern ) goto error_usd; - for ( n = 0; n < sigdata->n_patterns; ++n ) - sigdata->pattern[ n ].entry = NULL; - - sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); - if ( ! sigdata->sample ) goto error_usd; - for ( n = 0; n < sigdata->n_samples; ++n ) - { - IT_SAMPLE * sample = sigdata->sample + n; - sample->data = NULL; - } - - sigdata->n_samples = 0; - sigdata->n_patterns = 0; - - for ( n = 0; (unsigned)n < stream->chunk_count; ++n ) - { - struct riff_chunk * c = stream->chunks + n; - switch ( c->type ) - { - case DUMB_ID( 'P', 'A', 'T', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, f, c->size ) ) goto error_usd; - ++ sigdata->n_patterns; - break; - - case DUMB_ID( 'I', 'N', 'S', 'T' ): - if ( dumbfile_seek( f, c->offset, DFS_SEEK_SET ) ) goto error_usd; - if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, f, c->size ) ) goto error_usd; - ++ sigdata->n_samples; - break; - } - } - - _dumb_it_fix_invalid_orders( sigdata ); - - return sigdata; - -error_usd: - _dumb_it_unload_sigdata( sigdata ); - goto error; -error_sd: - free( sigdata ); -error: - return NULL; -} - -DUH *dumb_read_riff_dsmf( DUMBFILE * f, struct riff * stream ) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_riff_dsmf_load_sigdata( f, stream ); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "RIFF DSMF"; - return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata ); - } -} diff --git a/libraries/dumb/src/it/readmod.c b/libraries/dumb/src/it/readmod.c deleted file mode 100644 index f73802798..000000000 --- a/libraries/dumb/src/it/readmod.c +++ /dev/null @@ -1,633 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readmod.c - Code to read a good old-fashioned / / \ \ - * Amiga module from an open file. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - - - -static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer) -{ - int pos; - int channel; - int row; - IT_ENTRY *entry; - - pattern->n_rows = 64; - - if (n_channels == 0) { - /* Read the first four channels, leaving gaps for the rest. */ - for (pos = 0; pos < 64*8*4; pos += 8*4) - dumbfile_getnc((char *)buffer + pos, 4*4, f); - /* Read the other channels into the gaps we left. */ - for (pos = 4*4; pos < 64*8*4; pos += 8*4) - dumbfile_getnc((char *)buffer + pos, 4*4, f); - - n_channels = 8; - } else - dumbfile_getnc((char *)buffer, 64 * n_channels * 4, f); - - if (dumbfile_error(f)) - return -1; - - /* compute number of entries */ - pattern->n_entries = 64; /* Account for the row end markers */ - pos = 0; - for (row = 0; row < 64; row++) { - for (channel = 0; channel < n_channels; channel++) { - if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) - pattern->n_entries++; - pos += 4; - } - } - - pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); - if (!pattern->entry) - return -1; - - entry = pattern->entry; - pos = 0; - for (row = 0; row < 64; row++) { - for (channel = 0; channel < n_channels; channel++) { - if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) { - unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4); - int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1]; - - entry->channel = channel; - entry->mask = 0; - - if (period) { - int note; - entry->mask |= IT_ENTRY_NOTE; - - /* frequency = (AMIGA_DIVISOR / 8) / (period * 2) - * C-1: period = 214 -> frequency = 16726 - * so, set C5_speed to 16726 - * and period = 214 should translate to C5 aka 60 - * halve the period, go up an octive - * - * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60) - * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period - * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE) - */ - note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5); - entry->note = MID(0, note, 119); - // or should we preserve the period? - //entry->note = buffer[pos+0] & 0x0F; /* High nibble */ - //entry->volpan = buffer[pos+1]; /* Low byte */ - // and what about finetune? - } - - if (sample) { - entry->mask |= IT_ENTRY_INSTRUMENT; - entry->instrument = sample; - } - - _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry, 1); - - entry++; - } - pos += 4; - } - IT_SET_END_ROW(entry); - entry++; - } - - return 0; -} - - - -static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f, int stk) -{ - int finetune, loop_start, loop_length; - -/** - 21 22 Chars Sample 1 name. If the name is not a full - 22 chars in length, it will be null - terminated. - -If -the sample name begins with a '#' character (ASCII $23 (35)) then this is -assumed not to be an instrument name, and is probably a message. -*/ - dumbfile_getnc((char *)sample->name, 22, f); - sample->name[22] = 0; - - sample->filename[0] = 0; - - sample->length = dumbfile_mgetw(f) << 1; - finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */ -/** Each finetune step changes the note 1/8th of a semitone. */ - sample->global_volume = 64; - sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead? - loop_start = dumbfile_mgetw(f); - if ( !stk ) loop_start <<= 1; - loop_length = dumbfile_mgetw(f) << 1; - if ( loop_length > 2 && loop_start + loop_length > sample->length && loop_start / 2 + loop_length <= sample->length ) - loop_start /= 2; - sample->loop_start = loop_start; - sample->loop_end = loop_start + loop_length; -/** -Once this sample has been played completely from beginning -to end, if the repeat length (next field) is greater than two bytes it -will loop back to this position in the sample and continue playing. Once -it has played for the repeat length, it continues to loop back to the -repeat start offset. This means the sample continues playing until it is -told to stop. -*/ - - if (sample->length <= 0) { - sample->flags = 0; - return 0; - } - - sample->flags = IT_SAMPLE_EXISTS; - - sample->default_pan = 0; - sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32)); - sample->finetune = finetune * 32; - // the above line might be wrong - - if (sample->loop_end > sample->length) - sample->loop_end = sample->length; - - if (sample->loop_end - sample->loop_start > 2) - sample->flags |= IT_SAMPLE_LOOP; - - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; // do we have to set _all_ these? - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - - - -static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, uint32 fft) -{ - int32 i; - int32 truncated_size; - - /* let's get rid of the sample data coming after the end of the loop */ - if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { - truncated_size = sample->length - sample->loop_end; - sample->length = sample->loop_end; - } else { - truncated_size = 0; - } - - if (sample->length) { - sample->data = malloc(sample->length); - - if (!sample->data) - return -1; - - /* Sample data are stored in "8-bit two's compliment format" (sic). */ - /* - for (i = 0; i < sample->length; i++) - ((signed char *)sample->left)[i] = dumbfile_getc(f); - */ - /* F U Olivier Lapicque */ - if (sample->length >= 5) - { - i = dumbfile_getnc(sample->data, 5, f); - if (i == 5) - { - if (!memcmp(sample->data, "ADPCM", 5)) - { - if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) - return -1; - - return 0; - } - else - { - i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f); - } - } - } - else - { - i = dumbfile_getnc(sample->data, sample->length, f); - } - if (i < sample->length) - { - if (i <= 0) - { - sample->flags = 0; - return 0; - } - sample->length = i; - if (sample->loop_end > i) sample->loop_end = i; - // holy crap! - if (sample->loop_start > i) sample->flags &= ~IT_SAMPLE_LOOP; - } - else - { - /* skip truncated data */ - int feh = dumbfile_error(f); - - if (truncated_size) dumbfile_skip(f, truncated_size); - // Should we be truncating it? - - if (feh) - return -1; - } - - if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { - int delta = 0; - for (i = 0; i < sample->length; i++) { - delta += ((signed char *)sample->data)[i]; - ((signed char *)sample->data)[i] = delta; - } - } - } - - return 0; -} - - - - -#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128) - -static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict_) -{ - DUMB_IT_SIGDATA *sigdata; - int n_channels; - int i; - uint32 fft; - - if ( dumbfile_seek(f, MOD_FFT_OFFSET, DFS_SEEK_SET) ) - return NULL; - - fft = dumbfile_mgetl(f); - if (dumbfile_error(f)) - return NULL; - - if ( dumbfile_seek(f, 0, DFS_SEEK_SET) ) - return NULL; - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) { - return NULL; - } - - /** - 1 20 Chars Title of the song. If the title is not a - full 20 chars in length, it will be null- - terminated. - */ - if (dumbfile_getnc((char *)sigdata->name, 20, f) < 20) { - free(sigdata); - return NULL; - } - sigdata->name[20] = 0; - - sigdata->n_samples = 31; - - switch (fft) { - case DUMB_ID('M','.','K','.'): - case DUMB_ID('M','!','K','!'): - case DUMB_ID('M','&','K','!'): - case DUMB_ID('N','.','T','.'): - case DUMB_ID('N','S','M','S'): - case DUMB_ID('F','L','T','4'): - case DUMB_ID('M',0,0,0): - case DUMB_ID('8',0,0,0): - n_channels = 4; - break; - case DUMB_ID('F','L','T','8'): - n_channels = 0; - /* 0 indicates a special case; two four-channel patterns must be - * combined into one eight-channel pattern. Pattern indexes must - * be halved. Why oh why do they obfuscate so? - */ - /*for (i = 0; i < 128; i++) - sigdata->order[i] >>= 1;*/ - break; - case DUMB_ID('C','D','8','1'): - case DUMB_ID('O','C','T','A'): - case DUMB_ID('O','K','T','A'): - n_channels = 8; - break; - case DUMB_ID('1','6','C','N'): - n_channels = 16; - break; - case DUMB_ID('3','2','C','N'): - n_channels = 32; - break; - default: - /* If we get an illegal tag, assume 4 channels 15 samples. */ - if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) { - if (fft >= '1' << 24 && fft < '4' << 24) { - n_channels = ((fft & 0x00FF0000L) >> 16) - '0'; - if ((unsigned int)n_channels >= 10) { - /* Rightmost character wasn't a digit. */ - n_channels = 4; - sigdata->n_samples = 15; - } else { - n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10; - /* MODs should really only go up to 32 channels, but we're lenient. */ - if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) { - /* No channels or too many? Can't be right... */ - n_channels = 4; - sigdata->n_samples = 15; - } - } - } else { - n_channels = 4; - sigdata->n_samples = 15; - } - } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) { - n_channels = (fft >> 24) - '0'; - if ((unsigned int)(n_channels - 1) >= 9) { - /* Character was '0' or it wasn't a digit */ - n_channels = 4; - sigdata->n_samples = 15; - } - } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) { - n_channels = (fft & 0x000000FFL) - '0'; - if ((unsigned int)(n_channels - 1) >= 9) { - /* We've been very lenient, given that it should have - * been 1, 2 or 3, but this MOD has been very naughty and - * must be punished. - */ - n_channels = 4; - sigdata->n_samples = 15; - } - } else { - n_channels = 4; - sigdata->n_samples = 15; - } - } - - // moo - if ( ( restrict_ & 1 ) && sigdata->n_samples == 15 ) - { - free(sigdata); - return NULL; - } - - sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */ - - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - free(sigdata); - return NULL; - } - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - - for (i = 0; i < sigdata->n_samples; i++) - sigdata->sample[i].data = NULL; - - for (i = 0; i < sigdata->n_samples; i++) { - if (it_mod_read_sample_header(&sigdata->sample[i], f, sigdata->n_samples == 15)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - - sigdata->n_orders = dumbfile_getc(f); - sigdata->restart_position = dumbfile_getc(f); - // what if this is >= 127? what about with Fast Tracker II? - -/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right? - _dumb_it_unload_sigdata(sigdata); - return NULL; - }*/ - - //if (sigdata->restart_position >= sigdata->n_orders) - //sigdata->restart_position = 0; - - sigdata->order = malloc(128); /* We may need to scan the extra ones! */ - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right? - sigdata->n_orders = 128; - //while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders - 1]) sigdata->n_orders--; - } - - if ( ! n_channels ) - for (i = 0; i < 128; i++) - sigdata->order[i] >>= 1; - - /* "The old NST format contains only 15 samples (instead of 31). Further - * it doesn't contain a file format tag (id). So Pattern data offset is - * at 20+15*30+1+1+128." - * - Then I shall assume the File Format Tag never exists if there are - * only 15 samples. I hope this isn't a faulty assumption... - */ - if (sigdata->n_samples == 31) - dumbfile_skip(f, 4); - - sigdata->n_patterns = -1; - - if ( ( restrict_ & 2 ) ) - { - unsigned char buffer[5]; - long sample_number; - long total_sample_size; - long offset = dumbfile_pos(f); - long remain = dumbfile_get_size(f) - offset; - if ( dumbfile_error( f ) || - dumbfile_seek( f, 0, SEEK_END ) ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - sample_number = sigdata->n_samples - 1; - total_sample_size = 0; - while (dumbfile_pos(f) > offset && sample_number >= 0) { - if (sigdata->sample[sample_number].flags & IT_SAMPLE_EXISTS) { - if ( dumbfile_seek(f, -((sigdata->sample[sample_number].length + 1) / 2 + 5 + 16), DFS_SEEK_CUR) || - dumbfile_getnc((char *)buffer, 5, f) < 5 ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - if ( !memcmp( buffer, "ADPCM", 5 ) ) { /* BAH */ - total_sample_size += (sigdata->sample[sample_number].length + 1) / 2 + 5 + 16; - if ( dumbfile_seek(f, -5, DFS_SEEK_CUR) ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } else { - total_sample_size += sigdata->sample[sample_number].length; - if ( dumbfile_seek(f, -(sigdata->sample[sample_number].length - ((sigdata->sample[sample_number].length + 1) / 2 + 5 + 16) + 5), DFS_SEEK_CUR) ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - } - --sample_number; - } - - if (remain > total_sample_size) { - sigdata->n_patterns = ( remain - total_sample_size + 4 ) / ( 256 * sigdata->n_pchannels ); - if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { - remain -= sigdata->n_patterns * 256 * sigdata->n_pchannels; - if (dumbfile_skip(f, remain - total_sample_size)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - } - } - else - { - for (i = 0; i < 128; i++) - { - if (sigdata->order[i] > sigdata->n_patterns) - sigdata->n_patterns = sigdata->order[i]; - } - sigdata->n_patterns++; - } - - if ( sigdata->n_patterns <= 0 ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - /* May as well try to save a tiny bit of memory. */ - if (sigdata->n_orders < 128) { - unsigned char *order = realloc(sigdata->order, sigdata->n_orders); - if (order) sigdata->order = order; - } - - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) - sigdata->pattern[i].entry = NULL; - - /* Read in the patterns */ - { - unsigned char *buffer = malloc(256 * sigdata->n_pchannels); /* 64 rows * 4 bytes */ - if (!buffer) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) { - if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) { - free(buffer); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - free(buffer); - } - - /* And finally, the sample data */ - for (i = 0; i < sigdata->n_samples; i++) { - if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - - /* w00t! */ - /*if ( n_channels == 4 && - ( sigdata->n_samples == 15 || - ( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) && - ( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) && - ( fft & 240 ) != 0 ) ) ) { - for ( i = 0; i < sigdata->n_samples; ++i ) { - IT_SAMPLE * sample = &sigdata->sample [i]; - if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) { - int n, o; - o = sample->length; - if ( o > 4 ) o = 4; - for ( n = 0; n < o; ++n ) - ( ( char * ) sample->data ) [n] = 0; - } - } - }*/ - - /* Now let's initialise the remaining variables, and we're done! */ - sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - /* We want 50 ticks per second; 50/6 row advances per second; - * 50*10=500 row advances per minute; 500/4=125 beats per minute. - */ - sigdata->speed = 6; - sigdata->tempo = 125; - sigdata->pan_separation = 128; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[i+0] = 32 - sep; - sigdata->channel_pan[i+1] = 32 + sep; - sigdata->channel_pan[i+2] = 32 + sep; - sigdata->channel_pan[i+3] = 32 - sep; - } - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - - - -DUH *DUMBEXPORT dumb_read_mod_quick(DUMBFILE *f, int restrict_) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_mod_load_sigdata(f, restrict_); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "MOD"; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readmod2.c b/libraries/dumb/src/it/readmod2.c deleted file mode 100644 index e1e7a9ce0..000000000 --- a/libraries/dumb/src/it/readmod2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readmod2.c - Function to read a good old- / / \ \ - * fashioned Amiga module from an | < / \_ - * open file and do an initial | \/ /\ / - * run-through. \_ / > / - * | \ / / - * Split off from readmod.c by entheh. | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_mod(DUMBFILE *f, int restrict_) -{ - DUH *duh = dumb_read_mod_quick(f, restrict_); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readmtm.c b/libraries/dumb/src/it/readmtm.c deleted file mode 100644 index 77c4f9c76..000000000 --- a/libraries/dumb/src/it/readmtm.c +++ /dev/null @@ -1,413 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readmtm.c - Code to read a MultiTracker Module / / \ \ - * from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -static size_t strlen_max(const char * ptr, size_t max) -{ - const char * end, * start; - if (ptr==0) return 0; - start = ptr; - end = ptr + max; - while(*ptr && ptr < end) ptr++; - return ptr - start; -} - -static int it_mtm_assemble_pattern(IT_PATTERN *pattern, const unsigned char * track, const unsigned short * sequence, int n_rows) -{ - int n, o, note, sample; - const unsigned char * t; - IT_ENTRY * entry; - - pattern->n_rows = n_rows; - pattern->n_entries = n_rows; - - for (n = 0; n < 32; n++) { - if (sequence[n]) { - t = &track[192 * (sequence[n] - 1)]; - for (o = 0; o < n_rows; o++) { - if (t[0] || t[1] || t[2]) pattern->n_entries++; - t += 3; - } - } - } - - entry = malloc(pattern->n_entries * sizeof(*entry)); - if (!entry) return -1; - pattern->entry = entry; - - for (n = 0; n < n_rows; n++) { - for (o = 0; o < 32; o++) { - if (sequence[o]) { - t = &track[192 * (sequence[o] - 1) + (n * 3)]; - if (t[0] || t[1] || t[2]) { - entry->channel = o; - entry->mask = 0; - note = t[0] >> 2; - sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F; - - if (note) { - entry->mask |= IT_ENTRY_NOTE; - entry->note = note + 24; - } - - if (sample) { - entry->mask |= IT_ENTRY_INSTRUMENT; - entry->instrument = sample; - } - - _dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1); - - if (entry->mask) entry++; - } - } - } - IT_SET_END_ROW(entry); - entry++; - } - - pattern->n_entries = (int)(entry - pattern->entry); - - return 0; -} - -static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) -{ - int finetune, flags; - - dumbfile_getnc((char *)sample->name, 22, f); - sample->name[22] = 0; - - sample->filename[0] = 0; - - sample->length = dumbfile_igetl(f); - sample->loop_start = dumbfile_igetl(f); - sample->loop_end = dumbfile_igetl(f); - finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */ - sample->global_volume = 64; - sample->default_volume = dumbfile_getc(f); - - flags = dumbfile_getc(f); - - if (sample->length <= 0) { - sample->flags = 0; - return 0; - } - - sample->flags = IT_SAMPLE_EXISTS; - - if (flags & 1) { - sample->flags |= IT_SAMPLE_16BIT; - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - - sample->default_pan = 0; - sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32)); - sample->finetune = finetune * 32; - // the above line might be wrong - - if (sample->loop_end > sample->length) - sample->loop_end = sample->length; - - if (sample->loop_end - sample->loop_start > 2) - sample->flags |= IT_SAMPLE_LOOP; - - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; // do we have to set _all_ these? - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - -static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) -{ - int32 i; - int32 truncated_size; - - /* let's get rid of the sample data coming after the end of the loop */ - if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { - truncated_size = sample->length - sample->loop_end; - sample->length = sample->loop_end; - } else { - truncated_size = 0; - } - - sample->data = malloc(sample->length); - - if (!sample->data) - return -1; - - dumbfile_getnc((char *)sample->data, sample->length, f); - dumbfile_skip(f, truncated_size); - - if (dumbfile_error(f)) - return -1; - - for (i = 0; i < sample->length; i++) - ((signed char *)sample->data)[i] ^= 0x80; - - return 0; -} - -static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version) -{ - DUMB_IT_SIGDATA *sigdata; - - int n, o, n_tracks, l_comment, n_rows, n_channels; - - unsigned char * track; - - unsigned short * sequence; - - char * comment; - - if (dumbfile_getc(f) != 'M' || - dumbfile_getc(f) != 'T' || - dumbfile_getc(f) != 'M') goto error; - - *version = dumbfile_getc(f); - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) goto error; - - dumbfile_getnc((char *)sigdata->name, 20, f); - sigdata->name[20] = 0; - - n_tracks = dumbfile_igetw(f); - sigdata->n_patterns = dumbfile_getc(f) + 1; - sigdata->n_orders = dumbfile_getc(f) + 1; - l_comment = dumbfile_igetw(f); - sigdata->n_samples = dumbfile_getc(f); - //if (dumbfile_getc(f)) goto error_sd; - dumbfile_getc(f); - n_rows = dumbfile_getc(f); - n_channels = dumbfile_getc(f); - - if (dumbfile_error(f) || - (n_tracks <= 0) || - (sigdata->n_samples <= 0) || - (n_rows <= 0 || n_rows > 64) || - (n_channels <= 0 || n_channels > 32)) goto error_sd; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - if (dumbfile_getnc((char *)sigdata->channel_pan, 32, f) < 32) goto error_sd; - - for (n = 0; n < 32; n++) { - if (sigdata->channel_pan[n] <= 15) { - sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3; - sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7; - } else { - sigdata->channel_volume[n] = 0; - sigdata->channel_pan[n] = 7; - } - } - - for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[n ] = 32 - sep; - sigdata->channel_pan[n+1] = 32 + sep; - sigdata->channel_pan[n+2] = 32 + sep; - sigdata->channel_pan[n+3] = 32 - sep; - } - - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) goto error_sd; - - sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - sigdata->speed = 6; - sigdata->tempo = 125; - sigdata->pan_separation = 128; - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - - sigdata->restart_position = 0; - sigdata->n_pchannels = n_channels; - - for (n = 0; n < sigdata->n_samples; n++) - sigdata->sample[n].data = NULL; - - for (n = 0; n < sigdata->n_samples; n++) { - if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd; - } - - sigdata->order = malloc(sigdata->n_orders); - if (!sigdata->order) goto error_usd; - - if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_usd; - if (sigdata->n_orders < 128) - if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_usd; - - track = malloc(192 * n_tracks); - if (!track) goto error_usd; - - if (dumbfile_getnc((char *)track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft; - - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) goto error_ft; - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - - sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence)); - if (!sequence) goto error_ft; - - for (n = 0; n < sigdata->n_patterns; n++) { - for (o = 0; o < 32; o++) { - sequence[(n * 32) + o] = dumbfile_igetw(f); - if (sequence[(n * 32) + o] > n_tracks) - { - //goto error_fs; - // illegal track number, silence instead of rejecting the file - sequence[(n * 32) + o] = 0; - } - } - } - - for (n = 0; n < sigdata->n_patterns; n++) { - if (it_mtm_assemble_pattern(&sigdata->pattern[n], track, &sequence[n * 32], n_rows)) goto error_fs; - } - - if (l_comment) { - comment = malloc(l_comment); - if (!comment) goto error_fs; - if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc; - - /* Time for annoying "logic", yes. We want each line which has text, - * and each blank line in between all the valid lines. - */ - - /* Find last actual line. */ - for (o = -1, n = 0; n < l_comment; n += 40) { - if (comment[n]) o = n; - } - - if (o >= 0) { - - size_t l; - int m; - for (l = 0, n = 0; n <= o; n += 40) { - l += strlen_max(&comment[n], 40) + 2; - } - - l -= 1; - - sigdata->song_message = malloc(l); - if (!sigdata->song_message) goto error_fc; - - for (m = 0, n = 0; n <= o; n += 40) { - int p = (int)strlen_max(&comment[n], 40); - if (p) { - memcpy(sigdata->song_message + m, &comment[n], p); - m += p; - } - if (l - m > 1) { - sigdata->song_message[m++] = 13; - sigdata->song_message[m++] = 10; - } - } - - sigdata->song_message[m] = 0; - } - - free(comment); - } - - for (n = 0; n < sigdata->n_samples; n++) { - if (it_mtm_read_sample_data(&sigdata->sample[n], f)) goto error_fs; - } - - _dumb_it_fix_invalid_orders(sigdata); - - free(sequence); - free(track); - - return sigdata; - -error_fc: - free(comment); -error_fs: - free(sequence); -error_ft: - free(track); -error_usd: - _dumb_it_unload_sigdata(sigdata); - return NULL; - -error_sd: - free(sigdata); -error: - return NULL; -} - -static char hexdigit(int in) -{ - if (in < 10) return in + '0'; - else return in + 'A' - 10; -} - -DUH *DUMBEXPORT dumb_read_mtm_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - int ver; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_mtm_load_sigdata(f, &ver); - - if (!sigdata) - return NULL; - - { - char version[16]; - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - version[0] = 'M'; - version[1] = 'T'; - version[2] = 'M'; - version[3] = ' '; - version[4] = 'v'; - version[5] = hexdigit(ver >> 4); - version[6] = '.'; - version[7] = hexdigit(ver & 15); - version[8] = 0; - tag[1][1] = (const char *) &version; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readokt.c b/libraries/dumb/src/it/readokt.c deleted file mode 100644 index c1dc1ce13..000000000 --- a/libraries/dumb/src/it/readokt.c +++ /dev/null @@ -1,558 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readokt.c - Code to read an Oktalyzer module / / \ \ - * from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - - - -static int it_okt_read_pattern(IT_PATTERN *pattern, const unsigned char *data, int length, int n_channels) -{ - int pos; - int channel; - int row; - int n_rows; - IT_ENTRY *entry; - - if (length < 2) return -1; - - n_rows = (data[0] << 8) | data[1]; - if (!n_rows) n_rows = 64; - - if (length < 2 + (n_rows * n_channels * 4)) return -1; - - pattern->n_rows = n_rows; - - /* compute number of entries */ - pattern->n_entries = n_rows; /* Account for the row end markers */ - pos = 2; - for (row = 0; row < pattern->n_rows; row++) { - for (channel = 0; channel < n_channels; channel++) { - if (data[pos+0] | data[pos+2]) - pattern->n_entries++; - pos += 4; - } - } - - pattern->entry = (IT_ENTRY *) malloc(pattern->n_entries * sizeof(*pattern->entry)); - if (!pattern->entry) - return -1; - - entry = pattern->entry; - pos = 2; - for (row = 0; row < n_rows; row++) { - for (channel = 0; channel < n_channels; channel++) { - if (data[pos+0] | data[pos+2]) { - entry->channel = channel; - entry->mask = 0; - - if (data[pos+0] > 0 && data[pos+0] <= 36) { - entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT; - - entry->note = data[pos+0] + 35; - entry->instrument = data[pos+1] + 1; - } - - entry->effect = 0; - entry->effectvalue = data[pos+3]; - - switch (data[pos+2]) { - case 2: if (data[pos+3]) entry->effect = IT_PORTAMENTO_DOWN; break; // XXX code calls this rs_portu, but it's adding to the period, which decreases the pitch - case 13: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN; break; - case 21: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_DOWN_ROW; break; - - case 1: if (data[pos+3]) entry->effect = IT_PORTAMENTO_UP; break; // XXX same deal here, increasing the pitch - case 17: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP; break; - case 30: if (data[pos+3]) entry->effect = IT_OKT_NOTE_SLIDE_UP_ROW; break; - - case 10: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_3; break; - case 11: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_4; break; - case 12: if (data[pos+3]) entry->effect = IT_OKT_ARPEGGIO_5; break; - - case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_SET_FILTER, data[pos+3] & 0x0F); break; - - case 25: entry->effect = IT_JUMP_TO_ORDER; break; - - case 27: entry->note = IT_NOTE_OFF; entry->mask |= IT_ENTRY_NOTE; break; - - case 28: entry->effect = IT_SET_SPEED; break; - - case 31: - if ( data[pos+3] <= 0x40 ) entry->effect = IT_SET_CHANNEL_VOLUME; - else if ( data[pos+3] <= 0x50 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x40; } - else if ( data[pos+3] <= 0x60 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x50; } - else if ( data[pos+3] <= 0x70 ) { entry->effect = IT_OKT_VOLUME_SLIDE_DOWN; entry->effectvalue = data[pos+3] - 0x50; } - else if ( data[pos+3] <= 0x80 ) { entry->effect = IT_OKT_VOLUME_SLIDE_UP; entry->effectvalue = data[pos+3] - 0x60; } - break; - } - - if ( entry->effect ) entry->mask |= IT_ENTRY_EFFECT; - - entry++; - } - pos += 4; - } - IT_SET_END_ROW(entry); - entry++; - } - - return 0; -} - - - -static void it_okt_read_sample_header(IT_SAMPLE *sample, const unsigned char * data) -{ - int loop_start, loop_length; - - memcpy(sample->name, data, 20); - sample->name[20] = 0; - - sample->filename[0] = 0; - - sample->length = (data[20] << 24) | (data[21] << 16) | (data[22] << 8) | data[23]; - sample->global_volume = 64; - sample->default_volume = data[29]; - loop_start = ((data[24] << 8) | data[25]) << 1; - loop_length = ((data[26] << 8) | data[27]) << 1; - sample->sus_loop_start = loop_start; - sample->sus_loop_end = loop_start + loop_length; - - if (sample->length <= 0) { - sample->flags = 0; - return; - } - - sample->flags = IT_SAMPLE_EXISTS; - - sample->default_pan = 0; - sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32)); - sample->finetune = 0; - - if (sample->sus_loop_end > sample->length) - sample->sus_loop_end = sample->length; - - if (loop_length > 2) - sample->flags |= IT_SAMPLE_SUS_LOOP; - - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = 0; // do we have to set _all_ these? - sample->max_resampling_quality = -1; -} - - - -static int it_okt_read_sample_data(IT_SAMPLE *sample, const char * data, int length) -{ - if (length && sample->length) { - if (length < sample->length) { - sample->length = length; - if (length < sample->sus_loop_end) sample->sus_loop_end = length; - } - - sample->data = malloc(length); - - if (!sample->data) - return -1; - - memcpy(sample->data, data, length); - } - - return 0; -} - - - -typedef struct IFF_CHUNK IFF_CHUNK; -typedef struct IFF_CHUNKED IFF_CHUNKED; - -struct IFF_CHUNK -{ - unsigned type; - unsigned char * data; - unsigned size; -}; - -struct IFF_CHUNKED -{ - unsigned chunk_count; - IFF_CHUNK * chunks; -}; - - - -static IFF_CHUNKED *dumbfile_read_okt(DUMBFILE *f) -{ - IFF_CHUNKED *mod = (IFF_CHUNKED *) malloc(sizeof(*mod)); - if (!mod) return NULL; - - mod->chunk_count = 0; - mod->chunks = 0; - - for (;;) - { - long bytes_read; - IFF_CHUNK * chunk = ( IFF_CHUNK * ) realloc( mod->chunks, ( mod->chunk_count + 1 ) * sizeof( IFF_CHUNK ) ); - if ( !chunk ) - { - if ( mod->chunks ) free( mod->chunks ); - free( mod ); - return NULL; - } - mod->chunks = chunk; - chunk += mod->chunk_count; - - bytes_read = dumbfile_mgetl( f ); - if ( bytes_read < 0 ) break; - - chunk->type = bytes_read; - chunk->size = dumbfile_mgetl( f ); - - if ( dumbfile_error( f ) ) break; - - chunk->data = (unsigned char *) malloc( chunk->size ); - if ( !chunk->data ) - { - free( mod->chunks ); - free( mod ); - return NULL; - } - - bytes_read = dumbfile_getnc( ( char * ) chunk->data, chunk->size, f ); - if ( bytes_read < (long)chunk->size ) - { - if ( bytes_read <= 0 ) { - free( chunk->data ); - break; - } else { - chunk->size = bytes_read; - mod->chunk_count++; - break; - } - } - - mod->chunk_count++; - } - - if ( !mod->chunk_count ) { - if ( mod->chunks ) free(mod->chunks); - free(mod); - mod = NULL; - } - - return mod; -} - -void free_okt(IFF_CHUNKED * mod) -{ - unsigned i; - if (mod) - { - if (mod->chunks) - { - for (i = 0; i < mod->chunk_count; i++) - { - if (mod->chunks[i].data) free(mod->chunks[i].data); - } - free(mod->chunks); - } - free(mod); - } -} - -const IFF_CHUNK * get_chunk_by_type(IFF_CHUNKED * mod, unsigned type, unsigned offset) -{ - unsigned i; - if (mod) - { - if (mod->chunks) - { - for (i = 0; i < mod->chunk_count; i++) - { - if (mod->chunks[i].type == type) - { - if (!offset) return &mod->chunks[i]; - else offset--; - } - } - } - } - return NULL; -} - -unsigned get_chunk_count(IFF_CHUNKED *mod, unsigned type) -{ - unsigned i, count = 0; - if (mod) - { - if (mod->chunks) - { - for (i = 0; i < mod->chunk_count; i++) - { - if (mod->chunks[i].type == type) count++; - } - } - } - return count; -} - - -static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f) -{ - DUMB_IT_SIGDATA *sigdata; - int n_channels; - int i, j, k, l; - IFF_CHUNKED *mod; - const IFF_CHUNK *chunk; - - char signature[8]; - - if (dumbfile_getnc(signature, 8, f) < 8 || - memcmp(signature, "OKTASONG", 8)) { - return NULL; - } - - mod = dumbfile_read_okt(f); - if (!mod) - return NULL; - - sigdata = (DUMB_IT_SIGDATA *) malloc(sizeof(*sigdata)); - if (!sigdata) { - free_okt(mod); - return NULL; - } - - sigdata->name[0] = 0; - - chunk = get_chunk_by_type(mod, DUMB_ID('S','P','E','E'), 0); - if (!chunk || chunk->size < 2) { - free(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->speed = (chunk->data[0] << 8) | chunk->data[1]; - - chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0); - if (!chunk || chunk->size < 32) { - free(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->n_samples = chunk->size / 32; - - chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); - if (!chunk || chunk->size < 8) { - free(sigdata); - free_okt(mod); - return NULL; - } - - n_channels = 0; - - for (i = 0; i < 4; i++) { - j = (chunk->data[i * 2] << 8) | chunk->data[i * 2 + 1]; - if (!j) n_channels++; - else if (j == 1) n_channels += 2; - } - - if (!n_channels) { - free(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->n_pchannels = n_channels; - - sigdata->sample = (IT_SAMPLE *) malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - free(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - - for (i = 0; (unsigned)i < (unsigned)sigdata->n_samples; i++) - sigdata->sample[i].data = NULL; - - chunk = get_chunk_by_type(mod, DUMB_ID('S','A','M','P'), 0); - - for (i = 0; (unsigned)i < (unsigned)sigdata->n_samples; i++) { - it_okt_read_sample_header(&sigdata->sample[i], chunk->data + 32 * i); - } - - sigdata->restart_position = 0; - - chunk = get_chunk_by_type(mod, DUMB_ID('P','L','E','N'), 0); - if (!chunk || chunk->size < 2) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->n_orders = (chunk->data[0] << 8) | chunk->data[1]; - // what if this is > 128? - - if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - - chunk = get_chunk_by_type(mod, DUMB_ID('P','A','T','T'), 0); - if (!chunk || chunk->size < (unsigned)sigdata->n_orders) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->order = (unsigned char *) malloc(sigdata->n_orders); - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - - memcpy(sigdata->order, chunk->data, sigdata->n_orders); - - /* Work out how many patterns there are. */ - chunk = get_chunk_by_type(mod, DUMB_ID('S','L','E','N'), 0); - if (!chunk || chunk->size < 2) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->n_patterns = (chunk->data[0] << 8) | chunk->data[1]; - - j = get_chunk_count(mod, DUMB_ID('P','B','O','D')); - if (sigdata->n_patterns > (int)j) sigdata->n_patterns = (int)j; - - if (!sigdata->n_patterns) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - - sigdata->pattern = (IT_PATTERN *) malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - for (i = 0; (unsigned)i < (unsigned)sigdata->n_patterns; i++) - sigdata->pattern[i].entry = NULL; - - /* Read in the patterns */ - for (i = 0; (unsigned)i < (unsigned)sigdata->n_patterns; i++) { - chunk = get_chunk_by_type(mod, DUMB_ID('P','B','O','D'), i); - if (it_okt_read_pattern(&sigdata->pattern[i], chunk->data, chunk->size, n_channels) != 0) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - } - - /* And finally, the sample data */ - k = get_chunk_count(mod, DUMB_ID('S','B','O','D')); - for (i = 0, j = 0; (unsigned)i < (unsigned)sigdata->n_samples && j < k; i++) { - if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { - chunk = get_chunk_by_type(mod, DUMB_ID('S','B','O','D'), j); - if (it_okt_read_sample_data(&sigdata->sample[i], (const char *)chunk->data, chunk->size)) { - _dumb_it_unload_sigdata(sigdata); - free_okt(mod); - return NULL; - } - j++; - } - } - for (; (unsigned)i < (unsigned)sigdata->n_samples; i++) { - sigdata->sample[i].flags = 0; - } - - chunk = get_chunk_by_type(mod, DUMB_ID('C','M','O','D'), 0); - - for (i = 0, j = 0; i < n_channels && j < 4; j++) { - k = (chunk->data[j * 2] << 8) | chunk->data[j * 2 + 1]; - l = (j == 1 || j == 2) ? 48 : 16; - if (k == 0) { - sigdata->channel_pan[i++] = l; - } - else if (k == 1) { - sigdata->channel_pan[i++] = l; - sigdata->channel_pan[i++] = l; - } - } - - free_okt(mod); - - /* Now let's initialise the remaining variables, and we're done! */ - sigdata->flags = IT_WAS_AN_OKT | IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - /* We want 50 ticks per second; 50/6 row advances per second; - * 50*10=500 row advances per minute; 500/4=125 beats per minute. - */ - sigdata->tempo = 125; - sigdata->pan_separation = 128; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - memset(sigdata->channel_pan + n_channels, 32, DUMB_IT_N_CHANNELS - n_channels); - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - - - -DUH *DUMBEXPORT dumb_read_okt_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_okt_load_sigdata(f); - - if (!sigdata) - return NULL; - - { - const char *tag[1][2]; - tag[0][0] = "FORMAT"; - tag[0][1] = "Oktalyzer"; - return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readokt2.c b/libraries/dumb/src/it/readokt2.c deleted file mode 100644 index ef54b8d0d..000000000 --- a/libraries/dumb/src/it/readokt2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readokt2.c - Function to read an Oktalyzer / / \ \ - * module from an open file and do | < / \_ - * an initial run-through. | \/ /\ / - * \_ / > / - * | \ / / - * By Chris Moeller. | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_okt(DUMBFILE *f) -{ - DUH *duh = dumb_read_okt_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readoldpsm.c b/libraries/dumb/src/it/readoldpsm.c deleted file mode 100644 index 3946568b8..000000000 --- a/libraries/dumb/src/it/readoldpsm.c +++ /dev/null @@ -1,689 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readpsm.c - Code to read an old Protracker / / \ \ - * Studio module from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -static int CDECL psm_sample_compare(const void *e1, const void *e2) -{ - const unsigned char * pa = e1; - const unsigned char * pb = e2; - int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24); - int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24); - return a - b; -} - -static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num) -{ - int n, o, count = *num, true_num, snum, offset, flags, finetune, delta; - - unsigned char * buffer; - const unsigned char * sdata; - int32 sample_bytes; - - buffer = malloc(count * 64); - if (!buffer) goto error; - - if (dumbfile_getnc((char *)buffer, count * 64, f) < count * 64) goto error_fb; - - true_num = 0; - - for (n = 0; n < count; n++) { - snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); - if ((snum < 1) || (snum > 255)) goto error_fb; - if (true_num < snum) true_num = snum; - } - - if (true_num > count) { - IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh)); - if (!meh) goto error_fb; - for (n = count; n < true_num; n++) { - meh[n].data = NULL; - } - *sample = meh; - *num = true_num; - } - - qsort(buffer, count, 64, &psm_sample_compare); - - for (n = 0; n < true_num; n++) { - (*sample)[n].flags = 0; - } - - for (n = 0; n < count; n++) { - IT_SAMPLE * s; - snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); - s = &((*sample)[snum - 1]); - memcpy(s->filename, buffer + (n * 64), 13); - s->filename[13] = 0; - memcpy(s->name, buffer + (n * 64) + 13, 24); - s->name[24] = 0; - offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) | - (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24); - flags = buffer[(n * 64) + 47]; - s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) | - (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24); - s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) | - (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24); - s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) | - (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24); - - if (s->length <= 0) continue; - - finetune = buffer[(n * 64) + 60]; - s->default_volume = buffer[(n * 64) + 61]; - s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8); - if (finetune & 15) { - finetune &= 15; - if (finetune >= 8) finetune -= 16; - //s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32)); - s->finetune = finetune * 32; - } - else s->finetune = 0; - - s->flags |= IT_SAMPLE_EXISTS; - if (flags & 0x41) { - s->flags &= ~IT_SAMPLE_EXISTS; - continue; - } - if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP; - if (flags & 4) s->flags |= IT_SAMPLE_16BIT; - - if (flags & 0x80) { - s->flags |= IT_SAMPLE_LOOP; - if ((unsigned int)s->loop_end > (unsigned int)s->length) - s->loop_end = s->length; - else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end) - s->flags &= ~IT_SAMPLE_LOOP; - else - s->length = s->loop_end; - } - - s->global_volume = 64; - - s->vibrato_speed = 0; - s->vibrato_depth = 0; - s->vibrato_rate = 0; - s->vibrato_waveform = IT_VIBRATO_SINE; - s->max_resampling_quality = -1; - - sample_bytes = s->length * ((flags & 4) ? 2 : 1); - s->data = malloc(sample_bytes); - if (!s->data) goto error_fb; - - if (dumbfile_seek(f, offset, DFS_SEEK_SET) || dumbfile_getnc(s->data, sample_bytes, f) < sample_bytes) goto error_fb; - sdata = ( const unsigned char * ) s->data; - - if (flags & 0x10) { - if (flags & 8) { - if (flags & 4) { - for (o = 0; o < s->length; o++) - ((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000; - } else { - for (o = 0; o < s->length; o++) - ((signed char *)s->data)[o] = sdata[o] ^ 0x80; - } - } else { - if (flags & 4) { - for (o = 0; o < s->length; o++) - ((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8); - } else { - memcpy(s->data, sdata, s->length); - } - } - } else { - delta = 0; - if (flags & 8) { - /* unsigned delta? mehhh, does anything even use this? */ - if (flags & 4) { - for (o = 0; o < s->length; o++) { - delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); - ((short *)s->data)[o] = delta ^ 0x8000; - } - } else { - for (o = 0; o < s->length; o++) { - delta += (signed char)sdata[o]; - ((signed char *)s->data)[o] = delta ^ 0x80; - } - } - } else { - if (flags & 4) { - for (o = 0; o < s->length; o++) { - delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); - ((short *)s->data)[o] = delta; - } - } else { - for (o = 0; o < s->length; o++) { - delta += (signed char)sdata[o]; - ((signed char *)s->data)[o] = delta; - } - } - } - } - } - - free(buffer); - - return 0; - -error_fb: - free(buffer); -error: - return -1; -} - -static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans) -{ - int n, offset, psize, rows, chans, row, flags, channel; - - unsigned char * buffer, * ptr, * end; - - IT_ENTRY * entry; - - buffer = malloc(size); - if (!buffer) goto error; - - if (dumbfile_getnc((char *)buffer, size, f) < size) goto error_fb; - - offset = 0; - - for (n = 0; n < num; n++) { - IT_PATTERN * p = &pattern[n]; - - if (offset >= size) goto error_fb; - - ptr = buffer + offset; - psize = ptr[0] | (ptr[1] << 8); - rows = ptr[2]; - chans = ptr[3]; - - if (!rows || !chans) { - p->n_rows = 1; - p->n_entries = 0; - continue; - } - - psize = (psize + 15) & ~15; - - end = ptr + psize; - ptr += 4; - - p->n_rows = rows; - p->n_entries = rows; - row = 0; - - while ((row < rows) && (ptr < end)) { - flags = *ptr++; - if (!flags) { - row++; - continue; - } - if (flags & 0xE0) { - p->n_entries++; - if (flags & 0x80) ptr += 2; - if (flags & 0x40) ptr++; - if (flags & 0x20) { - ptr++; - if (*ptr == 40) ptr += 3; - else ptr++; - } - } - } - - entry = malloc(p->n_entries * sizeof(*p->entry)); - if (!entry) goto error_fb; - - p->entry = entry; - - ptr = buffer + offset + 4; - row = 0; - - while ((row < rows) && (ptr < end)) { - flags = *ptr++; - if (!flags) { - IT_SET_END_ROW(entry); - entry++; - row++; - continue; - } - if (flags & 0xE0) { - entry->mask = 0; - entry->channel = channel = flags & 0x1F; - if (channel >= chans) - { - //channel = 0; - //goto error_fb; - } - if (flags & 0x80) { - if ((*ptr < 60) && (channel < pchans)) { - entry->mask |= IT_ENTRY_NOTE; - entry->note = *ptr + 35; - } - ptr++; - if (*ptr) { - entry->mask |= IT_ENTRY_INSTRUMENT; - entry->instrument = *ptr; - } - ptr++; - } - if (flags & 0x40) { - if (*ptr <= 64) { - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = *ptr; - } - ptr++; - } - if (flags & 0x20) { - entry->mask |= IT_ENTRY_EFFECT; - - switch (*ptr) { - case 1: - entry->effect = IT_XM_FINE_VOLSLIDE_UP; - entry->effectvalue = ptr[1]; - break; - - case 2: - entry->effect = IT_VOLUME_SLIDE; - entry->effectvalue = (ptr[1] << 4) & 0xF0; - break; - - case 3: - entry->effect = IT_XM_FINE_VOLSLIDE_DOWN; - entry->effectvalue = ptr[1]; - break; - - case 4: - entry->effect = IT_VOLUME_SLIDE; - entry->effectvalue = ptr[1] & 0xF; - break; - - case 10: - entry->effect = IT_PORTAMENTO_UP; - entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]); - break; - - case 11: - entry->effect = IT_PORTAMENTO_UP; - entry->effectvalue = ptr[1]; - break; - - case 12: - entry->effect = IT_PORTAMENTO_DOWN; - entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF); - break; - - case 13: - entry->effect = IT_PORTAMENTO_DOWN; - entry->effectvalue = ptr[1]; - break; - - case 14: - entry->effect = IT_TONE_PORTAMENTO; - entry->effectvalue = ptr[1]; - break; - - case 15: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15); - break; - - case 16: - entry->effect = IT_VOLSLIDE_TONEPORTA; - entry->effectvalue = ptr[1] << 4; - break; - - case 17: - entry->effect = IT_VOLSLIDE_TONEPORTA; - entry->effectvalue = ptr[1] & 0xF; - break; - - case 20: - entry->effect = IT_VIBRATO; - entry->effectvalue = ptr[1]; - break; - - case 21: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11); - break; - - case 22: - entry->effect = IT_VOLSLIDE_VIBRATO; - entry->effectvalue = ptr[1] << 4; - break; - - case 23: - entry->effect = IT_VOLSLIDE_VIBRATO; - entry->effectvalue = ptr[1] & 0xF; - break; - - case 30: - entry->effect = IT_TREMOLO; - entry->effectvalue = ptr[1]; - break; - - case 31: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11); - break; - - case 40: - entry->effect = IT_SET_SAMPLE_OFFSET; - entry->effectvalue = ptr[2]; - ptr += 2; - break; - - case 41: - entry->effect = IT_XM_RETRIGGER_NOTE; - entry->effectvalue = ptr[1]; - break; - - case 42: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF); - break; - - case 43: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF); - break; - - case 50: - entry->effect = IT_JUMP_TO_ORDER; - entry->effectvalue = ptr[1]; - break; - - case 51: - entry->effect = IT_BREAK_TO_ROW; - entry->effectvalue = ptr[1]; - break; - - case 52: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF); - break; - - case 53: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF); - break; - - case 60: - entry->effect = IT_SET_SPEED; - entry->effectvalue = ptr[1]; - break; - - case 61: - entry->effect = IT_SET_SONG_TEMPO; - entry->effectvalue = ptr[1]; - break; - - case 70: - entry->effect = IT_ARPEGGIO; - entry->effectvalue = ptr[1]; - break; - - case 71: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF); - break; - - case 72: - /* "balance" ... panning? */ - entry->effect = IT_SET_PANNING; - entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7; - break; - - default: - entry->mask &= ~IT_ENTRY_EFFECT; - } - - ptr += 2; - } - if (entry->mask) entry++; - } - } - - p->n_entries = (int)(entry - p->entry); - offset += psize; - } - - free(buffer); - - return 0; - -error_fb: - free(buffer); -error: - return -1; -} - -#define PSM_COMPONENT_ORDERS 0 -#define PSM_COMPONENT_PANPOS 1 -#define PSM_COMPONENT_PATTERNS 2 -#define PSM_COMPONENT_SAMPLE_HEADERS 3 -#define PSM_COMPONENT_COMMENTS 4 - -typedef struct PSM_COMPONENT -{ - unsigned char type; - int32 offset; -} -PSM_COMPONENT; - -static int CDECL psm_component_compare(const void *e1, const void *e2) -{ - return ((const PSM_COMPONENT *)e1)->offset - - ((const PSM_COMPONENT *)e2)->offset; -} - -static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f) -{ - DUMB_IT_SIGDATA *sigdata; - - PSM_COMPONENT *component; - int n_components = 0; - - int n, flags, version, pver, n_orders, n_channels, total_pattern_size; - - if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error; - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) goto error; - - if (dumbfile_getnc((char *)sigdata->name, 60, f) < 60 || - sigdata->name[59] != 0x1A) goto error_sd; - sigdata->name[59] = 0; - - flags = dumbfile_getc(f); - version = dumbfile_getc(f); - pver = dumbfile_getc(f); - sigdata->speed = dumbfile_getc(f); - sigdata->tempo = dumbfile_getc(f); - sigdata->mixing_volume = dumbfile_getc(f); - sigdata->n_orders = dumbfile_igetw(f); - n_orders = dumbfile_igetw(f); - sigdata->n_patterns = dumbfile_igetw(f); - sigdata->n_samples = dumbfile_igetw(f); - sigdata->n_pchannels = dumbfile_igetw(f); - n_channels = dumbfile_igetw(f); - - if (dumbfile_error(f) || - (flags & 1) || - (version != 1 && version != 0x10) || - (pver) || - (sigdata->n_orders <= 0) || - (sigdata->n_orders > 255) || - (n_orders > 255) || - (n_orders < sigdata->n_orders) || - (sigdata->n_patterns > 255) || - (sigdata->n_samples > 255) || - (sigdata->n_pchannels > DUMB_IT_N_CHANNELS) || - (sigdata->n_pchannels > n_channels) || - (n_channels > DUMB_IT_N_CHANNELS)) - goto error_sd; - - sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; - - sigdata->global_volume = 128; - sigdata->pan_separation = 128; - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - - sigdata->restart_position = 0; - - sigdata->order = malloc(sigdata->n_orders); - if (!sigdata->order) goto error_usd; - - if (sigdata->n_samples) { - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) goto error_usd; - for (n = 0; n < sigdata->n_samples; n++) - sigdata->sample[n].data = NULL; - } - - if (sigdata->n_patterns) { - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) goto error_usd; - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - } - - component = malloc(5 * sizeof(*component)); - if (!component) goto error_usd; - - for (n = 0; n < 5; n++) { - component[n_components].offset = dumbfile_igetl(f); - if (component[n_components].offset) { - component[n_components].type = n; - n_components++; - } - } - - if (!n_components) goto error_fc; - - total_pattern_size = dumbfile_igetl(f); - if (!total_pattern_size) goto error_fc; - - qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare); - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[n ] = 32 - sep; - sigdata->channel_pan[n+1] = 32 + sep; - sigdata->channel_pan[n+2] = 32 + sep; - sigdata->channel_pan[n+3] = 32 - sep; - } - - for (n = 0; n < n_components; n++) - { - int o; - - if ( dumbfile_seek(f, component[n].offset, DFS_SEEK_SET) ) goto error_fc; - - switch (component[n].type) { - - case PSM_COMPONENT_ORDERS: - if (dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fc; - if (n_orders > sigdata->n_orders) - if (dumbfile_skip(f, n_orders - sigdata->n_orders)) - goto error_fc; - if (dumbfile_igetw(f)) goto error_fc; - break; - - case PSM_COMPONENT_PANPOS: - if (dumbfile_getnc((char *)sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fc; - for (o = 0; o < sigdata->n_pchannels; o++) { - sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3; - sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7; - } - break; - - case PSM_COMPONENT_PATTERNS: - if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels)) goto error_fc; - break; - - case PSM_COMPONENT_SAMPLE_HEADERS: - if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples)) goto error_fc; - break; - - case PSM_COMPONENT_COMMENTS: - if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) { - o = dumbfile_igetw(f); - if (o > 0) { - sigdata->song_message = malloc(o + 1); - if (dumbfile_getnc((char *)sigdata->song_message, o, f) < o) goto error_fc; - sigdata->song_message[o] = 0; - } - } - break; - } - } - - _dumb_it_fix_invalid_orders(sigdata); - - free(component); - - return sigdata; - -error_fc: - free(component); -error_usd: - _dumb_it_unload_sigdata(sigdata); - return NULL; -error_sd: - free(sigdata); -error: - return NULL; -} - -DUH *DUMBEXPORT dumb_read_old_psm_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_old_psm_load_sigdata(f); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "PSM (old)"; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readpsm.c b/libraries/dumb/src/it/readpsm.c deleted file mode 100644 index 95545a528..000000000 --- a/libraries/dumb/src/it/readpsm.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readpsm.c - Code to read a Protracker Studio / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifdef _MSC_VER -#define snprintf sprintf_s -#endif - -#define PSMV_OLD 940730 -#define PSMV_NEW 940902 - -typedef struct _PSMCHUNK -{ - int id; - int len; - unsigned char * data; -} PSMCHUNK; - -typedef struct _PSMEVENT -{ - int type; - unsigned char data[8]; -} PSMEVENT; - -#define PSM_EVENT_END 0 -#define PSM_EVENT_PLAY_PATTERN 1 -#define PSM_EVENT_JUMP_TO_LINE 4 -#define PSM_EVENT_SET_SPEED 7 -#define PSM_EVENT_SET_BPM 8 -#define PSM_EVENT_SAMPLE_MAP_TABLE 12 -#define PSM_EVENT_CHANGE_PAN 13 -#define PSM_EVENT_CHANGE_VOL 14 - -static int it_psm_process_sample(IT_SAMPLE * sample, const unsigned char * data, int len, int id, int version) { - int flags; - int insno = 0; - int length = 0; - int loopstart = 0; - int loopend = 0; - int panpos; - int defvol = 0; - int samplerate = 0; - - if (len < 0x60) return -1; - - flags = data[0]; - - if (version == PSMV_OLD) { - memcpy(sample->name, data + 0x0D, 34); - sample->name[34] = 0; - - insno = data[0x34] | (data[0x35] << 8); - length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24); - loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); - loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); - panpos = data[0x43]; - defvol = data[0x44]; - samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24); - } else /*if (version == PSMV_NEW)*/ { - memcpy(sample->name, data + 0x11, 34); - sample->name[34] = 0; - - insno = data[0x38] | (data[0x39] << 8); - length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); - loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); - loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24); - panpos = data[0x48]; - defvol = data[0x49]; - samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24); - } - - if (insno != id) return -1; - - if (!length) { - sample->flags &= ~IT_SAMPLE_EXISTS; - return 0; - } - - if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1; - - sample->flags = IT_SAMPLE_EXISTS; - sample->length = length; - sample->loop_start = loopstart; - sample->loop_end = loopend; - sample->C5_speed = samplerate; - sample->default_volume = defvol >> 1; - sample->default_pan = 0; - sample->filename[0] = 0; - sample->global_volume = 64; - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = IT_VIBRATO_SINE; - sample->finetune = 0; - sample->max_resampling_quality = -1; - - if (flags & 0x80) { - if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && - ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) { - sample->length = sample->loop_end; - sample->flags |= IT_SAMPLE_LOOP; - } - } - - sample->data = malloc(sample->length); - if (!sample->data) - return -1; - - flags = 0; - data += 0x60; - - for (insno = 0; insno < sample->length; insno++) { - flags += (signed char)(*data++); - ((signed char *)sample->data)[insno] = flags; - } - - return 0; -} - -static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * data, int len, int speed, int bpm, const unsigned char * pan, const int * vol, int version) { - int length, nrows, row, rowlen, pos; - unsigned flags, chan; - IT_ENTRY * entry; - - length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - if (len > length) len = length; - - if (version == PSMV_OLD) { - if (len < 10) return -1; - data += 8; - len -= 8; - } else /*if (version == PSMV_NEW)*/ { - if (len < 14) return -1; - data += 12; - len -= 12; - } - - nrows = data[0] | (data[1] << 8); - - if (!nrows) return 0; - - pattern->n_rows = nrows; - - data += 2; - len -= 2; - - pattern->n_entries = 0; - - row = 0; - pos = 2; - rowlen = data[0] | (data[1] << 8); - - while ((row < nrows) && (pos < len)) { - if (pos >= rowlen) { - row++; - rowlen += data[pos] | (data[pos+1] << 8); - pos += 2; - continue; - } - - flags = data[pos++]; - chan = data[pos++]; - - if (chan > 63) return -1; - - if (flags & 0xF0) { - pattern->n_entries++; - if (flags & 0x80) pos++; - if (flags & 0x40) pos++; - if (flags & 0x20) pos++; - if (flags & 0x10) { - switch (data[pos]) { - case 0x29: - pos++; - case 0x33: - pos++; - default: - pos += 2; - } - } - } - } - - if (!pattern->n_entries) return 0; - - pattern->n_entries += nrows; - if (speed) pattern->n_entries++; - if (bpm >= 0x20) pattern->n_entries++; - - for (pos = 0; pos < 32; pos++) { - if (!(pan[pos*2+1] & 0xF9)) pattern->n_entries++; - if (vol[pos] != -1) pattern->n_entries++; - } - - pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); - if (!pattern->entry) return -1; - - entry = pattern->entry; - - if (speed) { - entry->channel = 0; - entry->mask = IT_ENTRY_EFFECT; - entry->effect = IT_SET_SPEED; - entry->effectvalue = speed; - entry++; - } - - if (bpm >= 0x20) { - entry->channel = 0; - entry->mask = IT_ENTRY_EFFECT; - entry->effect = IT_SET_SONG_TEMPO; - entry->effectvalue = bpm; - entry++; - } - - for (pos = 0; pos < 32; pos++) { - if (!(pan[pos*2+1] & 0xF9)) { - entry->channel = pos; - entry->mask = IT_ENTRY_EFFECT; - switch (pan[pos*2+1]) { - case 0: - entry->effect = IT_SET_PANNING; - entry->effectvalue = pan[pos*2] ^ 128; - break; - case 2: - entry->effect = IT_S; - entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND,1); - break; - case 4: - entry->effect = IT_SET_PANNING; - entry->effectvalue = 128; - break; - } - entry++; - } - if (vol[pos] != -1) { - entry->channel = pos; - entry->mask = IT_ENTRY_EFFECT; - entry->effect = IT_SET_CHANNEL_VOLUME; - entry->effectvalue = (vol[pos] + 2) >> 2; - entry++; - } - } - - row = 0; - pos = 2; - rowlen = data[0] | (data[1] << 8); - - while ((row < nrows) && (pos < len)) { - if (pos >= rowlen) { - IT_SET_END_ROW(entry); - entry++; - row++; - rowlen += data[pos] | (data[pos+1] << 8); - pos += 2; - continue; - } - - flags = data[pos++]; - entry->channel = data[pos++]; - entry->mask = 0; - - if (flags & 0xF0) { - if (flags & 0x80) { - entry->mask |= IT_ENTRY_NOTE; - if (version == PSMV_OLD) { - if ((data[pos] < 0x80)) entry->note = (data[pos]>>4)*12+(data[pos]&0x0f)+12; - else entry->mask &= ~IT_ENTRY_NOTE; - } else /*if (version == PSMV_NEW)*/ { - if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35; - else entry->mask &= ~IT_ENTRY_NOTE; - } - pos++; - } - - if (flags & 0x40) { - entry->mask |= IT_ENTRY_INSTRUMENT; - entry->instrument = data[pos++] + 1; - } - - if (flags & 0x20) { - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = (data[pos++] + 1) >> 1; - } - - if (flags & 0x10) { - entry->mask |= IT_ENTRY_EFFECT; - length = data[pos+1]; - switch (data[pos]) { - case 1: - entry->effect = IT_VOLUME_SLIDE; - if (version == PSMV_OLD) entry->effectvalue = ((length&0x1e)<<3) | 0xF; - else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length<<4) | 0xF; - break; - - case 2: - entry->effect = IT_VOLUME_SLIDE; - if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0; - else /*if (version == PSMV_NEW)*/ entry->effectvalue = (length << 4) & 0xF0; - break; - - case 3: - entry->effect = IT_VOLUME_SLIDE; - if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0; - else /*if (version == PSMV_NEW)*/ entry->effectvalue = length | 0xF0; - break; - - case 4: - entry->effect = IT_VOLUME_SLIDE; - if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF; - else /*if (version == PSMV_NEW)*/ entry->effectvalue = length & 0xF; - break; - - case 12: - entry->effect = IT_PORTAMENTO_UP; - if (version == PSMV_OLD) { - if (length < 4) entry->effectvalue = length | 0xF0; - else entry->effectvalue = length >> 2; - } else /*if (version == PSMV_NEW)*/ { - entry->effectvalue = length; - } - break; - - case 14: - entry->effect = IT_PORTAMENTO_DOWN; - if (version == PSMV_OLD) { - if (length < 4) entry->effectvalue = length | 0xF0; - else entry->effectvalue = length >> 2; - } else /*if (version == PSMV_NEW)*/ { - entry->effectvalue = length; - } - break; - - case 15: - entry->effect = IT_TONE_PORTAMENTO; - if (version == PSMV_OLD) entry->effectvalue = length >> 2; - else /*if (version == PSMV_NEW)*/ entry->effectvalue = length; - break; - - case 0x15: - entry->effect = IT_VIBRATO; - entry->effectvalue = length; - break; - - case 0x18: - entry->effect = IT_VOLSLIDE_VIBRATO; - entry->effectvalue = length; - break; - - case 0x29: - entry->effect = IT_SET_SAMPLE_OFFSET; - entry->effectvalue = data[pos+2]; - pos += 2; - break; - - case 0x2A: - entry->effect = IT_RETRIGGER_NOTE; - entry->effectvalue = length; - break; - - case 0x33: -#if 0 - entry->effect = IT_POSITION_JUMP; - entry->effectvalue = data[pos+2]; -#else - entry->mask &= ~IT_ENTRY_EFFECT; -#endif - pos++; - break; - - case 0x34: - entry->effect = IT_BREAK_TO_ROW; - entry->effectvalue = length; - break; - - case 0x3D: - entry->effect = IT_SET_SPEED; - entry->effectvalue = length; - break; - - case 0x3E: - if (length >= 0x20) { - entry->effect = IT_SET_SONG_TEMPO; - entry->effectvalue = length; - } else { - entry->mask &= ~IT_ENTRY_EFFECT; - } - break; - - case 0x47: - entry->effect = IT_ARPEGGIO; - entry->effectvalue = length; - break; - - default: - return -1; - } - pos += 2; - } - if (entry->mask) entry++; - } - } - - while (row < nrows) { - IT_SET_END_ROW(entry); - entry++; - row++; - } - - pattern->n_entries = (int)(entry - pattern->entry); - if (!pattern->n_entries) return -1; - - return 0; -} - - -static void free_chunks(PSMCHUNK * chunk, int count) { - int n; - - for (n = 0; n < count; n++) { - if (chunk[n].data) - free(chunk[n].data); - } - - free(chunk); -} - -static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata); - -static int pattcmp( const unsigned char *, const unsigned char *, size_t ); - -static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong) -{ - DUMB_IT_SIGDATA *sigdata; - - PSMCHUNK *chunk; - int n_chunks = 0; - - PSMCHUNK *songchunk; - int n_song_chunks = 0; - - PSMEVENT *event = NULL; - int n_events = 0; - - unsigned char * ptr; - - int n, length, o; - - int found; - - int n_patterns = 0; - - int first_pattern_line = -1; - int first_pattern; - - int speed, bpm; - unsigned char pan[64]; - int vol[32]; - - if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) goto error; - - length = dumbfile_igetl(f); - - if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) goto error; - - chunk = calloc(768, sizeof(*chunk)); - - while (length >= 8) { - chunk[n_chunks].id = dumbfile_mgetl(f); - n = dumbfile_igetl(f); - length -= 8; - if (n < 0 || n > length) - goto error_fc; - chunk[n_chunks].len = n; - if (n) { - ptr = malloc(n); - if (!ptr) goto error_fc; - if (dumbfile_getnc((char *)ptr, n, f) < n) - { - free(ptr); - goto error_fc; - } - chunk[n_chunks].data = ptr; - } - n_chunks++; - length -= n; - } - - if (!n_chunks) goto error_fc; - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) goto error_fc; - - sigdata->n_patterns = 0; - sigdata->n_samples = 0; - sigdata->name[0] = 0; - - found = 0; - - for (n = 0; n < n_chunks; n++) { - PSMCHUNK * c = &chunk[n]; - switch(c->id) { - case DUMB_ID('S','D','F','T'): - /* song data format? */ - if ((found & 1) || (c->len != 8) || memcmp(c->data, "MAINSONG", 8)) goto error_sd; - found |= 1; - break; - - case DUMB_ID('S','O','N','G'): - if (/*(found & 2) ||*/ (c->len < 11) /*|| memcmp(c->data, "MAINSONG", 8)*/) goto error_sd; - found |= 2; - break; - - case DUMB_ID('D','S','M','P'): - sigdata->n_samples++; - break; - - case DUMB_ID('T','I','T','L'): - length = min((int)sizeof(sigdata->name) - 1, c->len); - memcpy(sigdata->name, c->data, length); - sigdata->name[length] = 0; - } - } - - if (found != 3 || !sigdata->n_samples) goto error_sd; - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - sigdata->n_orders = 0; - - for (n = 0; n < n_chunks; n++) { - PSMCHUNK * c = &chunk[n]; - if (c->id == DUMB_ID('S','O','N','G')) { - if (subsong == 0) break; - subsong--; - } - } - - if (n == n_chunks) return NULL; - subsong = n; - - /*for (n = 0; n < n_chunks; n++) { - PSMCHUNK * c = &chunk[n]; - if (c->id == DUMB_ID('S','O','N','G')) {*/ - { - PSMCHUNK * c = &chunk[subsong]; - { - ptr = c->data; - if (ptr[10] > 32) goto error_usd; - sigdata->n_pchannels = ptr[10]; - length = c->len - 11; - ptr += 11; - songchunk = 0; - if (length >= 8) { - songchunk = malloc(128 * sizeof(*songchunk)); - if (!songchunk) goto error_usd; - while (length >= 8) { - songchunk[n_song_chunks].id = DUMB_ID(ptr[0], ptr[1], ptr[2], ptr[3]); - n = ptr[4] | (ptr[5] << 8) | (ptr[6] << 16) | (ptr[7] << 24); - length -= 8; - if (n > length) goto error_sc; - songchunk[n_song_chunks].len = n; - songchunk[n_song_chunks].data = ptr + 8; - n_song_chunks++; - length -= n; - ptr += 8 + n; - } - } - /*break;*/ - } - } - - if (!n_song_chunks) goto error_sc; - - found = 0; - - for (n = 0; n < n_song_chunks; n++) { - PSMCHUNK * c = &songchunk[n]; - - if (c->id == DUMB_ID('D','A','T','E')) { - /* date of the library build / format spec */ - if (c->len == 6) { - length = c->len; - ptr = c->data; - while (length > 0) { - if (*ptr >= '0' && *ptr <= '9') { - found = (found * 10) + (*ptr - '0'); - } else { - found = 0; - break; - } - ptr++; - length--; - } - } - break; - } - } - - /* - if (found != 940506 && - found != 940509 && - found != 940510 && - found != 940530 && - found != 940629 && - found != PSMV_OLD && - found != 941011 && - found != PSMV_NEW && - found != 940906 && - found != 940903 && - found != 940914 && - found != 941213 && - found != 800211) // WTF? - goto error_sc; - */ - - *ver = found; - - if (found == 800211 || - found == PSMV_NEW || - found == 940903 || - found == 940906 || - found == 940914 || - found == 941213) found = PSMV_NEW; - else found = PSMV_OLD; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - - for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { - int sep = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[n ] = 32 - sep; - sigdata->channel_pan[n+1] = 32 + sep; - sigdata->channel_pan[n+2] = 32 + sep; - sigdata->channel_pan[n+3] = 32 - sep; - } - - for (n = 0; n < n_song_chunks; n++) { - PSMCHUNK * c = &songchunk[n]; - - switch (c->id) { - case DUMB_ID('O','P','L','H'): - if (c->len < 2) goto error_sc; - ptr = c->data; - o = ptr[0] | (ptr[1] << 8); - if (!o) goto error_sc; - event = malloc(o * sizeof(*event)); - if (!event) goto error_sc; - length = c->len - 2; - ptr += 2; - while ((length > 0) && (n_events < o)) { - event[n_events].type = *ptr; - switch (*ptr) { - case PSM_EVENT_END: - ptr++; - length--; - break; - - case PSM_EVENT_PLAY_PATTERN: - if (found == PSMV_OLD) { - if (length < 5) goto error_ev; - memcpy(event[n_events].data, ptr + 1, 4); - ptr += 5; - length -= 5; - } else /*if (found == PSMV_NEW)*/ { - if (length < 9) goto error_ev; - memcpy(event[n_events].data, ptr + 1, 8); - ptr += 9; - length -= 9; - } - break; - - case PSM_EVENT_SET_SPEED: - case PSM_EVENT_SET_BPM: - if (length < 2) goto error_ev; - event[n_events].data[0] = ptr[1]; - ptr += 2; - length -= 2; - break; - - case PSM_EVENT_JUMP_TO_LINE: - case PSM_EVENT_CHANGE_VOL: - if (length < 3) goto error_ev; - memcpy(event[n_events].data, ptr + 1, 2); - ptr += 3; - length -= 3; - break; - - case PSM_EVENT_SAMPLE_MAP_TABLE: - if (length < 7) goto error_ev; - memcpy(event[n_events].data, ptr + 1, 6); - ptr += 7; - length -= 7; - break; - - case PSM_EVENT_CHANGE_PAN: - if (length < 4) goto error_ev; - memcpy(event[n_events].data, ptr + 1, 3); - ptr += 4; - length -= 4; - break; - - default: - goto error_ev; - } - n_events++; - } - break; - - case DUMB_ID('P','P','A','N'): - length = c->len; - if (length & 1) goto error_ev; - ptr = c->data; - o = 0; - while (length > 0) { - switch (ptr[0]) { - case 0: - sigdata->channel_pan[o] = ((((int)(signed char)ptr[1]) * 32) / 127) + 32; - break; - case 2: - sigdata->channel_pan[o] = IT_SURROUND; - break; - case 4: - sigdata->channel_pan[o] = 32; - break; - } - ptr += 2; - length -= 2; - if (++o >= DUMB_IT_N_CHANNELS) break; - } - break; - - /* - case DUMB_ID('P','A','T','T'): - case DUMB_ID('D','S','A','M'): - */ - } - } - - sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; - - sigdata->global_volume = 128; - sigdata->speed = 6; - sigdata->tempo = 125; - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - speed = 0; - bpm = 0; - memset(pan, 255, sizeof(pan)); - memset(vol, 255, sizeof(vol)); - - sigdata->n_patterns = n_events; - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) goto error_ev; - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - - for (n = 0; n < n_events; n++) { - PSMEVENT * e = &event[n]; - switch (e->type) { - case PSM_EVENT_END: - n = n_events; - break; - - case PSM_EVENT_PLAY_PATTERN: - for (o = 0; o < n_chunks; o++) { - PSMCHUNK * c = &chunk[o]; - if (c->id == DUMB_ID('P','B','O','D')) { - ptr = c->data; - length = c->len; - if (found == PSMV_OLD) { - if (length < 8) goto error_ev; - if (!pattcmp(ptr + 4, e->data, 4)) { - if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev; - if (first_pattern_line < 0) { - first_pattern_line = n; - first_pattern = o; - } - e->data[0] = n_patterns; - e->data[1] = n_patterns >> 8; - n_patterns++; - break; - } - } else /*if (found == PSMV_NEW)*/ { - if (length < 12) goto error_ev; - if (!pattcmp(ptr + 4, e->data, 8)) { - if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev; - if (first_pattern_line < 0) { - first_pattern_line = n; - first_pattern = o; - } - e->data[0] = n_patterns; - e->data[1] = n_patterns >> 8; - n_patterns++; - break; - } - } - } - } - if (o == n_chunks) goto error_ev; - - speed = 0; - bpm = 0; - memset(pan, 255, sizeof(pan)); - memset(vol, 255, sizeof(vol)); - - e->type = PSM_EVENT_END; - break; - - case PSM_EVENT_JUMP_TO_LINE: - o = e->data[0] | (e->data[1] << 8); - if (o >= n_events) goto error_ev; - if (o == 0) { - /* whew! easy case! */ - sigdata->restart_position = 0; - n = n_events; - } else if (o == n) { - /* freeze */ - n = n_events; - } else if (o > n) { - /* jump ahead, setting played event numbers to zero will prevent endless looping */ - n = o - 1; - } else if (o >= first_pattern_line) { - /* another semi-easy case */ - sigdata->restart_position = event[o].data[0] | (event[o].data[1] << 8); - n = n_events; - } else { - /* crud, try to simulate rerunning all of the commands from the indicated - * line up to the first pattern, then dupe the first pattern again. - */ - /* - PSMCHUNK * c = &chunk[first_pattern]; - - for (; o < first_pattern_line; o++) { - PSMEVENT * ev = &event[o]; - switch (ev->type) { - case PSM_EVENT_SET_SPEED: - speed = ev->data[0]; - break; - case PSM_EVENT_SET_BPM: - bpm = ev->data[0]; - break; - case PSM_EVENT_CHANGE_PAN: - if (ev->data[0] > 31) goto error_ev; - pan[ev->data[0] * 2] = ev->data[1]; - pan[ev->data[0] * 2 + 1] = ev->data[2]; - break; - case PSM_EVENT_CHANGE_VOL: - if (ev->data[0] > 31) goto error_ev; - vol[ev->data[0]] = ev->data[1]; - break; - } - } - - if (it_psm_process_pattern(&sigdata->pattern[n_patterns], c->data, c->len, speed, bpm, pan, vol, found)) goto error_ev; - n_patterns++; - sigdata->restart_position = 1; - n = n_events; - - Eh, what the hell? PSM has no panning commands anyway. - */ - sigdata->restart_position = 0; - n = n_events; - } - e->type = PSM_EVENT_END; - break; - - case PSM_EVENT_SET_SPEED: - speed = e->data[0]; - break; - - case PSM_EVENT_SET_BPM: - bpm = e->data[0]; - break; - - case PSM_EVENT_CHANGE_PAN: - o = e->data[0]; - if (o > 31) goto error_ev; - pan[o * 2] = e->data[1]; - pan[o * 2 + 1] = e->data[2]; - break; - - case PSM_EVENT_CHANGE_VOL: - o = e->data[0]; - if (o > 31) goto error_ev; - vol[o] = e->data[1]; - break; - - case PSM_EVENT_SAMPLE_MAP_TABLE: - if (e->data[0] != 0 || e->data[1] != 0xFF || - e->data[2] != 0 || e->data[3] != 0 || - e->data[4] != 1 || e->data[5] != 0) - goto error_ev; - break; - } - } - - if (n_patterns > 256) goto error_ev; - - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) goto error_ev; - for (n = 0; n < sigdata->n_samples; n++) { - sigdata->sample[n].data = NULL; - sigdata->sample[n].flags = 0; - } - - o = 0; - for (n = 0; n < n_chunks; n++) { - PSMCHUNK * c = &chunk[n]; - if (c->id == DUMB_ID('D','S','M','P')) { - if (it_psm_process_sample(&sigdata->sample[o], c->data, c->len, o, found)) goto error_ev; - o++; - } - } - - sigdata->n_orders = n_patterns; - sigdata->n_patterns = n_patterns; - - sigdata->order = malloc(n_patterns); - - for (n = 0; n < n_patterns; n++) { - sigdata->order[n] = n; - } - - free(event); - free(songchunk); - free_chunks(chunk, n_chunks); - - _dumb_it_fix_invalid_orders(sigdata); - - dumb_it_optimize_orders(sigdata); - - return sigdata; - -error_ev: - free(event); -error_sc: - if (songchunk) free(songchunk); -error_usd: - _dumb_it_unload_sigdata(sigdata); - goto error_fc; -error_sd: - free(sigdata); -error_fc: - free_chunks(chunk, n_chunks); -error: - return NULL; -} - -static int CDECL it_order_compare(const void *e1, const void *e2) { - if (*((const char *)e1) < *((const char *)e2)) - return -1; - - if (*((const char *)e1) > *((const char *)e2)) - return 1; - - return 0; -} - -/* -static int it_optimize_compare(const void *e1, const void *e2) { - if (((const IT_ENTRY *)e1)->channel < ((const IT_ENTRY *)e2)->channel) - return -1; - - if (((const IT_ENTRY *)e1)->channel > ((const IT_ENTRY *)e2)->channel) - return 1; - - return 0; -} -*/ - -static int CDECL it_entry_compare(const IT_ENTRY * e1, const IT_ENTRY * e2) { - if (IT_IS_END_ROW(e1) && IT_IS_END_ROW(e2)) return 1; - if (e1->channel != e2->channel) return 0; - if (e1->mask != e2->mask) return 0; - if ((e1->mask & IT_ENTRY_NOTE) && (e1->note != e2->note)) return 0; - if ((e1->mask & IT_ENTRY_INSTRUMENT) && (e1->instrument != e2->instrument)) return 0; - if ((e1->mask & IT_ENTRY_VOLPAN) && (e1->volpan != e2->volpan)) return 0; - if ((e1->mask & IT_ENTRY_EFFECT) && ((e1->effect != e2->effect) || (e1->effectvalue != e2->effectvalue))) return 0; - return 1; -} - -/* -static void dumb_it_optimize_pattern(IT_PATTERN * pattern) { - IT_ENTRY * entry, * end; - IT_ENTRY * rowstart, * rowend; - IT_ENTRY * current; - - if (!pattern->n_entries || !pattern->entry) return; - - current = entry = pattern->entry; - end = entry + pattern->n_entries; - - while (entry < end) { - rowstart = entry; - while (!IT_IS_END_ROW(entry)) entry++; - rowend = entry; - if (rowend > rowstart + 1) - qsort(rowstart, rowend - rowstart, sizeof(IT_ENTRY), &it_optimize_compare); - entry = rowstart; - while (entry < rowend) { - if (!(entry->mask)) {} - else if (it_entry_compare(entry, current)) {} - else if (!(current->mask) || - ((entry->channel == current->channel) && - ((entry->mask | current->mask) == (entry->mask ^ current->mask)))) { - current->mask |= entry->mask; - if (entry->mask & IT_ENTRY_NOTE) current->note = entry->note; - if (entry->mask & IT_ENTRY_INSTRUMENT) current->instrument = entry->instrument; - if (entry->mask & IT_ENTRY_VOLPAN) current->volpan = entry->volpan; - if (entry->mask & IT_ENTRY_EFFECT) { - current->effect = entry->effect; - current->effectvalue = entry->effectvalue; - } - } else { - if (++current < entry) *current = *entry; - } - entry++; - } - if (++current < entry) *current = *entry; - entry++; - } - - current++; - - if (current < end) { - IT_ENTRY * opt; - pattern->n_entries = current - pattern->entry; - opt = realloc(pattern->entry, pattern->n_entries * sizeof(*pattern->entry)); - if (opt) pattern->entry = opt; - } -} -*/ - -static int it_pattern_compare(const IT_PATTERN * p1, const IT_PATTERN * p2) { - IT_ENTRY * e1, * end; - IT_ENTRY * e2; - - if (p1 == p2) return 1; - if (p1->n_entries != p2->n_entries) return 0; - - e1 = p1->entry; end = e1 + p1->n_entries; - e2 = p2->entry; - - while (e1 < end) { - if (!it_entry_compare(e1, e2)) return 0; - e1++; e2++; - } - - return 1; -} - -static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata) { - int n, o, p; - - /*int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;*/ - - unsigned char * order_list; - int n_patterns; - - IT_PATTERN * pattern; - - if (!sigdata->n_orders || !sigdata->n_patterns) return; - - n_patterns = 0; - order_list = malloc(sigdata->n_orders); - - if (!order_list) return; - - for (n = 0; n < sigdata->n_orders; n++) { - if (sigdata->order[n] < sigdata->n_patterns) { - for (o = 0; o < n_patterns; o++) { - if (sigdata->order[n] == order_list[o]) break; - } - if (o == n_patterns) { - order_list[n_patterns++] = sigdata->order[n]; - } - } - } - - if (!n_patterns) { - free(order_list); - return; - } - - /*for (n = 0; n < n_patterns; n++) { - dumb_it_optimize_pattern(&sigdata->pattern[order_list[n]]); - }*/ - - for (n = 0; n < n_patterns; n++) { - for (o = n + 1; o < n_patterns; o++) { - if ((order_list[n] != order_list[o]) && - it_pattern_compare(&sigdata->pattern[order_list[n]], &sigdata->pattern[order_list[o]])) { - for (p = 0; p < sigdata->n_orders; p++) { - if (sigdata->order[p] == order_list[o]) { - sigdata->order[p] = order_list[n]; - } - } - for (p = o + 1; p < n_patterns; p++) { - if (order_list[p] == order_list[o]) { - order_list[p] = order_list[n]; - } - } - order_list[o] = order_list[n]; - } - } - } - - qsort(order_list, n_patterns, sizeof(*order_list), &it_order_compare); - - for (n = 0, o = 0; n < n_patterns; n++) { - if (order_list[n] != order_list[o]) { - if (++o < n) order_list[o] = order_list[n]; - } - } - - n_patterns = o + 1; - - pattern = malloc(n_patterns * sizeof(*pattern)); - if (!pattern) { - free(order_list); - return; - } - - for (n = 0; n < n_patterns; n++) { - pattern[n] = sigdata->pattern[order_list[n]]; - } - - for (n = 0; n < sigdata->n_patterns; n++) { - for (o = 0; o < n_patterns; o++) { - if (order_list[o] == n) break; - } - if (o == n_patterns) { - if (sigdata->pattern[n].entry) - free(sigdata->pattern[n].entry); - } - } - - free(sigdata->pattern); - sigdata->pattern = pattern; - sigdata->n_patterns = n_patterns; - - for (n = 0; n < sigdata->n_orders; n++) { - for (o = 0; o < n_patterns; o++) { - if (sigdata->order[n] == order_list[o]) { - sigdata->order[n] = o; - break; - } - } - } - - free(order_list); -} - -int DUMBEXPORT dumb_get_psm_subsong_count(DUMBFILE *f) { - int length, subsongs; - int32 l; - - if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) return 0; - - length = dumbfile_igetl(f); - - if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) return 0; - - subsongs = 0; - - while (length >= 8 && !dumbfile_error(f)) { - if (dumbfile_mgetl(f) == DUMB_ID('S','O','N','G')) subsongs++; - l = dumbfile_igetl(f); - dumbfile_skip(f, l); - length -= l + 8; - } - - if (dumbfile_error(f)) return 0; - - return subsongs; -} - - - -/* Eww */ -int pattcmp( const unsigned char * a, const unsigned char * b, size_t l ) -{ - size_t i, j; - int na = 0, nb = 0, k; - char * p; - - k = memcmp( a, b, l ); - if ( !k ) return k; - - /* damnit */ - - for ( i = 0; i < l; ++i ) - { - if ( a [i] >= '0' && a [i] <= '9' ) break; - } - - if ( i < l ) - { - na = strtoul( (const char *)a + i, &p, 10 ); - if ( p == (const char *)a + i ) return 1; - } - - for ( j = 0; j < l; ++j ) - { - if ( b [j] >= '0' && b [j] <= '9' ) break; - } - - if ( j < l ) - { - nb = strtoul( (const char *)b + j, &p, 10 ); - if ( p == (const char *)b + j ) return -1; - } - - if ( i < j ) return -1; - else if ( j > i ) return 1; - - k = memcmp( a, b, j ); - if ( k ) return k; - - return na - nb; -} - - - -DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong) -{ - sigdata_t *sigdata; - int ver; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_psm_load_sigdata(f, &ver, subsong); - - if (!sigdata) - return NULL; - - { - int n_tags = 2; - char version[16]; - const char *tag[3][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "PSM"; - if ( ver ) - { - tag[2][0] = "FORMATVERSION"; -#if NEED_ITOA - snprintf( version, 15, "%u", ver ); - version[15] = 0; -#else - itoa(ver, version, 10); -#endif - tag[2][1] = (const char *) &version; - ++n_tags; - } - return make_duh(-1, n_tags, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readptm.c b/libraries/dumb/src/it/readptm.c deleted file mode 100644 index 3052a4daa..000000000 --- a/libraries/dumb/src/it/readptm.c +++ /dev/null @@ -1,554 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readptm.c - Code to read a Poly Tracker v2.03 / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. Based on reads3m.c \_ / > / - * by entheh. | \ / / - * | ' / - * \__/ - */ - -// IT_STEREO... :o -#include -#include - -#include "dumb.h" -#include "internal/it.h" - - - -static int it_ptm_read_sample_header(IT_SAMPLE *sample, int32 *offset, DUMBFILE *f) -{ - int flags; - - flags = dumbfile_getc(f); - - dumbfile_getnc((char *)sample->filename, 12, f); - sample->filename[12] = 0; - - sample->default_volume = dumbfile_getc(f); - - sample->C5_speed = dumbfile_igetw(f) << 1; - - dumbfile_skip(f, 2); /* segment */ - - *offset = dumbfile_igetl(f); - - sample->length = dumbfile_igetl(f); - sample->loop_start = dumbfile_igetl(f); - sample->loop_end = dumbfile_igetl(f); - - /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */ - dumbfile_skip(f, 4+4+4+1+1); - - dumbfile_getnc((char *)sample->name, 28, f); - sample->name[28] = 0; - - /* - if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S')) - return -1; - */ - - /* BLAH! Shit likes to have broken or missing sample IDs */ - dumbfile_skip(f, 4); - - if ((flags & 3) == 0) { - /* Looks like no sample */ - sample->flags &= ~IT_SAMPLE_EXISTS; - return dumbfile_error(f); - } - - sample->global_volume = 64; - - sample->flags = IT_SAMPLE_EXISTS; - if (flags & 4) sample->flags |= IT_SAMPLE_LOOP; - if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; - - if (flags & 16) { - sample->flags |= IT_SAMPLE_16BIT; - - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - - if (sample->loop_end) sample->loop_end--; - - sample->default_pan = 0; // 0 = don't use, or 160 = centre? - - if (sample->length <= 0) - sample->flags &= ~IT_SAMPLE_EXISTS; - else if (sample->flags & IT_SAMPLE_LOOP) { - if ((unsigned int)sample->loop_end > (unsigned int)sample->length) - sample->flags &= ~IT_SAMPLE_LOOP; - else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) - sample->flags &= ~IT_SAMPLE_LOOP; - else - sample->length = sample->loop_end; - } - - - //Do we need to set all these? - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = IT_VIBRATO_SINE; - sample->finetune = 0; - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - - -static int it_ptm_read_byte(DUMBFILE *f) -{ - int meh = dumbfile_getc(f); - if (meh < 0) return 0; - return meh; -} - -static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f) -{ - int32 n; - int s; - - sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); - if (!sample->data) - return -1; - - s = 0; - - if (sample->flags & IT_SAMPLE_16BIT) { - unsigned char a, b; - for (n = 0; n < sample->length; n++) { - a = s += (signed char) it_ptm_read_byte(f); - b = s += (signed char) it_ptm_read_byte(f); - ((short *)sample->data)[n] = a | (b << 8); - } - } else { - for (n = 0; n < sample->length; n++) { - s += (signed char) it_ptm_read_byte(f); - ((signed char *)sample->data)[n] = s; - } - } - - if (dumbfile_error(f) && !last) - return -1; - - return 0; -} - - - -static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length) -{ - int buflen = 0; - int bufpos = 0; - int effect, effectvalue; - - IT_ENTRY *entry; - - unsigned char channel; - - if (!length) - return -1; - - pattern->n_rows = 0; - pattern->n_entries = 0; - - /* Read in the pattern data, little by little, and work out how many - * entries we need room for. Sorry, but this is just so funny... - */ - for (;;) { - unsigned char b = buffer[buflen++] = dumbfile_getc(f); - -#if 1 - static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5}; - channel = b & 31; - b >>= 5; - pattern->n_entries++; - if (b) { - if (buflen + used[b] >= 65536) return -1; - dumbfile_getnc((char *)buffer + buflen, used[b], f); - buflen += used[b]; - } else { - /* End of row */ - if (++pattern->n_rows == 64) break; - if (buflen >= 65536) return -1; - } -#else - if (b == 0) { - /* End of row */ - pattern->n_entries++; - if (++pattern->n_rows == 64) break; - if (buflen >= 65536) return -1; - } else { - static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5}; - channel = b & 31; - b >>= 5; - if (b) { - pattern->n_entries++; - if (buflen + used[b] >= 65536) return -1; - dumbfile_getnc(buffer + buflen, used[b], f); - buflen += used[b]; - } - } -#endif - - /* We have ensured that buflen < 65536 at this point, so it is safe - * to iterate and read at least one more byte without checking. - * However, now would be a good time to check for errors reading from - * the file. - */ - - if (dumbfile_error(f)) - return -1; - - /* Great. We ran out of data, but there should be data for more rows. - * Fill the rest with null data... - */ - if (buflen >= length && pattern->n_rows < 64) - { - while (pattern->n_rows < 64) - { - if (buflen >= 65536) return -1; - buffer[buflen++] = 0; - pattern->n_entries++; - pattern->n_rows++; - } - break; - } - } - - pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); - - if (!pattern->entry) - return -1; - - entry = pattern->entry; - - while (bufpos < buflen) { - unsigned char b = buffer[bufpos++]; - - if (b == 0) - { - /* End of row */ - IT_SET_END_ROW(entry); - entry++; - continue; - } - - channel = b & 31; - - if (b & 224) { - entry->mask = 0; - entry->channel = channel; - - if (b & 32) { - unsigned char n = buffer[bufpos++]; - if (n == 254 || (n >= 1 && n <= 120)) { - if (n == 254) - entry->note = IT_NOTE_CUT; - else - entry->note = n - 1; - entry->mask |= IT_ENTRY_NOTE; - } - - entry->instrument = buffer[bufpos++]; - if (entry->instrument) - entry->mask |= IT_ENTRY_INSTRUMENT; - } - - if (b & 64) { - effect = buffer[bufpos++]; - effectvalue = buffer[bufpos++]; - _dumb_it_ptm_convert_effect(effect, effectvalue, entry); - } - - if (b & 128) { - entry->volpan = buffer[bufpos++]; - if (entry->volpan <= 64) - entry->mask |= IT_ENTRY_VOLPAN; - } - - entry++; - } - } - - ASSERT(entry == pattern->entry + pattern->n_entries); - - return 0; -} - - - -/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */ -/* Currently we assume the sample data are stored after the sample headers in - * module files. This assumption may be unjustified; let me know if you have - * trouble. - */ - -#define PTM_COMPONENT_INSTRUMENT 1 -#define PTM_COMPONENT_PATTERN 2 -#define PTM_COMPONENT_SAMPLE 3 - -typedef struct PTM_COMPONENT -{ - unsigned char type; - unsigned char n; - int32 offset; -} -PTM_COMPONENT; - - - -static int CDECL ptm_component_compare(const void *e1, const void *e2) -{ - return ((const PTM_COMPONENT *)e1)->offset - - ((const PTM_COMPONENT *)e2)->offset; -} - - - -static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) -{ - DUMB_IT_SIGDATA *sigdata; - - PTM_COMPONENT *component; - int n_components = 0; - - int n; - - unsigned char *buffer; - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) return NULL; - - /* Skip song name. */ - dumbfile_getnc((char *)sigdata->name, 28, f); - sigdata->name[28] = 0; - - if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) { - free(sigdata); - return NULL; - } - - dumbfile_skip(f, 1); - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_orders = dumbfile_igetw(f); - sigdata->n_instruments = 0; - sigdata->n_samples = dumbfile_igetw(f); - sigdata->n_patterns = dumbfile_igetw(f); - - if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->n_pchannels = dumbfile_igetw(f); - - if (dumbfile_igetw(f) != 0) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - dumbfile_skip(f, 2); - - if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - dumbfile_skip(f, 16); - - sigdata->order = malloc(sigdata->n_orders); - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (sigdata->n_samples) { - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_samples; n++) - sigdata->sample[n].data = NULL; - } - - if (sigdata->n_patterns) { - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - } - - /** WARNING: which ones? */ - sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM; - - sigdata->global_volume = 128; - sigdata->speed = 6; - sigdata->tempo = 125; - sigdata->mixing_volume = 48; - - /* Panning positions for 32 channels */ - { - int i; - for (i = 0; i < 32; i++) { - int c = dumbfile_getc(f); - if (c <= 15) { - sigdata->channel_volume[i] = 64; - sigdata->channel_pan[i] = c; - } else { - /** WARNING: this could be improved if we support channel muting... */ - sigdata->channel_volume[i] = 0; - sigdata->channel_pan[i] = 7; - } - } - } - - /* Orders, byte each, length = sigdata->n_orders (should be even) */ - dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f); - sigdata->restart_position = 0; - - component = malloc(768*sizeof(*component)); - if (!component) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (dumbfile_seek(f, 352, DFS_SEEK_SET)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (n = 0; n < sigdata->n_patterns; n++) { - component[n_components].type = PTM_COMPONENT_PATTERN; - component[n_components].n = n; - component[n_components].offset = dumbfile_igetw(f) << 4; - n_components++; - } - - if (dumbfile_seek(f, 608, DFS_SEEK_SET)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (n = 0; n < sigdata->n_samples; n++) { - if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue; - component[n_components].type = PTM_COMPONENT_SAMPLE; - component[n_components].n = n; - n_components++; - } - - qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare); - - { - int i; - for (i = 0; i < 32; i++) { - sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3; - sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7; - if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64; - } - } - - sigdata->pan_separation = 128; - - if (dumbfile_error(f)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - buffer = malloc(65536); - if (!buffer) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (n = 0; n < n_components; n++) { - if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - switch (component[n].type) { - - case PTM_COMPONENT_PATTERN: - if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - break; - - case PTM_COMPONENT_SAMPLE: - if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - } - - free(buffer); - free(component); - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - -DUH *DUMBEXPORT dumb_read_ptm_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_ptm_load_sigdata(f); - - if (!sigdata) - return NULL; - - { - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "PTM"; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readriff.c b/libraries/dumb/src/it/readriff.c deleted file mode 100644 index 4843f0527..000000000 --- a/libraries/dumb/src/it/readriff.c +++ /dev/null @@ -1,57 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readriff.c - Code to read a RIFF module file / / \ \ - * from memory. | < / \_ - * | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" -#include "internal/it.h" -#include "internal/riff.h" - - -DUH *dumb_read_riff_amff( DUMBFILE * f, struct riff * stream ); -DUH *dumb_read_riff_am( DUMBFILE * f, struct riff * stream ); -DUH *dumb_read_riff_dsmf( DUMBFILE * f, struct riff * stream ); - -/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a - * pointer to the DUH struct. When you have finished with it, you must pass - * the pointer to unload_duh() so that the memory can be freed. - */ -DUH *DUMBEXPORT dumb_read_riff_quick( DUMBFILE * f ) -{ - DUH * duh; - struct riff * stream; - long size; - - size = dumbfile_get_size(f); - - stream = riff_parse( f, 0, size, 1 ); - if ( ! stream ) stream = riff_parse( f, 0, size, 0 ); - - if ( ! stream ) return 0; - - if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) ) - duh = dumb_read_riff_am( f, stream ); - else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) ) - duh = dumb_read_riff_amff( f, stream ); - else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) ) - duh = dumb_read_riff_dsmf( f, stream ); - else duh = 0; - - riff_free( stream ); - - return duh; -} diff --git a/libraries/dumb/src/it/reads3m.c b/libraries/dumb/src/it/reads3m.c deleted file mode 100644 index 43b6128a4..000000000 --- a/libraries/dumb/src/it/reads3m.c +++ /dev/null @@ -1,766 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * reads3m.c - Code to read a ScreamTracker 3 / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * By entheh. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -// IT_STEREO... :o -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -static int it_s3m_read_sample_header(IT_SAMPLE *sample, int32 *offset, unsigned char *pack, int cwtv, DUMBFILE *f) -{ - unsigned char type; - int flags; - - type = dumbfile_getc(f); - - dumbfile_getnc((char *)sample->filename, 12, f); - sample->filename[12] = 0; - - if (type > 1) { - /** WARNING: no adlib support */ - dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12); - dumbfile_getnc((char *)sample->name, 28, f); - sample->name[28] = 0; - dumbfile_skip(f, 4); - sample->flags &= ~IT_SAMPLE_EXISTS; - return dumbfile_error(f); - } - - *offset = dumbfile_getc(f) << 20; - *offset += dumbfile_igetw(f) << 4; - - sample->length = dumbfile_igetl(f); - sample->loop_start = dumbfile_igetl(f); - sample->loop_end = dumbfile_igetl(f); - - sample->default_volume = dumbfile_getc(f); - - dumbfile_skip(f, 1); - - flags = dumbfile_getc(f); - - if (flags < 0 || (flags != 0 && flags != 4)) - /* Sample is packed apparently (or error reading from file). We don't - * know how to read packed samples. - */ - return -1; - - *pack = flags; - - flags = dumbfile_getc(f); - - sample->C5_speed = dumbfile_igetl(f) << 1; - - /* Skip four unused bytes and three internal variables. */ - dumbfile_skip(f, 4+2+2+4); - - dumbfile_getnc((char *)sample->name, 28, f); - sample->name[28] = 0; - - if (type == 0 || sample->length <= 0) { - /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */ - sample->flags &= ~IT_SAMPLE_EXISTS; - return dumbfile_error(f); - } - - if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S')) - return -1; - - sample->global_volume = 64; - - sample->flags = IT_SAMPLE_EXISTS; - if (flags & 1) sample->flags |= IT_SAMPLE_LOOP; - - /* The ST3 TECH.DOC is unclear on this, but IMAGO Orpheus is not. Piece of crap. */ - - if (flags & 2) { - sample->flags |= IT_SAMPLE_STEREO; - - if ((cwtv & 0xF000) == 0x2000) { - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - } - - if (flags & 4) { - sample->flags |= IT_SAMPLE_16BIT; - - if ((cwtv & 0xF000) == 0x2000) { - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - } - - sample->default_pan = 0; // 0 = don't use, or 160 = centre? - - if (sample->flags & IT_SAMPLE_LOOP) { - if ((unsigned int)sample->loop_end > (unsigned int)sample->length) - /*sample->flags &= ~IT_SAMPLE_LOOP;*/ - sample->loop_end = sample->length; - else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) - sample->flags &= ~IT_SAMPLE_LOOP; - else - /* ScreamTracker seems not to save what comes after the loop end - * point, but rather to assume it is a duplicate of what comes at - * the loop start point. I am not completely sure of this though. - * It is easy to evade; simply truncate the sample. - */ - sample->length = sample->loop_end; - } - - - //Do we need to set all these? - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = IT_VIBRATO_SINE; - sample->finetune = 0; - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - - - -static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, unsigned char pack, DUMBFILE *f) -{ - int32 n; - - int32 datasize = sample->length; - if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1; - - sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); - if (!sample->data) - return -1; - - if (pack == 4) { - if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) - return -1; - } - else if (sample->flags & IT_SAMPLE_STEREO) { - if (sample->flags & IT_SAMPLE_16BIT) { - for (n = 0; n < datasize; n += 2) - ((short *)sample->data)[n] = dumbfile_igetw(f); - for (n = 1; n < datasize; n += 2) - ((short *)sample->data)[n] = dumbfile_igetw(f); - } else { - for (n = 0; n < datasize; n += 2) - ((signed char *)sample->data)[n] = dumbfile_getc(f); - for (n = 1; n < datasize; n += 2) - ((signed char *)sample->data)[n] = dumbfile_getc(f); - } - } else if (sample->flags & IT_SAMPLE_16BIT) - for (n = 0; n < sample->length; n++) - ((short *)sample->data)[n] = dumbfile_igetw(f); - else - for (n = 0; n < sample->length; n++) - ((signed char *)sample->data)[n] = dumbfile_getc(f); - - if (dumbfile_error(f)) - return -1; - - if (ffi != 1) { - /* Convert to signed. */ - if (sample->flags & IT_SAMPLE_16BIT) - for (n = 0; n < datasize; n++) - ((short *)sample->data)[n] ^= 0x8000; - else - for (n = 0; n < datasize; n++) - ((signed char *)sample->data)[n] ^= 0x80; - } - - return 0; -} - - - -static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer) -{ - int length; - int buflen = 0; - int bufpos = 0; - - IT_ENTRY *entry; - - unsigned char channel; - - /* Haha, this is hilarious! - * - * Well, after some experimentation, it seems that different S3M writers - * define the format in different ways. The S3M docs say that the first - * two bytes hold the "length of [the] packed pattern", and the packed - * pattern data follow. Judging by the contents of ARMANI.S3M, packaged - * with ScreamTracker itself, the measure of length _includes_ the two - * bytes used to store the length; in other words, we should read - * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug - * Tracker, excludes these two bytes, so (length) more bytes must be - * read. - * - * Call me crazy, but I just find it insanely funny that the format was - * misunderstood in this way :D - * - * Now we can't just risk reading two extra bytes, because then we - * overshoot, and DUMBFILEs don't support backward seeking (for a good - * reason). Luckily, there is a way. We can read the data little by - * little, and stop when we have 64 rows in memory. Provided we protect - * against buffer overflow, this method should work with all sensibly - * written S3M files. If you find one for which it does not work, please - * let me know at entheh@users.sf.net so I can look at it. - * - * "for a good reason" ? What's this nonsense? -kode54 - * - */ - - length = dumbfile_igetw(f); - - if (dumbfile_error(f) || !length) - return -1; - - pattern->n_rows = 0; - pattern->n_entries = 0; - - /* Read in the pattern data, little by little, and work out how many - * entries we need room for. Sorry, but this is just so funny... - */ - for (;;) { - unsigned char b = buffer[buflen++] = dumbfile_getc(f); - -#if 1 - static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5}; - channel = b & 31; - b >>= 5; - pattern->n_entries++; - if (b) { - if (buflen + used[b] >= 65536) return -1; - if (buflen + used[b] <= length) - dumbfile_getnc((char *)buffer + buflen, used[b], f); - else - memset(buffer + buflen, 0, used[b]); - buflen += used[b]; - } else { - /* End of row */ - if (++pattern->n_rows == 64) break; - if (buflen >= 65536) return -1; - } -#else - if (b == 0) { - /* End of row */ - pattern->n_entries++; - if (++pattern->n_rows == 64) break; - if (buflen >= 65536) return -1; - } else { - static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5}; - channel = b & 31; - b >>= 5; - if (b) { - pattern->n_entries++; - if (buflen + used[b] >= 65536) return -1; - dumbfile_getnc(buffer + buflen, used[b], f); - buflen += used[b]; - } - } -#endif - - /* We have ensured that buflen < 65536 at this point, so it is safe - * to iterate and read at least one more byte without checking. - * However, now would be a good time to check for errors reading from - * the file. - */ - - if (dumbfile_error(f)) - return -1; - - /* Great. We ran out of data, but there should be data for more rows. - * Fill the rest with null data... - */ - if (buflen >= length && pattern->n_rows < 64) - { - while (pattern->n_rows < 64) - { - if (buflen >= 65536) return -1; - buffer[buflen++] = 0; - pattern->n_entries++; - pattern->n_rows++; - } - break; - } - } - - pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); - - if (!pattern->entry) - return -1; - - entry = pattern->entry; - - while (bufpos < buflen) { - unsigned char b = buffer[bufpos++]; - -#if 1 - if (!(b & ~31)) -#else - if (b == 0) -#endif - { - /* End of row */ - IT_SET_END_ROW(entry); - entry++; - continue; - } - - channel = b & 31; - - if (b & 224) { - entry->mask = 0; - entry->channel = channel; - - if (b & 32) { - unsigned char n = buffer[bufpos++]; - if (n != 255) { - if (n == 254) - entry->note = IT_NOTE_CUT; - else - entry->note = (n >> 4) * 12 + (n & 15); - entry->mask |= IT_ENTRY_NOTE; - } - - entry->instrument = buffer[bufpos++]; - if (entry->instrument) - entry->mask |= IT_ENTRY_INSTRUMENT; - } - - if (b & 64) { - entry->volpan = buffer[bufpos++]; - if (entry->volpan != 255) - entry->mask |= IT_ENTRY_VOLPAN; - } - - if (b & 128) { - entry->effect = buffer[bufpos++]; - entry->effectvalue = buffer[bufpos++]; - // XXX woot - if (entry->effect && entry->effect < IT_MIDI_MACRO /*!= 255*/) { - entry->mask |= IT_ENTRY_EFFECT; - switch (entry->effect) { - case IT_BREAK_TO_ROW: - entry->effectvalue -= (entry->effectvalue >> 4) * 6; - break; - - case IT_SET_CHANNEL_VOLUME: - case IT_CHANNEL_VOLUME_SLIDE: - case IT_PANNING_SLIDE: - case IT_GLOBAL_VOLUME_SLIDE: - case IT_PANBRELLO: - case IT_MIDI_MACRO: - entry->mask &= ~IT_ENTRY_EFFECT; - break; - - case IT_S: - switch (entry->effectvalue >> 4) { - case IT_S_SET_PANBRELLO_WAVEFORM: - case IT_S_FINE_PATTERN_DELAY: - case IT_S7: - case IT_S_SET_SURROUND_SOUND: - case IT_S_SET_MIDI_MACRO: - entry->mask &= ~IT_ENTRY_EFFECT; - break; - } - break; - } - } - /** WARNING: ARGH! CONVERT TEH EFFECTS!@~ */ - } - - entry++; - } - } - - ASSERT(entry == pattern->entry + pattern->n_entries); - - return 0; -} - - - -/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */ -/* Currently we assume the sample data are stored after the sample headers in - * module files. This assumption may be unjustified; let me know if you have - * trouble. - */ - -#define S3M_COMPONENT_INSTRUMENT 1 -#define S3M_COMPONENT_PATTERN 2 -#define S3M_COMPONENT_SAMPLE 3 - -typedef struct S3M_COMPONENT -{ - unsigned char type; - unsigned char n; - int32 offset; - short sampfirst; /* component[sampfirst] = first sample data after this */ - short sampnext; /* sampnext is used to create linked lists of sample data */ -} -S3M_COMPONENT; - - - -static int CDECL s3m_component_compare(const void *e1, const void *e2) -{ - return ((const S3M_COMPONENT *)e1)->offset - - ((const S3M_COMPONENT *)e2)->offset; -} - - - -static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv) -{ - DUMB_IT_SIGDATA *sigdata; - - int flags, ffi; - int default_pan_present; - - int master_volume; - - unsigned char sample_pack[256]; - - S3M_COMPONENT *component; - int n_components = 0; - - int n; - - unsigned char *buffer; - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) return NULL; - - dumbfile_getnc((char *)sigdata->name, 28, f); - sigdata->name[28] = 0; - - n = dumbfile_getc(f); - - if (n != 0x1A && n != 0) { - free(sigdata); - return NULL; - } - - if (dumbfile_getc(f) != 16) { - free(sigdata); - return NULL; - } - - dumbfile_skip(f, 2); - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_orders = dumbfile_igetw(f); - sigdata->n_instruments = 0; - sigdata->n_samples = dumbfile_igetw(f); - sigdata->n_patterns = dumbfile_igetw(f); - - if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->order = malloc(sigdata->n_orders); - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (sigdata->n_samples) { - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_samples; n++) - sigdata->sample[n].data = NULL; - } - - if (sigdata->n_patterns) { - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - } - - flags = dumbfile_igetw(f); - - *cwtv = dumbfile_igetw(f); - - if (*cwtv == 0x1300) { - /** WARNING: volume slides on every frame */ - } - - ffi = dumbfile_igetw(f); - - /** WARNING: which ones? */ - sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; - - if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','M')) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->global_volume = dumbfile_getc(f); - if ( !sigdata->global_volume || sigdata->global_volume > 64 ) sigdata->global_volume = 64; - sigdata->speed = dumbfile_getc(f); - if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? - sigdata->tempo = dumbfile_getc(f); - master_volume = dumbfile_getc(f); // 7 bits; +128 for stereo - sigdata->mixing_volume = master_volume & 127; - - if (master_volume & 128) sigdata->flags |= IT_STEREO; - - /* Skip GUS Ultra Click Removal byte. */ - dumbfile_getc(f); - - default_pan_present = dumbfile_getc(f); - - dumbfile_skip(f, 8); - - /* Skip Special Custom Data Pointer. */ - /** WARNING: investigate this? */ - dumbfile_igetw(f); - - sigdata->n_pchannels = 0; - /* Channel settings for 32 channels, 255=unused, +128=disabled */ - { - int i; - int sep = (7 * dumb_it_default_panning_separation + 50) / 100; - for (i = 0; i < 32; i++) { - int c = dumbfile_getc(f); - if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */ - if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1; - sigdata->channel_volume[i] = 64; - sigdata->channel_pan[i] = c & 8 ? 7 + sep : 7 - sep; - /** WARNING: ah, but it should be 7 for mono... */ - } else { - /** WARNING: this could be improved if we support channel muting... */ - sigdata->channel_volume[i] = 0; - sigdata->channel_pan[i] = 7; - } - } - } - - /* Orders, byte each, length = sigdata->n_orders (should be even) */ - dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f); - sigdata->restart_position = 0; - - component = malloc(768*sizeof(*component)); - if (!component) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (n = 0; n < sigdata->n_samples; n++) { - component[n_components].type = S3M_COMPONENT_SAMPLE; - component[n_components].n = n; - component[n_components].offset = dumbfile_igetw(f) << 4; - component[n_components].sampfirst = -1; - n_components++; - } - - for (n = 0; n < sigdata->n_patterns; n++) { - int32 offset = dumbfile_igetw(f) << 4; - if (offset) { - component[n_components].type = S3M_COMPONENT_PATTERN; - component[n_components].n = n; - component[n_components].offset = offset; - component[n_components].sampfirst = -1; - n_components++; - } else { - /** WARNING: Empty 64-row pattern ... ? (this does happen!) */ - sigdata->pattern[n].n_rows = 64; - sigdata->pattern[n].n_entries = 0; - } - } - - qsort(component, n_components, sizeof(S3M_COMPONENT), &s3m_component_compare); - - /* I found a really dumb S3M file that claimed to contain default pan - * data but didn't contain any. Programs would load it by reading part of - * the first instrument header, assuming the data to be default pan - * positions, and then rereading the instrument module. We cannot do this - * without obfuscating the file input model, so we insert an extra check - * here that we won't overrun the start of the first component. - */ - if (default_pan_present == 252 && component[0].offset >= dumbfile_pos(f) + 32) { - /* Channel default pan positions */ - int i; - for (i = 0; i < 32; i++) { - int c = dumbfile_getc(f); - if (c & 32) - sigdata->channel_pan[i] = c & 15; - } - } - - { - int i; - for (i = 0; i < 32; i++) { - sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3; - sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7; - } - } - - sigdata->pan_separation = 128; - - if (dumbfile_error(f)) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - buffer = malloc(65536); - if (!buffer) { - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - for (n = 0; n < n_components; n++) { - int32 offset; - int m; - - offset = 0; - if (dumbfile_seek(f, component[n].offset, DFS_SEEK_SET)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - switch (component[n].type) { - - case S3M_COMPONENT_PATTERN: - if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - break; - - case S3M_COMPONENT_SAMPLE: - if (it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, &sample_pack[component[n].n], *cwtv, f)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) { - short *sample; - - for (m = n + 1; m < n_components; m++) - if (component[m].offset > offset) - break; - m--; - - sample = &component[m].sampfirst; - - while (*sample >= 0 && component[*sample].offset <= offset) - sample = &component[*sample].sampnext; - - component[n].sampnext = *sample; - *sample = n; - - component[n].offset = offset; - } - } - - m = component[n].sampfirst; - - while (m >= 0) { - // XXX - if (dumbfile_seek(f, component[m].offset, DFS_SEEK_SET)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, sample_pack[component[m].n], f)) { - free(buffer); - free(component); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - m = component[m].sampnext; - } - } - - free(buffer); - free(component); - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - -static char hexdigit(int in) -{ - if (in < 10) return in + '0'; - else return in + 'A' - 10; -} - -DUH *DUMBEXPORT dumb_read_s3m_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - int cwtv; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_s3m_load_sigdata(f, &cwtv); - - if (!sigdata) - return NULL; - - { - char version[8]; - const char *tag[3][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - tag[1][1] = "S3M"; - tag[2][0] = "TRACKERVERSION"; - version[0] = hexdigit((cwtv >> 8) & 15); - version[1] = '.'; - version[2] = hexdigit((cwtv >> 4) & 15); - version[3] = hexdigit(cwtv & 15); - version[4] = 0; - tag[2][1] = (const char *) &version; - return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/reads3m2.c b/libraries/dumb/src/it/reads3m2.c deleted file mode 100644 index e7d34de33..000000000 --- a/libraries/dumb/src/it/reads3m2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * reads3m2.c - Function to read a ScreamTracker 3 / / \ \ - * module from an open file and do an | < / \_ - * initial run-through. | \/ /\ / - * \_ / > / - * Split off from reads3m.c by entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_s3m(DUMBFILE *f) -{ - DUH *duh = dumb_read_s3m_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readstm.c b/libraries/dumb/src/it/readstm.c deleted file mode 100644 index a2ae69033..000000000 --- a/libraries/dumb/src/it/readstm.c +++ /dev/null @@ -1,397 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readstm.c - Code to read a ScreamTracker 2 / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * By Chris Moeller. \_ / > / - * | \ / / - * | ' / - * \__/ - */ - -// IT_STEREO... :o -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -#ifdef _MSC_VER - #define strnicmp _strnicmp -#else - #if defined(unix) || defined(__unix__) || defined(__unix) - #include - #endif - #define strnicmp strncasecmp -#endif - -static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned short *offset ) -{ - dumbfile_getnc( (char *) sample->filename, 12, f ); - sample->filename[12] = 0; - - memcpy( sample->name, sample->filename, 13 ); - - dumbfile_skip( f, 2 ); - - *offset = dumbfile_igetw( f ); - - sample->length = dumbfile_igetw( f ); - sample->loop_start = dumbfile_igetw( f ); - sample->loop_end = dumbfile_igetw( f ); - - sample->default_volume = dumbfile_getc( f ); - - dumbfile_skip( f, 1 ); - - sample->C5_speed = dumbfile_igetw( f ) << 3; - - dumbfile_skip( f, 6 ); - - if ( sample->length < 4 || !sample->default_volume ) { - /* Looks like no-existy. */ - sample->flags &= ~IT_SAMPLE_EXISTS; - sample->length = 0; - *offset = 0; - return dumbfile_error( f ); - } - - sample->flags = IT_SAMPLE_EXISTS; - sample->global_volume = 64; - sample->default_pan = 0; // 0 = don't use, or 160 = centre? - - if ( ( sample->loop_start < sample->length ) && - ( sample->loop_end > sample->loop_start ) && - ( sample->loop_end != 0xFFFF ) ) { - sample->flags |= IT_SAMPLE_LOOP; - if ( sample->loop_end > sample->length ) sample->loop_end = sample->length; - } - - //Do we need to set all these? - sample->vibrato_speed = 0; - sample->vibrato_depth = 0; - sample->vibrato_rate = 0; - sample->vibrato_waveform = IT_VIBRATO_SINE; - sample->finetune = 0; - sample->max_resampling_quality = -1; - - return dumbfile_error(f); -} - -static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE * f ) -{ - if ( ! sample->length ) return 0; - - sample->data = malloc( sample->length ); - if (!sample->data) - return -1; - - dumbfile_getnc( sample->data, sample->length, f ); - - return dumbfile_error( f ); -} - -static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer ) -{ - int pos; - int channel; - int row; - IT_ENTRY *entry; - - pattern->n_rows = 64; - - if ( dumbfile_getnc( (char *) buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 ) - return -1; - - pattern->n_entries = 64; - pos = 0; - for ( row = 0; row < 64; ++row ) { - for ( channel = 0; channel < 4; ++channel ) { - if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) - ++pattern->n_entries; - pos += 4; - } - } - - pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) ); - if ( !pattern->entry ) - return -1; - - entry = pattern->entry; - pos = 0; - for ( row = 0; row < 64; ++row ) { - for ( channel = 0; channel < 4; ++channel ) { - if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) { - unsigned note; - note = buffer[ pos + 0 ]; - entry->channel = channel; - entry->mask = 0; - entry->instrument = buffer[ pos + 1 ] >> 3; - entry->volpan = ( buffer[ pos + 1 ] & 0x07 ) + ( buffer[ pos + 2 ] >> 1 ); - entry->effect = buffer[ pos + 2 ] & 0x0F; - entry->effectvalue = buffer[ pos + 3 ]; - if ( entry->instrument && entry->instrument < 32 ) - entry->mask |= IT_ENTRY_INSTRUMENT; - if ( note < 251 ) { - entry->mask |= IT_ENTRY_NOTE; - entry->note = ( note >> 4 ) * 12 + ( note & 0x0F ); - } - if ( entry->volpan <= 64 ) - entry->mask |= IT_ENTRY_VOLPAN; - entry->mask |= IT_ENTRY_EFFECT; - switch ( entry->effect ) { - case IT_SET_SPEED: - /* taken care of in the renderer */ - break; - - case IT_BREAK_TO_ROW: - entry->effectvalue -= (entry->effectvalue >> 4) * 6; - break; - - case IT_JUMP_TO_ORDER: - case IT_VOLUME_SLIDE: - case IT_PORTAMENTO_DOWN: - case IT_PORTAMENTO_UP: - case IT_TONE_PORTAMENTO: - case IT_VIBRATO: - case IT_TREMOR: - case IT_ARPEGGIO: - case IT_VOLSLIDE_VIBRATO: - case IT_VOLSLIDE_TONEPORTA: - break; - - default: - entry->mask &= ~IT_ENTRY_EFFECT; - break; - } - if ( entry->mask ) ++entry; - } - pos += 4; - } - IT_SET_END_ROW(entry); - ++entry; - } - - pattern->n_entries = (int)(entry - pattern->entry); - - return 0; -} - - - -static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) -{ - DUMB_IT_SIGDATA *sigdata; - - char tracker_name[ 8 ]; - - unsigned short sample_offset[ 31 ]; - - int n; - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) return NULL; - - /* Skip song name. */ - dumbfile_getnc((char *)sigdata->name, 20, f); - sigdata->name[20] = 0; - - dumbfile_getnc(tracker_name, 8, f); - n = dumbfile_getc(f); - if ( n != 0x02 && n != 0x1A && n != 0x1B ) - { - free( sigdata ); - return NULL; - } - if ( dumbfile_getc(f) != 2 ) /* only support modules */ - { - free( sigdata ); - return NULL; - } - if ( strnicmp( tracker_name, "!Scream!", 8 ) && - strnicmp( tracker_name, "BMOD2STM", 8 ) && - strnicmp( tracker_name, "WUZAMOD!", 8 ) ) - { - free( sigdata ); - return NULL; - } - - *version = dumbfile_mgetw(f); - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_instruments = 0; - sigdata->n_samples = 31; - sigdata->n_pchannels = 4; - - sigdata->tempo = 125; - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - /** WARNING: which ones? */ - sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M | IT_WAS_AN_STM | IT_STEREO; - - n = dumbfile_getc(f); - if ( n < 32 ) n = 32; - sigdata->speed = n; - sigdata->n_patterns = dumbfile_getc(f); - sigdata->global_volume = dumbfile_getc(f) << 1; - if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128; - - dumbfile_skip(f, 13); - - if ( dumbfile_error(f) || sigdata->n_patterns < 1 || sigdata->n_patterns > 99 ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); - if (!sigdata->sample) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_samples; n++) - sigdata->sample[n].data = NULL; - - if (sigdata->n_patterns) { - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (n = 0; n < sigdata->n_patterns; n++) - sigdata->pattern[n].entry = NULL; - } - - memset( sigdata->channel_volume, 64, 4 ); - n = 32 * dumb_it_default_panning_separation / 100; - sigdata->channel_pan[ 0 ] = 32 + n; - sigdata->channel_pan[ 1 ] = 32 - n; - sigdata->channel_pan[ 2 ] = 32 + n; - sigdata->channel_pan[ 3 ] = 32 - n; - - for ( n = 0; n < sigdata->n_samples; ++n ) { - if ( it_stm_read_sample_header( &sigdata->sample[ n ], f, &sample_offset[ n ] ) ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - } - - sigdata->order = malloc( 128 ); - if ( !sigdata->order ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - - /* Orders, byte each, length = sigdata->n_orders (should be even) */ - dumbfile_getnc( (char *) sigdata->order, *version >= 0x200 ? 128 : 64, f ); - if (*version < 0x200) memset( sigdata->order + 64, 0xFF, 64 ); - sigdata->restart_position = 0; - - for ( n = 127; n >= 0; --n ) { - if ( sigdata->order[ n ] < sigdata->n_patterns ) break; - } - if ( n < 0 ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - sigdata->n_orders = n + 1; - - for ( n = 0; n < 128; ++n ) { - if ( sigdata->order[ n ] >= 99 ) sigdata->order[ n ] = 0xFF; - } - - if ( sigdata->n_patterns ) { - unsigned char * buffer = malloc( 64 * 4 * 4 ); - if ( ! buffer ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - for ( n = 0; n < sigdata->n_patterns; ++n ) { - if ( it_stm_read_pattern( &sigdata->pattern[ n ], f, buffer ) ) { - free( buffer ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - } - free( buffer ); - } - - for ( n = 0; n < sigdata->n_samples; ++n ) { - if ( sample_offset[ n ] ) - { - if ( dumbfile_seek( f, sample_offset[ n ] * 16, DFS_SEEK_SET ) || - it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) { - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - } - else - { - sigdata->sample[ n ].flags = 0; - sigdata->sample[ n ].length = 0; - } - } - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - -DUH *DUMBEXPORT dumb_read_stm_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - int ver; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_stm_load_sigdata(f , &ver); - - if (!sigdata) - return NULL; - - { - char version[16]; - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - version[0] = 'S'; - version[1] = 'T'; - version[2] = 'M'; - version[3] = ' '; - version[4] = 'v'; - version[5] = '0' + ((ver >> 8) & 15); - version[6] = '.'; - if ((ver & 255) > 99) - { - version[7] = '0' + ((ver & 255) / 100 ); - version[8] = '0' + (((ver & 255) / 10) % 10); - version[9] = '0' + ((ver & 255) % 10); - version[10] = 0; - } - else - { - version[7] = '0' + ((ver & 255) / 10); - version[8] = '0' + ((ver & 255) % 10); - version[9] = 0; - } - tag[1][1] = (const char *) &version; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readstm2.c b/libraries/dumb/src/it/readstm2.c deleted file mode 100644 index bd78eaf69..000000000 --- a/libraries/dumb/src/it/readstm2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readstm2.c - Function to read a ScreamTracker 2 / / \ \ - * module from an open file and do an | < / \_ - * initial run-through. | \/ /\ / - * \_ / > / - * By Chris Moeller. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_stm(DUMBFILE *f) -{ - DUH *duh = dumb_read_stm_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/readxm.c b/libraries/dumb/src/it/readxm.c deleted file mode 100644 index b26359f64..000000000 --- a/libraries/dumb/src/it/readxm.c +++ /dev/null @@ -1,1530 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readxm.c - Code to read a Fast Tracker II / / \ \ - * module from an open file. | < / \_ - * | \/ /\ / - * By Julien Cugniere. Some bits of code taken \_ / > / - * from reads3m.c. | \ / / - * | ' / - * \__/ - */ - -#include -#include -#include - -#include "dumb.h" -#include "internal/it.h" -#include "internal/dumbfile.h" - -#include -#include - -extern short *DUMBCALLBACK dumb_decode_vorbis(int outlen, const void *oggstream, int sizebytes); - -/** TODO: - - * XM_TREMOLO doesn't sound quite right... - * XM_SET_ENVELOPE_POSITION todo. - - * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check - that effect memory is correct when using XM_VOLSLIDE_VIBRATO. - - sample vibrato (instrument vibrato) is now handled correctly. - entheh - - * XM_E_SET_VIBRATO/TREMOLO_CONTROL: effectvalue&4 -> don't retrig wave when - a new instrument is played. In retrigger_note()?. Is it worth implementing? - - * Lossy fadeout approximation. 0..31 converted to 0 --> won't fade at all. - - * Replace DUMB's sawtooth by ramp_down/ramp_up. Update XM loader. - - * A lot of things need to be reset when the end of the song is reached. - - * It seems that IT and XM don't behave the same way when dealing with - mixed loops. When IT encounters multiple SBx (x>0) commands on the same - row, it decrements the loop count for all, but only execute the loop of - the last one (highest channel). FT2 only decrements the loop count of the - last one. Not that I know of any modules using so convoluted combinations! - - * Maybe we could remove patterns that don't appear in the order table ? Or - provide a function to "optimize" a DUMB_IT_SIGDATA ? - -*/ - - - -#define XM_LINEAR_FREQUENCY 1 /* otherwise, use amiga slides */ - -#define XM_ENTRY_PACKED 128 -#define XM_ENTRY_NOTE 1 -#define XM_ENTRY_INSTRUMENT 2 -#define XM_ENTRY_VOLUME 4 -#define XM_ENTRY_EFFECT 8 -#define XM_ENTRY_EFFECTVALUE 16 - -#define XM_NOTE_OFF 97 - -#define XM_ENVELOPE_ON 1 -#define XM_ENVELOPE_SUSTAIN 2 -#define XM_ENVELOPE_LOOP 4 - -#define XM_SAMPLE_NO_LOOP 0 -#define XM_SAMPLE_FORWARD_LOOP 1 -#define XM_SAMPLE_PINGPONG_LOOP 2 -#define XM_SAMPLE_16BIT 16 -#define XM_SAMPLE_STEREO 32 - -#define XM_VIBRATO_SINE 0 -#define XM_VIBRATO_SQUARE 1 -#define XM_VIBRATO_RAMP_DOWN 2 -#define XM_VIBRATO_RAMP_UP 3 - - - -/* Probably useless :) */ -const char xm_convert_vibrato[] = { - IT_VIBRATO_SINE, - IT_VIBRATO_XM_SQUARE, - IT_VIBRATO_RAMP_DOWN, - IT_VIBRATO_RAMP_UP, - IT_VIBRATO_RANDOM -}; - - - -#define XM_MAX_SAMPLES_PER_INSTRUMENT 16 - - - -/* Extra data that doesn't fit inside IT_INSTRUMENT */ -typedef struct XM_INSTRUMENT_EXTRA -{ - int n_samples; - int vibrato_type; - int vibrato_sweep; /* 0-0xFF */ - int vibrato_depth; /* 0-0x0F */ - int vibrato_speed; /* 0-0x3F */ - int sample_header_size; -} -XM_INSTRUMENT_EXTRA; - - - -/* Trims off trailing white space, usually added by the tracker on file creation - */ -static void trim_whitespace(char *ptr, size_t size) -{ - char *p = ptr + size - 1; - while (p >= ptr && *p <= 0x20) *p-- = '\0'; -} - -/* Frees the original block if it can't resize it or if size is 0, and acts - * as malloc if ptr is NULL. - */ -static void *safe_realloc(void *ptr, size_t size) -{ - if (ptr == NULL) - return malloc(size); - - if (size == 0) { - free(ptr); - return NULL; - } else { - void *new_block = realloc(ptr, size); - if (!new_block) - free(ptr); - return new_block; - } -} - - - -/* The interpretation of the XM volume column is left to the player. Here, we - * just filter bad values. - */ -// This function is so tiny now, should we inline it? -static void it_xm_convert_volume(int volume, IT_ENTRY *entry) -{ - entry->mask |= IT_ENTRY_VOLPAN; - entry->volpan = volume; - - switch (volume >> 4) { - case 0xA: /* set vibrato speed */ - case 0xB: /* vibrato */ - case 0xF: /* tone porta */ - case 0x6: /* vol slide up */ - case 0x7: /* vol slide down */ - case 0x8: /* fine vol slide up */ - case 0x9: /* fine vol slide down */ - case 0xC: /* set panning */ - case 0xD: /* pan slide left */ - case 0xE: /* pan slide right */ - case 0x1: /* set volume */ - case 0x2: /* set volume */ - case 0x3: /* set volume */ - case 0x4: /* set volume */ - break; - - case 0x5: - if (volume == 0x50) - break; /* set volume */ - /* else fall through */ - - default: - entry->mask &= ~IT_ENTRY_VOLPAN; - break; - } -} - - - -static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version) -{ - int size; - int pos; - int channel; - int row; - int effect, effectvalue; - IT_ENTRY *entry; - - /* pattern header size */ - if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) { - TRACE("XM error: unexpected pattern header size\n"); - return -1; - } - - /* pattern data packing type */ - if (dumbfile_getc(f) != 0) { - TRACE("XM error: unexpected pattern packing type\n"); - return -1; - } - - if ( version == 0x0102 ) - pattern->n_rows = dumbfile_getc(f) + 1; - else - pattern->n_rows = dumbfile_igetw(f); /* 1..256 */ - size = dumbfile_igetw(f); - pattern->n_entries = 0; - - if (dumbfile_error(f)) - return -1; - - if (size == 0) - return 0; - - if (size > 1280 * n_channels) { - TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels); - return -1; - } - - if (dumbfile_getnc((char *)buffer, size, f) < size) - return -1; - - /* compute number of entries */ - pattern->n_entries = 0; - pos = channel = row = 0; - while (pos < size) { - if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31)) - pattern->n_entries++; - - channel++; - if (channel >= n_channels) { - channel = 0; - row++; - pattern->n_entries++; - } - - if (buffer[pos] & XM_ENTRY_PACKED) { - static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 }; - pos += 1 + offset[buffer[pos] & 31]; - } else { - pos += 5; - } - } - - if (row > pattern->n_rows) { - TRACE("XM error: wrong number of rows in pattern data\n"); - return -1; - } - - /* Whoops, looks like some modules may be short, a few channels, maybe even rows... */ - - while (row < pattern->n_rows) - { - pattern->n_entries++; - row++; - } - - pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); - if (!pattern->entry) - return -1; - - /* read the entries */ - entry = pattern->entry; - pos = channel = row = 0; - while (pos < size) { - unsigned char mask; - - if (buffer[pos] & XM_ENTRY_PACKED) - mask = buffer[pos++] & 31; - else - mask = 31; - - if (mask) { - ASSERT(entry < pattern->entry + pattern->n_entries); - - entry->channel = channel; - entry->mask = 0; - - if (mask & XM_ENTRY_NOTE) { - int note = buffer[pos++]; /* 1-96 <=> C0-B7 */ - entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1); - entry->mask |= IT_ENTRY_NOTE; - } - - if (mask & XM_ENTRY_INSTRUMENT) { - entry->instrument = buffer[pos++]; /* 1-128 */ - entry->mask |= IT_ENTRY_INSTRUMENT; - } - - if (mask & XM_ENTRY_VOLUME) - it_xm_convert_volume(buffer[pos++], entry); - - effect = effectvalue = 0; - if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++]; - if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++]; - _dumb_it_xm_convert_effect(effect, effectvalue, entry, 0); - - entry++; - } - - channel++; - if (channel >= n_channels) { - channel = 0; - row++; - IT_SET_END_ROW(entry); - entry++; - } - } - - while (row < pattern->n_rows) - { - row++; - IT_SET_END_ROW(entry); - entry++; - } - - return 0; -} - - - -static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset) -{ - int i, pos, val; - - if (envelope->n_nodes > 12) { - /* XXX - TRACE("XM error: wrong number of envelope nodes (%d)\n", envelope->n_nodes); - envelope->n_nodes = 0; - return -1; */ - envelope->n_nodes = 12; - } - - if (envelope->sus_loop_start >= 12) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; - if (envelope->loop_end >= 12) envelope->loop_end = 0; - if (envelope->loop_start >= envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; - - pos = 0; - for (i = 0; i < envelope->n_nodes; i++) { - envelope->node_t[i] = data[pos++]; - val = data[pos++]; - if (val > 64) { - TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, val); - /* FT2 seems to simply clip the value */ - val = 64; - } - envelope->node_y[i] = (signed char)(val + y_offset); - } - - return 0; -} - - - -typedef struct LIMITED_XM LIMITED_XM; - -struct LIMITED_XM -{ - unsigned char *buffered; - long ptr, limit, allocated; - DUMBFILE *remaining; -}; - -static int DUMBCALLBACK limit_xm_resize(void *f, long n) -{ - DUMBFILE *df = f; - LIMITED_XM *lx = df->file; - if (lx->buffered || n) { - if (n > lx->allocated) { - unsigned char *buffered = realloc( lx->buffered, n ); - if ( !buffered ) return -1; - lx->buffered = buffered; - memset( buffered + lx->allocated, 0, n - lx->allocated ); - lx->allocated = n; - } - if ( dumbfile_getnc( (char *)lx->buffered, n, lx->remaining ) < n ) return -1; - } else if (!n) { - if ( lx->buffered ) free( lx->buffered ); - lx->buffered = NULL; - lx->allocated = 0; - } - lx->limit = n; - lx->ptr = 0; - return 0; -} - -static int DUMBCALLBACK limit_xm_skip_end(void *f, int32 n) -{ - DUMBFILE *df = f; - LIMITED_XM *lx = df->file; - return dumbfile_skip( lx->remaining, n ); -} - -static int DUMBCALLBACK limit_xm_skip(void *f, long n) -{ - LIMITED_XM *lx = f; - lx->ptr += n; - return 0; -} - - - -static int DUMBCALLBACK limit_xm_getc(void *f) -{ - LIMITED_XM *lx = f; - if (lx->ptr >= lx->allocated) { - return 0; - } - return lx->buffered[lx->ptr++]; -} - - - -static int32 DUMBCALLBACK limit_xm_getnc(char *ptr, int32 n, void *f) -{ - LIMITED_XM *lx = f; - int left; - left = lx->allocated - lx->ptr; - if (n > left) { - if (left > 0) { - memcpy( ptr, lx->buffered + lx->ptr, left ); - memset( ptr + left, 0, n - left ); - } else { - memset( ptr, 0, n ); - } - } else { - memcpy( ptr, lx->buffered + lx->ptr, n ); - } - lx->ptr += n; - return n; -} - - - -static void DUMBCALLBACK limit_xm_close(void *f) -{ - LIMITED_XM *lx = f; - if (lx->buffered) free(lx->buffered); - /* Do NOT close lx->remaining */ - free(f); -} - - - -/* These two can be stubs since this implementation doesn't use seeking */ -static int DUMBCALLBACK limit_xm_seek(void *f, long n) -{ - (void)f; - (void)n; - return 1; -} - - - -static long DUMBCALLBACK limit_xm_get_size(void *f) -{ - (void)f; - return 0; -} - - - -DUMBFILE_SYSTEM limit_xm_dfs = { - NULL, - &limit_xm_skip, - &limit_xm_getc, - &limit_xm_getnc, - &limit_xm_close, - &limit_xm_seek, - &limit_xm_get_size -}; - -static DUMBFILE *dumbfile_limit_xm(DUMBFILE *f) -{ - LIMITED_XM * lx = malloc(sizeof(*lx)); - lx->remaining = f; - lx->buffered = NULL; - lx->ptr = 0; - lx->limit = 0; - lx->allocated = 0; - return dumbfile_open_ex( lx, &limit_xm_dfs ); -} - -static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f) -{ - uint32 size, bytes_read; - unsigned short vol_points[24]; - unsigned short pan_points[24]; - int i, type; - const unsigned long max_size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2; - unsigned long skip_end = 0; - - /* Header size. Tends to be more than the actual size of the structure. - * So unread bytes must be skipped before reading the first sample - * header. - */ - - if ( limit_xm_resize( f, 4 ) < 0 ) return -1; - - size = dumbfile_igetl(f); - - if ( size == 0 ) size = max_size; - else if ( size > max_size ) - { - skip_end = size - max_size; - size = max_size; - } - - if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1; - - dumbfile_getnc((char *)instrument->name, 22, f); - instrument->name[22] = 0; - trim_whitespace((char *)instrument->name, 22); - instrument->filename[0] = 0; - dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */ - extra->n_samples = dumbfile_igetw(f); - - if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT) - return -1; - - bytes_read = 4 + 22 + 1 + 2; - - if (extra->n_samples) { - /* sample header size */ - /*i = dumbfile_igetl(f); - if (!i || i > 0x28) i = 0x28;*/ - dumbfile_skip(f, 4); - i = 0x28; - extra->sample_header_size = i; - - /* sample map */ - for (i = 0; i < 96; i++) { - instrument->map_sample[i] = dumbfile_getc(f) + 1; - instrument->map_note[i] = i; - } - - if (dumbfile_error(f)) - return 1; - - /* volume/panning envelopes */ - for (i = 0; i < 24; i++) - vol_points[i] = dumbfile_igetw(f); - for (i = 0; i < 24; i++) - pan_points[i] = dumbfile_igetw(f); - - instrument->volume_envelope.n_nodes = dumbfile_getc(f); - instrument->pan_envelope.n_nodes = dumbfile_getc(f); - - if (dumbfile_error(f)) - return -1; - - instrument->volume_envelope.sus_loop_start = dumbfile_getc(f); - instrument->volume_envelope.loop_start = dumbfile_getc(f); - instrument->volume_envelope.loop_end = dumbfile_getc(f); - - instrument->pan_envelope.sus_loop_start = dumbfile_getc(f); - instrument->pan_envelope.loop_start = dumbfile_getc(f); - instrument->pan_envelope.loop_end = dumbfile_getc(f); - - /* The envelope handler for XM files won't use sus_loop_end. */ - - type = dumbfile_getc(f); - instrument->volume_envelope.flags = 0; - if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes) - instrument->volume_envelope.flags |= IT_ENVELOPE_ON; - if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON; -#if 1 - if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP; -#else // This is now handled in itrender.c - /* let's avoid fading out when reaching the last envelope node */ - if (!(type & XM_ENVELOPE_LOOP)) { - instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1; - instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1; - } - instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON; -#endif - - type = dumbfile_getc(f); - instrument->pan_envelope.flags = 0; - if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes) - instrument->pan_envelope.flags |= IT_ENVELOPE_ON; - if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here? - if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP; - - if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) { - TRACE("XM error: volume envelope\n"); - if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1; - } - - if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) { - TRACE("XM error: pan envelope\n"); - if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1; - } - - instrument->pitch_envelope.flags = 0; - - extra->vibrato_type = dumbfile_getc(f); - extra->vibrato_sweep = dumbfile_getc(f); - extra->vibrato_depth = dumbfile_getc(f); - extra->vibrato_speed = dumbfile_getc(f); - - if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX - return -1; - - /** WARNING: lossy approximation */ - instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF; - - dumbfile_skip(f, 2); /* reserved */ - - bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2; - } else - for (i = 0; i < 96; i++) - instrument->map_sample[i] = 0; - - if (size > bytes_read && dumbfile_skip(f, size - bytes_read)) - return -1; - - if (skip_end && limit_xm_skip_end(f, skip_end)) - return -1; - - instrument->new_note_action = NNA_NOTE_CUT; - instrument->dup_check_type = DCT_OFF; - instrument->dup_check_action = DCA_NOTE_CUT; - instrument->pp_separation = 0; - instrument->pp_centre = 60; /* C-5 */ - instrument->global_volume = 128; - instrument->default_pan = 32; - instrument->random_volume = 0; - instrument->random_pan = 0; - instrument->filter_cutoff = 0; - instrument->filter_resonance = 0; - - return 0; -} - - - -/* I (entheh) have two XM files saved by a very naughty program. After a - * 16-bit sample, it saved a rogue byte. The length of the sample was indeed - * an odd number, incremented to include the rogue byte. - * - * In this function we are converting sample lengths and loop points so they - * are measured in samples. This means we forget about the extra bytes, and - * they don't get skipped. So we fail trying to read the next instrument. - * - * To get around this, this function returns the number of rogue bytes that - * won't be accounted for by reading sample->length samples. It returns a - * negative number on failure. - */ -static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) -{ - int type; - int relative_note_number; /* relative to C4 */ - int finetune; - int roguebytes; - int roguebytesmask; - int reserved; - - sample->length = dumbfile_igetl(f); - sample->loop_start = dumbfile_igetl(f); - sample->loop_end = sample->loop_start + dumbfile_igetl(f); - sample->global_volume = 64; - sample->default_volume = dumbfile_getc(f); - finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */ - type = dumbfile_getc(f); - sample->default_pan = dumbfile_getc(f); /* 0-255 */ - relative_note_number = (signed char)dumbfile_getc(f); - - reserved = dumbfile_getc(f); - - dumbfile_getnc((char *)sample->name, 22, f); - sample->name[22] = 0; - trim_whitespace((char *)sample->name, 22); - - sample->filename[0] = 0; - - if (dumbfile_error(f)) - return -1; - - sample->C5_speed = (int32)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number) /**pow(DUMB_PITCH_BASE, )*/ ); - sample->finetune = finetune*2; - - sample->flags = IT_SAMPLE_EXISTS; - - if (reserved == 0xAD && - (!(type & (XM_SAMPLE_16BIT | XM_SAMPLE_STEREO)))) - { - /* F U Olivier Lapicque */ - roguebytes = 4; - roguebytesmask = 4 << 2; - } - else - { - roguebytes = (int)sample->length; - roguebytesmask = 3; - } - - if (type & XM_SAMPLE_16BIT) - sample->flags |= IT_SAMPLE_16BIT; - else - roguebytesmask >>= 1; - - if (type & XM_SAMPLE_STEREO) - sample->flags |= IT_SAMPLE_STEREO; - else - roguebytesmask >>= 1; - - roguebytes &= roguebytesmask; - - if ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end) { - if (type & XM_SAMPLE_FORWARD_LOOP) sample->flags |= IT_SAMPLE_LOOP; - if (type & XM_SAMPLE_PINGPONG_LOOP) sample->flags |= IT_SAMPLE_LOOP | IT_SAMPLE_PINGPONG_LOOP; - } - - if (sample->length <= 0) - sample->flags &= ~IT_SAMPLE_EXISTS; - - return roguebytes; -} - -static void it_xm_fixup_sample_points(IT_SAMPLE *sample) -{ - if (sample->flags & IT_SAMPLE_16BIT) { - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - if (sample->flags & IT_SAMPLE_STEREO) { - sample->length >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - - if ((unsigned int)sample->loop_end > (unsigned int)sample->length) - sample->flags &= ~IT_SAMPLE_LOOP; - else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) - sample->flags &= ~IT_SAMPLE_LOOP; -} - -static int iswapw(int val) -{ - union - { - short sv; - char cv[2]; - } endiancheck; - /* A smart compiler will optimize this check away. */ - endiancheck.sv = 1; - if (endiancheck.cv[0] == 1) - { - return val; - } - endiancheck.sv = val; - return (unsigned char)endiancheck.cv[0] | (endiancheck.cv[1] << 8); -} - -static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, DUMBFILE *f) -{ - int old; - int32 i; -// long truncated_size; - int n_channels; - int32 datasizebytes; - - if (!(sample->flags & IT_SAMPLE_EXISTS)) - return dumbfile_skip(f, roguebytes); - -#if 0 - /* let's get rid of the sample data coming after the end of the loop */ - if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length && roguebytes != 4) { - truncated_size = sample->length - sample->loop_end; - sample->length = sample->loop_end; - } else { - truncated_size = 0; - } -#endif - n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1; - datasizebytes = sample->length; - - sample->data = malloc(datasizebytes); - if (!sample->data) - return -1; - - if (roguebytes == 4) - { - if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) - return -1; - return 0; - } - - dumbfile_getnc(sample->data, datasizebytes, f); - - if (dumbfile_error(f)) - return -1; - - /* FMOD extension: Samples compressed with Ogg Vorbis */ - if (!memcmp((char *)sample->data + 4, "OggS", 4) && - !memcmp((char *)sample->data + 33, "vorbis", 7)) - { - int32 outlen = ((unsigned char *)(sample->data))[0] | - (((unsigned char *)(sample->data))[1] << 8) | - (((unsigned char *)(sample->data))[2] << 16) | - (((unsigned char *)(sample->data))[3] << 24); - short *output; - - if (!(sample->flags & IT_SAMPLE_16BIT)) - { - /* Because it'll be 16-bit when we're done with it. */ - outlen <<= 1; - } - - if (sample->flags & IT_SAMPLE_STEREO) - { - /* OggMod knows nothing of stereo samples and compresses them as mono, - * screwing up the second channel. (Because for whatever reason, - * ModPlug delta encodes them independantly, even though it presents - * the sample as a double-length mono sound to other players.) - */ - sample->flags &= ~IT_SAMPLE_STEREO; - outlen >>= 1; - sample->loop_start >>= 1; - sample->loop_end >>= 1; - } - output = dumb_decode_vorbis(outlen, (char *)sample->data + 4, datasizebytes - 4); - if (output != NULL) - { - free(sample->data); - sample->data = output; - sample->length = outlen; - if (!(sample->flags & IT_SAMPLE_16BIT)) - { - sample->flags |= IT_SAMPLE_16BIT; - sample->loop_start <<= 1; - sample->loop_end <<= 1; - } - - it_xm_fixup_sample_points(sample); - return 0; - } - /* Decode failed, so assume it's normal sample data that just so - * happened to look like a Vorbis stream. (Not likely to happen - * by coincidence!) */ - } - - it_xm_fixup_sample_points(sample); - - /* sample data is stored as signed delta values */ - old = 0; - if (sample->flags & IT_SAMPLE_STEREO) - { - /* Stereo samples are a ModPlug extension, so to keep compatibility with - * players that don't know about it (and FastTracker 2 itself), the two - * channels are not stored interleaved but rather, one after the other. */ - int old_r = 0; - void *ibuffer = malloc(sample->length << ((sample->flags & IT_SAMPLE_16BIT) ? 2 : 1)); - if (ibuffer == NULL) - { - /* No memory => ignore stereo bits at the end */ - sample->flags &= ~IT_SAMPLE_STEREO; - } - else if (sample->flags & IT_SAMPLE_16BIT) - { - for (i = 0; i < sample->length; i++) - { - ((short *)ibuffer)[i*2] = old += iswapw(((short *)sample->data)[i]); - ((short *)ibuffer)[i*2+1] = old_r += iswapw(((short *)sample->data)[i + sample->length]); - } - } - else - { - for (i = 0; i < sample->length; i++) - { - ((char *)ibuffer)[i*2] = old += ((char *)sample->data)[i]; - ((char *)ibuffer)[i*2+1] = old_r += ((char *)sample->data)[i + sample->length]; - } - } - if (ibuffer != NULL) - { - free(sample->data); - sample->data = ibuffer; - } - } - if (!(sample->flags & IT_SAMPLE_STEREO)) - { - if (sample->flags & IT_SAMPLE_16BIT) - { - for (i = 0; i < sample->length; i++) - ((short *)sample->data)[i] = old += iswapw(((short *)sample->data)[i]); - } - else - { - for (i = 0; i < sample->length; i++) - ((char *)sample->data)[i] = old += ((char *)sample->data)[i]; - } - } - return 0; -} - - - -/* "Real programmers don't document. If it was hard to write, - * it should be hard to understand." - * - * (Never trust the documentation provided with a tracker. - * Real files are the only truth...) - */ -static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) -{ - DUMB_IT_SIGDATA *sigdata; - char id_text[18]; - - int header_size; - int flags; - int n_channels; - int total_samples; - int i, j; - - /* check ID text */ - if (dumbfile_getnc(id_text, 17, f) < 17) - return NULL; - id_text[17] = 0; - if (strcmp(id_text, "Extended Module: ") != 0) { - TRACE("XM error: Not an Extended Module\n"); - return NULL; - } - - sigdata = malloc(sizeof(*sigdata)); - if (!sigdata) - return NULL; - - /* song name */ - if (dumbfile_getnc((char *)sigdata->name, 20, f) < 20) { - free(sigdata); - return NULL; - } - sigdata->name[20] = 0; - trim_whitespace((char *)sigdata->name, 20); - - if (dumbfile_getc(f) != 0x1A) { - TRACE("XM error: 0x1A not found\n"); - free(sigdata); - return NULL; - } - - /* tracker name */ - if (dumbfile_skip(f, 20)) { - free(sigdata); - return NULL; - } - - /* version number */ - * version = dumbfile_igetw(f); - if (* version > 0x0104 || * version < 0x0102) { - TRACE("XM error: wrong format version\n"); - free(sigdata); - return NULL; - } - - /* - ------------------ - --- Header --- - ------------------ - */ - - /* header size */ - header_size = dumbfile_igetl(f); - if (header_size < (4 + 2*8 + 1) || header_size > 0x114) { - TRACE("XM error: unexpected header size\n"); - free(sigdata); - return NULL; - } - - sigdata->song_message = NULL; - sigdata->order = NULL; - sigdata->instrument = NULL; - sigdata->sample = NULL; - sigdata->pattern = NULL; - sigdata->midi = NULL; - sigdata->checkpoint = NULL; - - sigdata->n_samples = 0; - sigdata->n_orders = dumbfile_igetw(f); - sigdata->restart_position = dumbfile_igetw(f); - n_channels = dumbfile_igetw(f); /* max 32 but we'll be lenient */ - sigdata->n_pchannels = n_channels; - sigdata->n_patterns = dumbfile_igetw(f); - sigdata->n_instruments = dumbfile_igetw(f); /* max 128 */ /* XXX upped to 256 */ - flags = dumbfile_igetw(f); - sigdata->speed = dumbfile_igetw(f); - if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? - sigdata->tempo = dumbfile_igetw(f); - - // FT2 always clips restart position against the song length - if (sigdata->restart_position > sigdata->n_orders) - sigdata->restart_position = sigdata->n_orders; - // And FT2 starts playback on order 0, regardless of length, - // and only checks if the next order is greater than or equal - // to this, not the current pattern. Work around this with - // DUMB's playback core by overriding a zero length with one. - if (sigdata->n_orders == 0) - sigdata->n_orders = 1; - - /* sanity checks */ - // XXX - i = header_size - 4 - 2 * 8; /* Maximum number of orders expected */ - if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > i || sigdata->n_patterns > 256 || sigdata->n_instruments > 256 || n_channels > DUMB_IT_N_CHANNELS) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - //if (sigdata->restart_position >= sigdata->n_orders) - //sigdata->restart_position = 0; - - /* order table */ - sigdata->order = malloc(sigdata->n_orders*sizeof(*sigdata->order)); - if (!sigdata->order) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - dumbfile_getnc((char *)sigdata->order, sigdata->n_orders, f); - dumbfile_skip(f, i - sigdata->n_orders); - - if (dumbfile_error(f)) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if ( * version > 0x103 ) { - /* - -------------------- - --- Patterns --- - -------------------- - */ - - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) - sigdata->pattern[i].entry = NULL; - - { - unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */ - if (!buffer) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) { - if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) { - free(buffer); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - free(buffer); - } - - /* - ----------------------------------- - --- Instruments and Samples --- - ----------------------------------- - */ - - sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); - if (!sigdata->instrument) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - /* With XM, samples are not global, they're part of an instrument. In a - * file, each instrument is stored with its samples. Because of this, I - * don't know how to find how many samples are present in the file. Thus - * I have to do n_instruments reallocation on sigdata->sample. - * Looking at FT2, it doesn't seem possible to have more than 16 samples - * per instrument (even though n_samples is stored as 2 bytes). So maybe - * we could allocate a 128*16 array of samples, and shrink it back to the - * correct size when we know it? - * Alternatively, I could allocate samples by blocks of N (still O(n)), - * or double the number of allocated samples when I need more (O(log n)). - */ - total_samples = 0; - sigdata->sample = NULL; - - for (i = 0; i < sigdata->n_instruments; i++) { - XM_INSTRUMENT_EXTRA extra; - - DUMBFILE * lf = dumbfile_limit_xm( f ); - if ( !lf ) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) { - // XXX - if ( ! i ) - { - TRACE("XM error: instrument %d\n", i+1); - dumbfile_close( lf ); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - else - { - dumbfile_close( lf ); - sigdata->n_instruments = i; - break; - } - } - - if (extra.n_samples) { - unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT]; - - /* adjust instrument sample map (make indices absolute) */ - for (j = 0; j < 96; j++) - sigdata->instrument[i].map_sample[j] += total_samples; - - sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); - if (!sigdata->sample) { - dumbfile_close( lf ); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (j = total_samples; j < total_samples+extra.n_samples; j++) - sigdata->sample[j].data = NULL; - - if ( limit_xm_resize( lf, 0 ) < 0 ) { - dumbfile_close( lf ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - - /* read instrument's samples */ - for (j = 0; j < extra.n_samples; j++) { - IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; - int b; - if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) { - dumbfile_close( lf ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - b = it_xm_read_sample_header(sample, lf); - if (b < 0) { - dumbfile_close( lf ); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - roguebytes[j] = b; - // Any reason why these can't be set inside it_xm_read_sample_header()? - sample->vibrato_speed = extra.vibrato_speed; - sample->vibrato_depth = extra.vibrato_depth; - sample->vibrato_rate = extra.vibrato_sweep; - /* Rate and sweep don't match, but the difference is - * accounted for in itrender.c. - */ - sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type]; - sample->max_resampling_quality = -1; - } - for (j = 0; j < extra.n_samples; j++) { - if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) { - dumbfile_close( lf ); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - total_samples += extra.n_samples; - } - - dumbfile_close( lf ); - } - - sigdata->n_samples = total_samples; - } else { - // ahboy! old layout! - // first instruments and sample headers, then patterns, then sample data! - - /* - ----------------------------------- - --- Instruments and Samples --- - ----------------------------------- - */ - - unsigned char * roguebytes = malloc( sigdata->n_instruments * XM_MAX_SAMPLES_PER_INSTRUMENT ); - if (!roguebytes) { - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); - if (!sigdata->instrument) { - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - total_samples = 0; - sigdata->sample = NULL; - - for (i = 0; i < sigdata->n_instruments; i++) { - XM_INSTRUMENT_EXTRA extra; - - DUMBFILE * lf = dumbfile_limit_xm( f ); - if ( !lf ) { - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) { - TRACE("XM error: instrument %d\n", i+1); - dumbfile_close(lf); - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - - if (extra.n_samples) { - /* adjust instrument sample map (make indices absolute) */ - for (j = 0; j < 96; j++) - sigdata->instrument[i].map_sample[j] += total_samples; - - sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); - if (!sigdata->sample) { - dumbfile_close( lf ); - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (j = total_samples; j < total_samples+extra.n_samples; j++) - sigdata->sample[j].data = NULL; - - if ( limit_xm_resize( lf, 0 ) < 0 ) { - dumbfile_close( lf ); - free( roguebytes ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - - /* read instrument's samples */ - for (j = 0; j < extra.n_samples; j++) { - IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; - int b; - if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) { - dumbfile_close( lf ); - free( roguebytes ); - _dumb_it_unload_sigdata( sigdata ); - return NULL; - } - b = it_xm_read_sample_header(sample, lf); - if (b < 0) { - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - roguebytes[total_samples+j] = b; - // Any reason why these can't be set inside it_xm_read_sample_header()? - sample->vibrato_speed = extra.vibrato_speed; - sample->vibrato_depth = extra.vibrato_depth; - sample->vibrato_rate = extra.vibrato_sweep; - /* Rate and sweep don't match, but the difference is - * accounted for in itrender.c. - */ - sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type]; - sample->max_resampling_quality = -1; - } - total_samples += extra.n_samples; - } - - dumbfile_close( lf ); - } - - sigdata->n_samples = total_samples; - - /* - -------------------- - --- Patterns --- - -------------------- - */ - - sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); - if (!sigdata->pattern) { - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) - sigdata->pattern[i].entry = NULL; - - { - unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */ - if (!buffer) { - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - for (i = 0; i < sigdata->n_patterns; i++) { - if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) { - free(buffer); - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - free(buffer); - } - - // and now we load the sample data - for (j = 0; j < total_samples; j++) { - if (it_xm_read_sample_data(&sigdata->sample[j], roguebytes[j], f) != 0) { - free(roguebytes); - _dumb_it_unload_sigdata(sigdata); - return NULL; - } - } - - free(roguebytes); - } - - - sigdata->flags = IT_WAS_AN_XM | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_USE_INSTRUMENTS; - // Are we OK with IT_COMPATIBLE_GXX off? - // - // When specifying note + instr + tone portamento, and an old note is still playing (even after note off): - // - If Compatible Gxx is on, the new note will be triggered only if the instrument _changes_. - // - If Compatible Gxx is off, the new note will always be triggered, provided the instrument is specified. - // - FT2 seems to do the latter (unconfirmed). - - // Err, wait. XM playback has its own code. The change made to the IT - // playbackc code didn't affect XM playback. Forget this then. There's - // still a bug in XM playback though, and it'll need some investigation... - // tomorrow... - - // UPDATE: IT_COMPATIBLE_GXX is required to be on, so that tone porta has - // separate memory from portamento. - - if (flags & XM_LINEAR_FREQUENCY) - sigdata->flags |= IT_LINEAR_SLIDES; - - sigdata->global_volume = 128; - sigdata->mixing_volume = 48; - sigdata->pan_separation = 128; - - memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); - memset(sigdata->channel_pan, 32, DUMB_IT_N_CHANNELS); - - _dumb_it_fix_invalid_orders(sigdata); - - return sigdata; -} - - - -#if 0 // no fucking way, dude! - -/* The length returned is the time required to play from the beginning of the - * file to the last row of the last order (which is when the player will - * loop). Depending on the song, the sound might stop sooner. - * Due to fixed point roundoffs, I think this is only reliable to the second. - * Full precision could be achieved by using a double during the computation, - * or maybe a LONG_LONG. - */ -int32 it_compute_length(const DUMB_IT_SIGDATA *sigdata) -{ - IT_PATTERN *pattern; - int tempo, speed; - int loop_start[IT_N_CHANNELS]; - char loop_count[IT_N_CHANNELS]; - int order, entry; - int row_first_entry = 0; - int jump, jump_dest; - int delay, fine_delay; - int i; - int32 t; - - if (!sigdata) - return 0; - - tempo = sigdata->tempo; - speed = sigdata->speed; - order = entry = 0; - jump = jump_dest = 0; - t = 0; - - /* for each PATTERN */ - for (order = 0; order < sigdata->n_orders; order++) { - - if (sigdata->order[order] == IT_ORDER_END) break; - if (sigdata->order[order] == IT_ORDER_SKIP) continue; - - for (i = 0; i < IT_N_CHANNELS; i++) - loop_count[i] = -1; - - pattern = &sigdata->pattern[ sigdata->order[order] ]; - entry = 0; - if (jump == IT_BREAK_TO_ROW) { - int row = 0; - while (row < jump_dest) - if (pattern->entry[entry++].channel >= IT_N_CHANNELS) - row++; - } - - /* for each ROW */ - while (entry < pattern->n_entries) { - row_first_entry = entry; - delay = fine_delay = 0; - jump = 0; - - /* for each note NOTE */ - while (entry < pattern->n_entries && pattern->entry[entry].channel < IT_N_CHANNELS) { - int value = pattern->entry[entry].effectvalue; - int channel = pattern->entry[entry].channel; - - switch (pattern->entry[entry].effect) { - - case IT_SET_SPEED: speed = value; break; - - case IT_JUMP_TO_ORDER: - if (value <= order) /* infinite loop */ - return 0; - jump = IT_JUMP_TO_ORDER; - jump_dest = value; - break; - - case IT_BREAK_TO_ROW: - jump = IT_BREAK_TO_ROW; - jump_dest = value; - break; - - case IT_S: - switch (HIGH(value)) { - case IT_S_PATTERN_DELAY: delay = LOW(value); break; - case IT_S_FINE_PATTERN_DELAY: fine_delay = LOW(value); break; - case IT_S_PATTERN_LOOP: - if (LOW(value) == 0) { - loop_start[channel] = row_first_entry; - } else { - if (loop_count[channel] == -1) - loop_count[channel] = LOW(value); - - if (loop_count[channel]) { - jump = IT_S_PATTERN_LOOP; - jump_dest = loop_start[channel]; - } - loop_count[channel]--; - } - break; - } - break; - - case IT_SET_SONG_TEMPO: - switch (HIGH(value)) { /* slides happen every non-row frames */ - case 0: tempo = tempo - LOW(value)*(speed-1); break; - case 1: tempo = tempo + LOW(value)*(speed-1); break; - default: tempo = value; - } - tempo = MID(32, tempo, 255); - break; - } - - entry++; - } - - /* end of ROW */ - entry++; - t += TICK_TIME_DIVIDEND * (speed*(1+delay) + fine_delay) / tempo; - - if (jump == IT_JUMP_TO_ORDER) { - order = jump_dest - 1; - break; - } else if (jump == IT_BREAK_TO_ROW) - break; - else if (jump == IT_S_PATTERN_LOOP) - entry = jump_dest - 1; - } - - /* end of PATTERN */ - } - - return t; -} - -#endif /* 0 */ - - -static char hexdigit(int in) -{ - if (in < 10) return in + '0'; - else return in + 'A' - 10; -} - -DUH *DUMBEXPORT dumb_read_xm_quick(DUMBFILE *f) -{ - sigdata_t *sigdata; - int ver; - - DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; - - sigdata = it_xm_load_sigdata(f, &ver); - - if (!sigdata) - return NULL; - - { - char version[16]; - const char *tag[2][2]; - tag[0][0] = "TITLE"; - tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name); - tag[1][0] = "FORMAT"; - version[0] = 'X'; - version[1] = 'M'; - version[2] = ' '; - version[3] = 'v'; - version[4] = hexdigit( ( ver >> 8 ) & 15 ); - version[5] = '.'; - version[6] = hexdigit( ( ver >> 4 ) & 15 ); - version[7] = hexdigit( ver & 15 ); - version[8] = 0; - tag[1][1] = ( const char * ) & version; - return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); - } -} diff --git a/libraries/dumb/src/it/readxm2.c b/libraries/dumb/src/it/readxm2.c deleted file mode 100644 index 7a721d852..000000000 --- a/libraries/dumb/src/it/readxm2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * readxm2.c - Function to read a Fast Tracker II / / \ \ - * module from an open file and do an | < / \_ - * initial run-through. | \/ /\ / - * \_ / > / - * Split off from readxm.c by entheh. | \ / / - * | ' / - * \__/ - */ - -#include "dumb.h" - - - -DUH *DUMBEXPORT dumb_read_xm(DUMBFILE *f) -{ - DUH *duh = dumb_read_xm_quick(f); - dumb_it_do_initial_runthrough(duh); - return duh; -} diff --git a/libraries/dumb/src/it/xmeffect.c b/libraries/dumb/src/it/xmeffect.c deleted file mode 100644 index 96cf7da67..000000000 --- a/libraries/dumb/src/it/xmeffect.c +++ /dev/null @@ -1,245 +0,0 @@ -/* _______ ____ __ ___ ___ - * \ _ \ \ / \ / \ \ / / ' ' ' - * | | \ \ | | || | \/ | . . - * | | | | | | || ||\ /| | - * | | | | | | || || \/ | | ' ' ' - * | | | | | | || || | | . . - * | |_/ / \ \__// || | | - * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque - * / \ - * / . \ - * xmeffect.c - Code for converting MOD/XM / / \ \ - * effects to IT effects. | < / \_ - * | \/ /\ / - * By Julien Cugniere. Ripped out of readxm.c \_ / > / - * by entheh. | \ / / - * | ' / - * \__/ - */ - - - -#include -#include - -#include "dumb.h" -#include "internal/it.h" - -#if 0 -unsigned char **_dumb_malloc2(int w, int h) -{ - unsigned char **line = malloc(h * sizeof(*line)); - int i; - if (!line) return NULL; - - line[0] = malloc(w * h * sizeof(*line[0])); - if (!line[0]) { - free(line); - return NULL; - } - - for (i = 1; i < h; i++) - line[i] = line[i-1] + w; - - memset(line[0], 0, w*h); - - return line; -} - - - -void _dumb_free2(unsigned char **line) -{ - if (line) { - if (line[0]) - free(line[0]); - free(line); - } -} - - - -/* Effects having a memory. 2 means that the two parts of the effectvalue - * should be handled separately. - */ -static const char xm_has_memory[] = { -/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */ - 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, - -/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */ - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; -#endif - - - -/* Effects marked with 'special' are handled specifically in itrender.c */ -void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod) -{ -const int log = 0; - - if ((!effect && !value) || (effect >= XM_N_EFFECTS)) - return; - -if (log) printf("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value); - - /* Linearisation of the effect number... */ - if (effect == XM_E) { - effect = EBASE + HIGH(value); - value = LOW(value); - } else if (effect == XM_X) { - effect = XBASE + HIGH(value); - value = LOW(value); - } - -if (log) printf(" - %2d %02X", effect, value); - -#if 0 // This should be handled in itrender.c! - /* update effect memory */ - switch (xm_has_memory[effect]) { - case 1: - if (!value) - value = memory[entry->channel][effect]; - else - memory[entry->channel][effect] = value; - break; - - case 2: - if (!HIGH(value)) - SET_HIGH(value, HIGH(memory[entry->channel][effect])); - else - SET_HIGH(memory[entry->channel][effect], HIGH(value)); - - if (!LOW(value)) - SET_LOW(value, LOW(memory[entry->channel][effect])); - else - SET_LOW(memory[entry->channel][effect], LOW(value)); - break; - } -#endif - - /* convert effect */ - entry->mask |= IT_ENTRY_EFFECT; - switch (effect) { - - case XM_APPREGIO: effect = IT_ARPEGGIO; break; - case XM_VIBRATO: effect = IT_VIBRATO; break; - case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break; - case XM_TREMOLO: effect = IT_TREMOLO; break; - case XM_SET_PANNING: effect = IT_SET_PANNING; break; - case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break; - case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break; - case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break; - case XM_TREMOR: effect = IT_TREMOR; break; - case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break; - case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break; - case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */ - case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */ - case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */ - - case XM_PATTERN_BREAK: - effect = IT_BREAK_TO_ROW; - value = BCD_TO_NORMAL(value); - if (value > 63) value = 0; /* FT2, maybe ProTracker? */ - break; - - case XM_VOLUME_SLIDE: /* special */ - effect = IT_VOLUME_SLIDE; - value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value)); - break; - - case XM_PANNING_SLIDE: - effect = IT_PANNING_SLIDE; - //value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value)); - value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0); - break; - - case XM_GLOBAL_VOLUME_SLIDE: /* special */ - effect = IT_GLOBAL_VOLUME_SLIDE; - value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value)); - break; - - case XM_SET_TEMPO_BPM: - if (mod) effect = (value <= 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO); - else effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO); - break; - - case XM_SET_GLOBAL_VOLUME: - effect = IT_SET_GLOBAL_VOLUME; - value *= 2; - if (value > 128) value = 128; - break; - - case XM_KEY_OFF: - effect = IT_XM_KEY_OFF; - break; - - case XM_SET_ENVELOPE_POSITION: - effect = IT_XM_SET_ENVELOPE_POSITION; - break; - - case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break; - case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */ - case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; - case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break; - case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break; - case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break; - case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break; - case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break; - case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break; - case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break; - case EBASE+XM_E_SET_MIDI_MACRO: effect = SBASE+IT_S_SET_MIDI_MACRO; break; - - case EBASE + XM_E_FINE_PORTA_UP: - effect = IT_PORTAMENTO_UP; - value = EFFECT_VALUE(0xF, value); - break; - - case EBASE + XM_E_FINE_PORTA_DOWN: - effect = IT_PORTAMENTO_DOWN; - value = EFFECT_VALUE(0xF, value); - break; - - case EBASE + XM_E_RETRIG_NOTE: - effect = IT_XM_RETRIGGER_NOTE; - value = EFFECT_VALUE(0, value); - break; - - case EBASE + XM_E_SET_VIBRATO_CONTROL: - effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM; - value &= ~4; - break; - - case EBASE + XM_E_SET_TREMOLO_CONTROL: - effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM; - value &= ~4; - break; - - case XBASE + XM_X_EXTRAFINE_PORTA_UP: - effect = IT_PORTAMENTO_UP; - value = EFFECT_VALUE(0xE, value); - break; - - case XBASE + XM_X_EXTRAFINE_PORTA_DOWN: - effect = IT_PORTAMENTO_DOWN; - value = EFFECT_VALUE(0xE, value); - break; - - default: - /* user effect (often used in demos for synchronisation) */ - entry->mask &= ~IT_ENTRY_EFFECT; - } - -if (log) printf(" - %2d %02X", effect, value); - - /* Inverse linearisation... */ - if (effect >= SBASE && effect < SBASE+16) { - value = EFFECT_VALUE(effect-SBASE, value); - effect = IT_S; - } - -if (log) printf(" - %c%02X\n", 'A'+effect-1, value); - - entry->effect = effect; - entry->effectvalue = value; -} diff --git a/libraries/dumb/vc6/dumb/.gitignore b/libraries/dumb/vc6/dumb/.gitignore deleted file mode 100644 index a5aab370c..000000000 --- a/libraries/dumb/vc6/dumb/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.user -Debug -Release \ No newline at end of file diff --git a/libraries/dumb/vc6/dumb/dumb.vcxproj b/libraries/dumb/vc6/dumb/dumb.vcxproj deleted file mode 100644 index bc10c9a67..000000000 --- a/libraries/dumb/vc6/dumb/dumb.vcxproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {612D360C-A51B-4B34-8F49-33F42A2957F5} - dumb - - - - - - - - - - - - StaticLibrary - true - v120_xp - - - StaticLibrary - v120_xp - - - - - - - - - - - - - <_ProjectFileVersion>10.0.21006.1 - AllRules.ruleset - - - AllRules.ruleset - - - - - - Disabled - ../../include;%(AdditionalIncludeDirectories) - _USE_SSE;RESAMPLER_DECORATE=dumb;BARRAY_DECORATE=dumb;_DEBUG;WIN32;_LIB;DUMB_DECLARE_DEPRECATED;DEBUGMODE=1;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - Level3 - true - EditAndContinue - Default - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - MaxSpeed - AnySuitable - ../../include;%(AdditionalIncludeDirectories) - _USE_SSE;RESAMPLER_DECORATE=dumb;BARRAY_DECORATE=dumb;NDEBUG;WIN32;_LIB;DUMB_DECLARE_DEPRECATED;%(PreprocessorDefinitions) - true - MultiThreaded - true - Level3 - true - ProgramDatabase - Default - Fast - NoExtensions - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Document - true - true - - - Document - true - true - - - Document - true - true - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libraries/dumb/vc6/dumb/dumb.vcxproj.filters b/libraries/dumb/vc6/dumb/dumb.vcxproj.filters deleted file mode 100644 index bd096043f..000000000 --- a/libraries/dumb/vc6/dumb/dumb.vcxproj.filters +++ /dev/null @@ -1,326 +0,0 @@ - - - - - {419c5e1f-2bf4-473a-b2e5-2e531285aa62} - - - {44b333b3-1607-4820-82bc-e4c21a40e31a} - - - {0b122556-3781-4ef3-87fe-ffa5fb50b493} - - - {e961cd19-26f6-4df0-b895-e099d3e81db9} - - - {82e35139-08ff-4e99-a3ce-2254d7427ec4} - - - {5f7fc0f6-4008-4166-83ad-e5d914718bd0} - - - {0fd0715e-5824-4419-aa5b-2d4272d222ce} - - - {b9e26fe7-6056-4580-b2c6-10e6116d4129} - - - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\core - - - src\helpers - - - src\helpers - - - src\helpers - - - src\helpers - - - src\helpers - - - src\helpers - - - src\helpers - - - src\helpers - - - src\helpers - - - src\it\loaders - - - src\it\loaders - - - src\it - - - src\it - - - src\it\readers - - - src\it\readers - - - src\it - - - src\it - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it\readers - - - src\it - - - src\it\readers - - - src\it\readers - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\loaders - - - src\it\readers - - - src\it\readers - - - src\helpers - - - - - include - - - include\internal - - - include\internal - - - include\internal - - - include\internal - - - include\internal - - - include\internal - - - include\internal - - - include\internal - - - include\internal - - - - - src\helpers - - - src\helpers - - - src\helpers - - - \ No newline at end of file diff --git a/libraries/enet/CMakeLists.txt b/libraries/enet/CMakeLists.txt deleted file mode 100644 index 176361b3c..000000000 --- a/libraries/enet/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -make_release_only() - -if( DEM_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" ) -endif() - -if (MSVC) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996 /wd4244 /wd4018 /wd4267" ) # this code throws a lot of warnings. -endif() - -add_library( enet STATIC - callbacks.c - compress.c - host.c - list.c - packet.c - peer.c - protocol.c - unix.c # This and the next one are platform safe! - win32.c - ) -target_link_libraries( enet ) diff --git a/libraries/game-music-emu/CMakeLists.txt b/libraries/game-music-emu/CMakeLists.txt deleted file mode 100644 index 50325c6e8..000000000 --- a/libraries/game-music-emu/CMakeLists.txt +++ /dev/null @@ -1,146 +0,0 @@ -# CMake project definition file. -project(libgme) - -include (CheckCXXCompilerFlag) - -# When version is changed, also change the one in gme/gme.h to match -set(GME_VERSION 0.6.2 CACHE INTERNAL "libgme Version") - -# 2.6+ always assumes FATAL_ERROR, but 2.4 and below don't. -# Of course, 2.4 might work, in which case you're welcome to drop -# down the requirement, but I can't test that. -cmake_minimum_required(VERSION 2.6 FATAL_ERROR) - -# I don't plan on debugging this, so make it a release build. -if( NOT CMAKE_BUILD_TYPE MATCHES "Release" ) - set( CMAKE_BUILD_TYPE "RelWithDebInfo" ) -endif() - -if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" ) - if( NOT PROFILE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" ) - endif() - check_cxx_compiler_flag( -Wno-array-bounds HAVE_NO_ARRAY_BOUNDS ) - if( HAVE_NO_ARRAY_BOUNDS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-array-bounds" ) - endif() -endif() - -# Disable most of bogus and annoying MSVC warnings -if( MSVC ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4101 /wd4800 /wd4702 /wd4706 /wd4805 /wd4310 /wd4244 /wd4456 /wd4459 /wd4146 /wd4127 /wd4458 /wd4267 /wd4804") -endif() - -# Enable fast flag for GME -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DEM_FASTMATH_FLAG}" ) - -# Default emulators to build (all of them! ;) -# No options, enable all of them by default. - -#if (NOT DEFINED USE_GME_AY) - SET(USE_GME_AY 1 CACHE BOOL "Enable support for Spectrum ZX music emulation") -#endif() - -#if (NOT DEFINED USE_GME_GBS) - SET(USE_GME_GBS 1 CACHE BOOL "Enable support for Game Boy music emulation") -#endif() - -#if (NOT DEFINED USE_GME_GYM) - SET(USE_GME_GYM 1 CACHE BOOL "Enable Sega MegaDrive/Genesis music emulation") -#endif() - -#if (NOT DEFINED USE_GME_HES) - SET(USE_GME_HES 1 CACHE BOOL "Enable PC Engine/TurboGrafx-16 music emulation") -#endif() - -#if (NOT DEFINED USE_GME_KSS) - SET(USE_GME_KSS 1 CACHE BOOL "Enable MSX or other Z80 systems music emulation") -#endif() - -#if (NOT DEFINED USE_GME_NSF) - SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation") -#endif() - -#if (NOT DEFINED USE_GME_NSFE) - SET(USE_GME_NSFE 1 CACHE BOOL "Enable NES NSFE and NSF music emulation") -#endif() - -#if (NOT DEFINED USE_GME_SAP) - SET(USE_GME_SAP 1 CACHE BOOL "Enable Atari SAP music emulation") -#endif() - -#if (NOT DEFINED USE_GME_SPC) - SET(USE_GME_SPC 1 CACHE BOOL "Enable SNES SPC music emulation") -#endif() - -#if (NOT DEFINED USE_GME_VGM) - SET(USE_GME_VGM 1 CACHE BOOL "Enable Sega VGM/VGZ music emulation") -#endif() - -#if (NOT DEFINED GME_YM2612_EMU) - SET(GME_YM2612_EMU "Nuked" CACHE STRING "Which YM2612 emulator to use: \"Nuked\" (LGPLv2.1+), \"MAME\" (GPLv2+), or \"GENS\" (LGPLv2.1+)") -#endif() - -#if (USE_GME_NSFE AND NOT USE_GME_NSF) - #MESSAGE(" -- NSFE support requires NSF, enabling NSF support. --") - SET(USE_GME_NSF 1 CACHE BOOL "Enable NES NSF music emulation" FORCE) -#endif() - -# Set always to OFF. -set(BUILD_SHARED_LIBS OFF) -set(ENABLE_UBSAN OFF) - -# Check for GCC/Clang "visibility" support. -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - OR - CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -W -Wextra") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - - # Assume we have visibility support on any compiler that supports C++11 - add_definitions (-DLIBGME_VISIBILITY) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") - - # Try to protect against undefined behavior from signed integer overflow - # This has caused miscompilation of code already and there are other - # potential uses; see https://bitbucket.org/mpyne/game-music-emu/issues/18/ - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fwrapv") - - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if (NOT DEFINED LIBGME_SWITCH_FALLTHROUGH) - check_cxx_compiler_flag (-Wimplicit-fallthrough __LIBGME_SWITCH_FALLTHROUGH_WARNINGS) - set (LIBGME_SWITCH_FALLTHROUGH ${__LIBGME_SWITCH_FALLTHROUGH_WARNINGS} - CACHE BOOL "Set if the compiler will complain about implicit switch fallthrough" - ) - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override -Wno-unused-const-variable") - endif() - - if (ENABLE_UBSAN) - # GCC needs -static-libubsan - if (NOT BUILD_SHARED_LIBS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -static-libubsan") - else() - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") - endif() - endif() -endif () - -if(LIBGME_SWITCH_FALLTHROUGH) - # Avoid warning spam about switch fallthroughs, which are numerous in - # the codebase. - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wimplicit-fallthrough=0") -endif() - -# Shared library defined here -add_subdirectory(gme) - -# EXCLUDE_FROM_ALL adds build rules but keeps it out of default build -# Not needed. -if( FALSE ) -add_subdirectory(player EXCLUDE_FROM_ALL) -add_subdirectory(demo EXCLUDE_FROM_ALL) -endif() diff --git a/libraries/game-music-emu/changes.txt b/libraries/game-music-emu/changes.txt deleted file mode 100644 index 034ba4821..000000000 --- a/libraries/game-music-emu/changes.txt +++ /dev/null @@ -1,5 +0,0 @@ -Game_Music_Emu Change Log -------------------------- - -Please see the git version history (e.g. git shortlog tags/0.6.0..tags/0.6.1) -for the accurate change log. diff --git a/libraries/game-music-emu/design.txt b/libraries/game-music-emu/design.txt deleted file mode 100644 index d79c860f7..000000000 --- a/libraries/game-music-emu/design.txt +++ /dev/null @@ -1,194 +0,0 @@ -Game_Music_Emu 0.6.0 Design ---------------------------- -This might be slightly out-of-date at times, but will be a big help in -understanding the library implementation. - - -Architecture ------------- -The library is essentially a bunch of independent game music file -emulators unified with a common interface. - -Gme_File and Music_Emu provide a common interface to the emulators. The -virtual functions are protected rather than public to allow pre- and -post-processing of arguments and data in one place. This allows the -emulator classes to assume that everything is set up properly when -starting a track and playing samples. - -All file input is done with the Data_Reader interface. Many derived -classes are present, for the usual disk-based file and block of memory, -to specialized adaptors for things like reading a subset of data or -combining a block of memory with a Data_Reader to the remaining data. -This makes the library much more flexible with regard to the source of -game music file data. I still added a specialized load_mem() function to -have the emulator keep a pointer to data already read in memory, for -those formats whose files can be absolutely huge (GYM, some VGMs). This -is important if for some reason the caller must load the data ahead of -time, but doesn't want the emulator needlessly making a copy. - -Since silence checking and fading are relatively complex, they are kept -separate from basic file loading and track information, which are -handled in the base class Gme_File. My original intent was to use -Gme_File as the common base class for full emulators and track -information-only readers, but implementing the C interface was much -simpler if both derived from Music_Emu. User C++ code can still benefit -from static checking by using Gme_File where only track information will -be accessed. - -Each emulator generally has three components: main emulator, CPU -emulator, and sound chip emulator(s). Each component has minimal -coupling, so use in a full emulator or stand alone is fairly easy. This -modularity really helps reduce complexity. Blip_Buffer helps a lot with -simplifying the APU interfaces and implementation. - -The "classic" emulators derive from Classic_Emu, which handles -Blip_Buffer filling and multiple channels. It uses Multi_Buffer for -output, allowing you to derive a custom buffer that could output each -voice to a separate sound channel and do different processing on each. -At some point I'm going to implement a better Effects_Buffer that allows -individual control of every channel. - -In implementing the C interface, I wanted a way to specify an emulator -type that didn't require linking in all the emulators. For each emulator -type there is a global object with pointers to functions to create the -emulator or a track information reader. The emulator type is thus a -pointer to this, which conveniently allows for a NULL value. The user -referencing this emulator type object is what ultimately links the -emulator in (unless new Foo_Emu is used in C++, of course). This type -also serves as a useful substitute for RTTI on older C++ compilers. - -Addendum: I have since added gme_type_list(), which causes all listed -emulators to be linked in. To avoid this, I make the list itself -editable in blargg_config.h. Having a built-in list allows -gme_load_file() to take a path and give back an emulator with the file -loaded, which is extremely useful for new users. - - -Interface conventions ----------------------- -If a function retains a pointer to or replaces the value of an object -passed, it takes a pointer so that it will be clear in the caller's -source code that care is required. - -Multi-word names have an underscore '_' separator between individual -words. - -Functions are named with lowercase words. Functions which perform an -action with side-effects are named with a verb phrase (i.e. load, move, -run). Functions which return the value of a piece of state are named -using a noun phrase (i.e. loaded, moved, running). - -Classes are named with capitalized words. Only the first letter of an -acronym is capitalized. Class names are nouns, sometimes suggestive of -what they do (i.e. File_Scanner). - -Structure, enumeration, and typedefs to these and built-in types are -named using lowercase words with a _t suffix. - -Macros are named with all-uppercase words. - -Internal names which can't be hidden due to technical reasons have an -underscore '_' suffix. - - -Managing Complexity -------------------- -Complexity has been a factor in most library decisions. Many features -have been passed by due to the complexity they would add. Once -complexity goes past a certain level, it mentally grasping the library -in its entirety, at which point more defects will occur and be hard to -find. - -I chose 16-bit signed samples because it seems to be the most common -format. Supporting multiple formats would add too much complexity to be -worth it. Other formats can be obtained via conversion. - -I've kept interfaces fairly lean, leaving many possible features -untapped but easy to add if necessary. For example the classic emulators -could have volume and frequency equalization adjusted separately for -each channel, since they each have an associated Blip_Synth. - -Source files of 400 lines or less seem to be the best size to limit -complexity. In a few cases there is no reasonable way to split longer -files, or there is benefit from having the source together in one file. - - -Preventing Bugs ---------------- -I've done many things to reduce the opportunity for defects. A general -principle is to write code so that defects will be as visible as -possible. I've used several techniques to achieve this. - -I put assertions at key points where defects seem likely or where -corruption due to a defect is likely to be visible. I've also put -assertions where violations of the interface are likely. In emulators -where I am unsure of exact hardware operation in a particular case, I -output a debug-only message noting that this has occurred; many times I -haven't implemented a hardware feature because nothing uses it. I've -made code brittle where there is no clear reason flexibility; code -written to handle every possibility sacrifices quality and reliability -to handle vaguely defined situations. - - -Flexibility through indirection -------------------------------- -I've tried to allow the most flexibility of modules by using indirection -to allow extension by the user. This keeps each module simpler and more -focused on its unique task. - -The classic emulators use Multi_Buffer, which potentially allows a -separate Blip_Buffer for each channel. This keeps emulators free of -typical code to allow output in mono, stereo, panning, etc. - -All emulators use a reader object to access file data, allowing it to be -stored in a regular file, compressed archive, memory, or generated -on-the-fly. Again, the library can be kept free of the particulars of -file access and changes required to support new formats. - - -Emulators in general --------------------- -When I wrote the first NES sound emulator, I stored most of the state in -an emulator-specific format, with significant redundancy. In the -register write function I decoded everything into named variables. I -became tired of the verbosity and wanted to more closely model the -hardware, so I moved to a style of storing the last written value to -each register, along with as little other state as possible, mostly the -internal hardware registers. While this involves slightly more -recalculation, in most cases the emulation code is of comparable size. -It also makes state save/restore (for use in a full emulator) much -simpler. Finally, it makes debugging easier since the hardware registers -used in emulation are obvious. - - -CPU Cores ---------- -I've spent lots of time coming up with techniques to optimize the CPU -cores. Some of the most important: execute multiple instructions during -an emulation call, keep state in local variables to allow register -assignment, optimize state representation for most common instructions, -defer status flag calculation until actually needed, read program code -directly without a call to the memory read function, always pre-fetch -the operand byte before decoding instruction, and emulate instructions -using common blocks of code. - -I've successfully used Nes_Cpu in a fairly complete NES emulator, and -I'd like to make all the CPU emulators suitable for use in emulators. It -seems a waste for them to be used only for the small amount of emulation -necessary for game music files. - -I debugged the CPU cores by writing a test shell that ran them in -parallel with other CPU cores and compared all memory accesses and -processor states at each step. This provided good value at little cost. - -The CPU mapping page size is adjustable to allow the best tradeoff -between memory/cache usage and handler granularity. The interface allows -code to be somewhat independent of the page size. - -I optimize program memory accesses to direct reads rather than calls to -the memory read function. My assumption is that it would be difficult to -get useful code out of hardware I/O addresses, so no software will -intentionally execute out of I/O space. Since the page size can be -changed easily, most program memory mapping schemes can be accommodated. -This greatly reduces memory access function calls. - diff --git a/libraries/game-music-emu/gme.txt b/libraries/game-music-emu/gme.txt deleted file mode 100644 index 5a7d2f560..000000000 --- a/libraries/game-music-emu/gme.txt +++ /dev/null @@ -1,376 +0,0 @@ -Game_Music_Emu 0.6.2 --------------------- -Author : Shay Green -Maintainer : Michael Pyne -Website : https://bitbucket.org/mpyne/game-music-emu/ -Source : https://bitbucket.org/mpyne/game-music-emu/ -License : GNU Lesser General Public License (LGPL), see LICENSE.txt - -Contents --------- -* Overview -* Error handling -* Emulator types -* M3U playlist support -* Information fields -* Track length -* Loading file data -* Sound parameters -* VGM/GYM YM2413 & YM2612 FM sound -* Modular construction -* Obscure features -* Solving problems -* Thanks - - -Overview --------- -This library can open game music files, play tracks, and read game and -track information tags. To play a game music file, do the following: - -* Open the file with gme_open_file() -* Start a track with gme_start_track(); -* Generate samples as needed with gme_play() -* Play samples through speaker using your operating system -* Delete emulator when done with gme_delete() - -Your code must arrange for the generated samples to be played through -the computer's speaker using whatever method your operating system -requires. - -There are many additional features available; you can: - -* Determine of the type of a music file without opening it with -gme_identify_*() -* Load just the file's information tags with gme_info_only -* Load from a block of memory rather than a file with gme_load_data() -* Arrange for a fade-out at a particular time with gme_set_fade -* Find when a track has ended with gme_track_ended() -* Seek to a new time in the track with gme_seek() -* Load an extended m3u playlist with gme_load_m3u() -* Get a list of the voices (channels) and mute them individually with -gme_voice_names() and gme_mute_voice() -* Change the playback tempo without affecting pitch with gme_set_tempo() -* Adjust treble/bass equalization with gme_set_equalizer() -* Associate your own data with an emulator and later get it back with -gme_set_user_data() -* Register a function of yours to be called back when the emulator is -deleted with gme_set_user_cleanup() - -Refer to gme.h for a comprehensive summary of features. - - -Error handling --------------- -Functions which can fail have a return type of gme_err_t, which is a -pointer to an error string (const char*). If a function is successful it -returns NULL. Errors that you can easily avoid are checked with debug -assertions; gme_err_t return values are only used for genuine run-time -errors that can't be easily predicted in advance (out of memory, I/O -errors, incompatible file data). Your code should check all error -values. - -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 -error in C++ like this: - - gme_err_t err = gme_open_file( path, &emu ); - if ( err == gme_wrong_file_type ) - ... - -To check for minor problems, call gme_warning() to get a string -describing the last warning. Your player should allow the user some way -of knowing when this is the case, since these minor errors could affect -playback. Without this information the user can't solve problems as -well. When playing a track, gme_warning() returns minor playback-related -problems (major playback problems end the track immediately and set the -warning string). - - -Emulator types --------------- -The library includes several game music emulators that each support a -different file type. Each is identified by a gme_type_t constant defined -in gme.h, for example gme_nsf_emu is for the NSF emulator. If you use -gme_open_file() or gme_open_data(), the library does the work of -determining the file type and creating an appropriate emulator. If you -want more control over this process, read on. - -There are two basic ways to identify a game music file's type: look at -its file extension, or read the header data. The library includes -functions to help with both methods. The first is preferable because it -is fast and the most common way to identify files. Sometimes the -extension is lost or wrong, so the header must be read. - -Use gme_identify_extension() to find the correct game music type based -on a filename. To identify a file based on its extension and header -contents, use gme_identify_file(). If you read the header data yourself, -use gme_identify_header(). - -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 -support just NSF and GBS, use this: - - #define GME_TYPE_LIST \ - gme_nsf_type,\ - gme_gbs_type - - -M3U playlist support --------------------- -The library supports playlists in an extended m3u format with -gme_load_m3u() to give track names and times to multi-song formats: AY, -GBS, HES, KSS, NSF, NSFE, and SAP. Some aspects of the file format -itself is not well-defined so some m3u files won't work properly -(particularly those provided with KSS files). Only m3u files referencing -a single file are supported; your code must handle m3u files covering -more than one game music file, though it can use the built-in m3u -parsing provided by the library. - - -Information fields ------------------- -Support is provided for the various text fields and length information -in a file with gme_track_info(). If you just need track information for -a file (for example, building a playlist), use gme_new_info() in place -of gme_new_emu(), load the file normally, then you can access the track -count and info, but nothing else. - - M3U VGM GYM SPC SAP NSFE NSF AY GBS HES KSS - ------------------------------------------------------- -Track Count | * * * * * * * * * - | -System | * * * * * * * * * * - | -Game | * * * * * * * - | -Song | * * * * * * * - | -Author | * * * * * * * * - | -Copyright | * * * * * * * * - | -Comment | * * * * - | -Dumper | * * * * - | -Length | * * * * * * - | -Intro Length| * * * - | -Loop Length | * * * - -As listed above, the HES and KSS file formats don't include a track -count, and tracks are often scattered over the 0-255 range, so an m3u -playlist for these is a must. - -Unavailable text fields are set to an empty string and times to -1. Your -code should be prepared for any combination of available and unavailable -fields, as a particular music file might not use all of the supported -fields listed above. - -Currently text fields are truncated to 255 characters. Obscure fields of -some formats are not currently decoded; contact me if you want one -added. - - -Track length ------------- -The library leaves it up to you as to when to stop playing a track. You -can ask for available length information and then tell the library what -time it should start fading the track with gme_set_fade(). By default it -also continually checks for 6 or more seconds of silence to mark the end -of a track. Here is a reasonable algorithm you can use to decide how -long to play a track: - -* If the track length is > 0, use it -* If the loop length > 0, play for intro + loop * 2 -* Otherwise, default to 2.5 minutes (150000 msec) - -If you want to play a track longer than normal, be sure the loop length -isn't zero. See Music_Player.cpp around line 145 for example code. - -By default, the library skips silence at the beginning of a track. It -also continually checks for the end of a non-looping track by watching -for 6 seconds of unbroken silence. When doing this is scans *ahead* by -several seconds so it can report the end of the track after only one -second of silence has actually played. This feature can be disabled with -gme_ignore_silence(). - - -Loading file data ------------------ -The library allows file data to be loaded in many different ways. All -load functions return an error which you should check. The following -examples assume these variables: - - Music_Emu* emu; - gme_err_t error; - -If you're letting the library determine a file's type, you can use -either gme_open_file() or gme_open_data(): - - error = gme_open_file( pathname, &emu ); - error = gme_open_data( pointer, size, &emu ); - -If you're manually determining file type and using used gme_new_emu() to -create an emulator, you can use the following methods of loading: - -* From a block of memory: - - error = gme_load_data( emu, pointer, size ); - -* Have library call your function to read data: - - gme_err_t my_read( void* my_data, void* out, long count ) - { - // code that reads 'count' bytes into 'out' buffer - // and return 0 if no error - } - - error = gme_load_custom( emu, my_read, file_size, my_data ); - - -Sound parameters ----------------- -All emulators support an arbitrary output sampling rate. A rate of 44100 -Hz should work well on most systems. Since band-limited synthesis is -used, a sampling rate above 48000 Hz is not necessary and will actually -reduce sound quality and performance. - -All emulators also support adjustable gain, mainly for the purpose of -getting consistent volume between different music formats and avoiding -excessive modulation. The gain can only be set *before* setting the -emulator's sampling rate, so it's not useful as a general volume -control. The default gains of emulators are set so that they give -generally similar volumes, though some soundtracks are significantly -louder or quieter than normal. - -Some emulators support adjustable treble and bass frequency equalization -(AY, GBS, HES, KSS, NSF, NSFE, SAP, VGM) using set_equalizer(). -Parameters are specified using gme_equalizer_t eq = { treble_dB, -bass_freq }. Treble_dB sets the treble level (in dB), where 0.0 dB gives -normal treble; -200.0 dB is quite muffled, and 5.0 dB emphasizes treble -for an extra crisp sound. Bass_freq sets the frequency where bass -response starts to diminish; 15 Hz is normal, 0 Hz gives maximum bass, -and 15000 Hz removes all bass. For example, the following makes the -sound extra-crisp but lacking bass: - - gme_equalizer_t eq = { 5.0, 1000 }; - gme_set_equalizer( music_emu, &eq ); - -Each emulator's equalization defaults to approximate the particular -console's sound quality; this default can be determined by calling -equalizer() just after creating the emulator. The Music_Emu::tv_eq -profile gives sound as if coming from a TV speaker, and some emulators -include other profiles for different versions of the system. For -example, to use Famicom sound equalization with the NSF emulator, do the -following: - - music_emu->set_equalizer( Nsf_Emu::famicom_eq ); - - -VGM/GYM YM2413 & YM2612 FM sound --------------------------------- -The library plays Sega Genesis/Mega Drive music using a YM2612 FM sound -chip emulator based on the Gens project. Because this has some -inaccuracies, other YM2612 emulators can be used in its place by -re-implementing the interface in YM2612_Emu.h. Available on my website -is a modified version of MAME's YM2612 emulator, which sounds better in -some ways and whose author is still making improvements. - -VGM music files using the YM2413 FM sound chip are also supported, but a -YM2413 emulator isn't included with the library due to technical -reasons. I have put one of the available YM2413 emulators on my website -that can be used directly. - - -Modular construction --------------------- -The library is made of many fairly independent modules. If you're using -only one music file emulator, you can eliminate many of the library -sources from your program. Refer to the files list in readme.txt to get -a general idea of what can be removed, and be sure to edit GME_TYPE_LIST -(see "Emulator types" above). Post to the forum if you'd like me to put -together a smaller version for a particular use, as this only takes me a -few minutes to do. - -If you want to use one of the individual sound chip emulators (or CPU -cores) in your own console emulator, first check the libraries page on -my website since I have released several of them as stand alone -libraries with included documentation and examples on their use. If you -don't find it as a standalone library, contact me and I'll consider -separating it. - -The "classic" sound chips use my Blip_Buffer library, which greatly -simplifies their implementation and efficiently handles band-limited -synthesis. It is also available as a stand alone library with -documentation and many examples. - - -Obscure features ----------------- -The library's flexibility allows many possibilities. Contact me if you -want help implementing ideas or removing limitations. - -* Uses no global/static variables, allowing multiple instances of any -emulator. This is useful in a music player if you want to allow -simultaneous recording or scanning of other tracks while one is already -playing. This will also be useful if your platform disallows global -data. - -* Emulators that support a custom sound buffer can have *every* voice -routed to a different Blip_Buffer, allowing custom processing on each -voice. For example you could record a Game Boy track as a 4-channel -sound file. - -* Defining BLIP_BUFFER_FAST uses lower quality, less-multiply-intensive -synthesis on "classic" emulators, which might help on some really old -processors. This significantly lowers sound quality and prevents treble -equalization. Try this if your platform's processor isn't fast enough -for normal quality. Even on my ten-year-old 400 MHz Mac, this reduces -processor usage at most by about 0.6% (from 4% to 3.4%), hardly worth -the quality loss. - - -Solving problems ----------------- -If you're having problems, try the following: - -* If you're getting garbled sound, try this simple siren generator in -place of your call to play(). This will quickly tell whether the problem -is in the library or in your code. - - static void play_siren( long count, short* out ) - { - static double a, a2; - while ( count-- ) - *out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) ); - } - -* Enable debugging support in your environment. This enables assertions -and other run-time checks. - -* Turn the compiler's optimizer is off. Sometimes an optimizer generates -bad code. - -* If multiple threads are being used, ensure that only one at a time is -accessing a given set of objects from the library. This library is not -in general thread-safe, though independent objects can be used in -separate threads. - -* If all else fails, see if the demos work. - - -Thanks ------- -Big thanks to Chris Moeller (kode54) for help with library testing and -feedback, for maintaining the Foobar2000 plugin foo_gep based on it, and -for original work on openspc++ that was used when developing Spc_Emu. -Brad Martin's excellent OpenSPC SNES DSP emulator worked well from the -start. Also thanks to Richard Bannister, Mahendra Tallur, Shazz, -nenolod, theHobbit, Johan Samuelsson, and nes6502 for testing, using, -and giving feedback for the library in their respective game music -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. diff --git a/libraries/game-music-emu/gme/Ay_Apu.cpp b/libraries/game-music-emu/gme/Ay_Apu.cpp deleted file mode 100644 index d132c42f9..000000000 --- a/libraries/game-music-emu/gme/Ay_Apu.cpp +++ /dev/null @@ -1,395 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Ay_Apu.h" - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// Emulation inaccuracies: -// * Noise isn't run when not in use -// * Changes to envelope and noise periods are delayed until next reload -// * Super-sonic tone should attenuate output to about 60%, not 50% - -// Tones above this frequency are treated as disabled tone at half volume. -// Power of two is more efficient (avoids division). -unsigned const inaudible_freq = 16384; - -int const period_factor = 16; - -static byte const amp_table [16] = -{ -#define ENTRY( n ) byte (n * Ay_Apu::amp_range + 0.5) - // With channels tied together and 1K resistor to ground (as datasheet recommends), - // output nearly matches logarithmic curve as claimed. Approx. 1.5 dB per step. - ENTRY(0.000000),ENTRY(0.007813),ENTRY(0.011049),ENTRY(0.015625), - ENTRY(0.022097),ENTRY(0.031250),ENTRY(0.044194),ENTRY(0.062500), - ENTRY(0.088388),ENTRY(0.125000),ENTRY(0.176777),ENTRY(0.250000), - ENTRY(0.353553),ENTRY(0.500000),ENTRY(0.707107),ENTRY(1.000000), - - /* - // Measured from an AY-3-8910A chip with date code 8611. - - // Direct voltages without any load (very linear) - ENTRY(0.000000),ENTRY(0.046237),ENTRY(0.064516),ENTRY(0.089785), - ENTRY(0.124731),ENTRY(0.173118),ENTRY(0.225806),ENTRY(0.329032), - ENTRY(0.360215),ENTRY(0.494624),ENTRY(0.594624),ENTRY(0.672043), - ENTRY(0.766129),ENTRY(0.841935),ENTRY(0.926882),ENTRY(1.000000), - // With only some load - ENTRY(0.000000),ENTRY(0.011940),ENTRY(0.017413),ENTRY(0.024876), - ENTRY(0.036318),ENTRY(0.054229),ENTRY(0.072637),ENTRY(0.122388), - ENTRY(0.174129),ENTRY(0.239303),ENTRY(0.323881),ENTRY(0.410945), - ENTRY(0.527363),ENTRY(0.651741),ENTRY(0.832338),ENTRY(1.000000), - */ -#undef ENTRY -}; - -static byte const modes [8] = -{ -#define MODE( a0,a1, b0,b1, c0,c1 ) \ - (a0 | a1<<1 | b0<<2 | b1<<3 | c0<<4 | c1<<5) - MODE( 1,0, 1,0, 1,0 ), - MODE( 1,0, 0,0, 0,0 ), - MODE( 1,0, 0,1, 1,0 ), - MODE( 1,0, 1,1, 1,1 ), - MODE( 0,1, 0,1, 0,1 ), - MODE( 0,1, 1,1, 1,1 ), - MODE( 0,1, 1,0, 0,1 ), - MODE( 0,1, 0,0, 0,0 ), -}; - -Ay_Apu::Ay_Apu() -{ - // build full table of the upper 8 envelope waveforms - for ( int m = 8; m--; ) - { - byte* out = env.modes [m]; - int flags = modes [m]; - for ( int x = 3; --x >= 0; ) - { - int amp = flags & 1; - int end = flags >> 1 & 1; - int step = end - amp; - amp *= 15; - for ( int y = 16; --y >= 0; ) - { - *out++ = amp_table [amp]; - amp += step; - } - flags >>= 2; - } - } - - output( 0 ); - volume( 1.0 ); - reset(); -} - -void Ay_Apu::reset() -{ - last_time = 0; - noise.delay = 0; - noise.lfsr = 1; - - osc_t* osc = &oscs [osc_count]; - do - { - osc--; - osc->period = period_factor; - osc->delay = 0; - osc->last_amp = 0; - osc->phase = 0; - } - while ( osc != oscs ); - - for ( int i = sizeof regs; --i >= 0; ) - regs [i] = 0; - regs [7] = 0xFF; - write_data_( 13, 0 ); -} - -void Ay_Apu::write_data_( int addr, int data ) -{ - assert( (unsigned) addr < reg_count ); - - if ( (unsigned) addr >= 14 ) - { - #ifdef debug_printf - debug_printf( "Wrote to I/O port %02X\n", (int) addr ); - #endif - } - - // envelope mode - if ( addr == 13 ) - { - if ( !(data & 8) ) // convert modes 0-7 to proper equivalents - data = (data & 4) ? 15 : 9; - env.wave = env.modes [data - 7]; - env.pos = -48; - env.delay = 0; // will get set to envelope period in run_until() - } - regs [addr] = data; - - // handle period changes accurately - int i = addr >> 1; - if ( i < osc_count ) - { - blip_time_t period = (regs [i * 2 + 1] & 0x0F) * (0x100L * period_factor) + - regs [i * 2] * period_factor; - if ( !period ) - period = period_factor; - - // adjust time of next timer expiration based on change in period - osc_t& osc = oscs [i]; - if ( (osc.delay += period - osc.period) < 0 ) - osc.delay = 0; - osc.period = period; - } - - // TODO: same as above for envelope timer, and it also has a divide by two after it -} - -int const noise_off = 0x08; -int const tone_off = 0x01; - -void Ay_Apu::run_until( blip_time_t final_end_time ) -{ - require( final_end_time >= last_time ); - - // noise period and initial values - blip_time_t const noise_period_factor = period_factor * 2; // verified - blip_time_t noise_period = (regs [6] & 0x1F) * noise_period_factor; - if ( !noise_period ) - noise_period = noise_period_factor; - blip_time_t const old_noise_delay = noise.delay; - blargg_ulong const old_noise_lfsr = noise.lfsr; - - // envelope period - blip_time_t const env_period_factor = period_factor * 2; // verified - blip_time_t env_period = (regs [12] * 0x100L + regs [11]) * env_period_factor; - if ( !env_period ) - env_period = env_period_factor; // same as period 1 on my AY chip - if ( !env.delay ) - env.delay = env_period; - - // run each osc separately - for ( int index = 0; index < osc_count; index++ ) - { - osc_t* const osc = &oscs [index]; - int osc_mode = regs [7] >> index; - - // output - Blip_Buffer* const osc_output = osc->output; - if ( !osc_output ) - continue; - osc_output->set_modified(); - - // period - int half_vol = 0; - blip_time_t inaudible_period = (blargg_ulong) (osc_output->clock_rate() + - inaudible_freq) / (inaudible_freq * 2); - if ( osc->period <= inaudible_period && !(osc_mode & tone_off) ) - { - half_vol = 1; // Actually around 60%, but 50% is close enough - osc_mode |= tone_off; - } - - // envelope - blip_time_t start_time = last_time; - blip_time_t end_time = final_end_time; - int const vol_mode = regs [0x08 + index]; - int volume = amp_table [vol_mode & 0x0F] >> half_vol; - int osc_env_pos = env.pos; - if ( vol_mode & 0x10 ) - { - volume = env.wave [osc_env_pos] >> half_vol; - // use envelope only if it's a repeating wave or a ramp that hasn't finished - if ( !(regs [13] & 1) || osc_env_pos < -32 ) - { - end_time = start_time + env.delay; - if ( end_time >= final_end_time ) - end_time = final_end_time; - - //if ( !(regs [12] | regs [11]) ) - // debug_printf( "Used envelope period 0\n" ); - } - else if ( !volume ) - { - osc_mode = noise_off | tone_off; - } - } - else if ( !volume ) - { - osc_mode = noise_off | tone_off; - } - - // tone time - blip_time_t const period = osc->period; - blip_time_t time = start_time + osc->delay; - if ( osc_mode & tone_off ) // maintain tone's phase when off - { - blargg_long count = (final_end_time - time + period - 1) / period; - time += count * period; - osc->phase ^= count & 1; - } - - // noise time - blip_time_t ntime = final_end_time; - blargg_ulong noise_lfsr = 1; - if ( !(osc_mode & noise_off) ) - { - ntime = start_time + old_noise_delay; - noise_lfsr = old_noise_lfsr; - //if ( (regs [6] & 0x1F) == 0 ) - // debug_printf( "Used noise period 0\n" ); - } - - // The following efficiently handles several cases (least demanding first): - // * Tone, noise, and envelope disabled, where channel acts as 4-bit DAC - // * Just tone or just noise, envelope disabled - // * Envelope controlling tone and/or noise - // * Tone and noise disabled, envelope enabled with high frequency - // * Tone and noise together - // * Tone and noise together with envelope - - // This loop only runs one iteration if envelope is disabled. If envelope - // is being used as a waveform (tone and noise disabled), this loop will - // still be reasonably efficient since the bulk of it will be skipped. - while ( 1 ) - { - // current amplitude - int amp = 0; - if ( (osc_mode | osc->phase) & 1 & (osc_mode >> 3 | noise_lfsr) ) - amp = volume; - { - int delta = amp - osc->last_amp; - if ( delta ) - { - osc->last_amp = amp; - synth_.offset( start_time, delta, osc_output ); - } - } - - // Run wave and noise interleved with each catching up to the other. - // If one or both are disabled, their "current time" will be past end time, - // so there will be no significant performance hit. - if ( ntime < end_time || time < end_time ) - { - // Since amplitude was updated above, delta will always be +/- volume, - // so we can avoid using last_amp every time to calculate the delta. - int delta = amp * 2 - volume; - int delta_non_zero = delta != 0; - int phase = osc->phase | (osc_mode & tone_off); assert( tone_off == 0x01 ); - do - { - // run noise - blip_time_t end = end_time; - if ( end_time > time ) end = time; - if ( phase & delta_non_zero ) - { - while ( ntime <= end ) // must advance *past* time to avoid hang - { - int changed = noise_lfsr + 1; - noise_lfsr = (-(noise_lfsr & 1) & 0x12000) ^ (noise_lfsr >> 1); - if ( changed & 2 ) - { - delta = -delta; - synth_.offset( ntime, delta, osc_output ); - } - ntime += noise_period; - } - } - else - { - // 20 or more noise periods on average for some music - blargg_long remain = end - ntime; - blargg_long count = remain / noise_period; - if ( remain >= 0 ) - ntime += noise_period + count * noise_period; - } - - // run tone - end = end_time; - if ( end_time > ntime ) end = ntime; - if ( noise_lfsr & delta_non_zero ) - { - while ( time < end ) - { - delta = -delta; - synth_.offset( time, delta, osc_output ); - time += period; - //phase ^= 1; - } - //assert( phase == (delta > 0) ); - phase = unsigned (-delta) >> (CHAR_BIT * sizeof (unsigned) - 1); - // (delta > 0) - } - else - { - // loop usually runs less than once - //SUB_CASE_COUNTER( (time < end) * (end - time + period - 1) / period ); - - while ( time < end ) - { - time += period; - phase ^= 1; - } - } - } - while ( time < end_time || ntime < end_time ); - - osc->last_amp = (delta + volume) >> 1; - if ( !(osc_mode & tone_off) ) - osc->phase = phase; - } - - if ( end_time >= final_end_time ) - break; // breaks first time when envelope is disabled - - // next envelope step - if ( ++osc_env_pos >= 0 ) - osc_env_pos -= 32; - volume = env.wave [osc_env_pos] >> half_vol; - - start_time = end_time; - end_time += env_period; - if ( end_time > final_end_time ) - end_time = final_end_time; - } - osc->delay = time - final_end_time; - - if ( !(osc_mode & noise_off) ) - { - noise.delay = ntime - final_end_time; - noise.lfsr = noise_lfsr; - } - } - - // TODO: optimized saw wave envelope? - - // maintain envelope phase - blip_time_t remain = final_end_time - last_time - env.delay; - if ( remain >= 0 ) - { - blargg_long count = (remain + env_period) / env_period; - env.pos += count; - if ( env.pos >= 0 ) - env.pos = (env.pos & 31) - 32; - remain -= count * env_period; - assert( -remain <= env_period ); - } - env.delay = -remain; - assert( env.delay > 0 ); - assert( env.pos < 0 ); - - last_time = final_end_time; -} diff --git a/libraries/game-music-emu/gme/Ay_Apu.h b/libraries/game-music-emu/gme/Ay_Apu.h deleted file mode 100644 index ad2d83692..000000000 --- a/libraries/game-music-emu/gme/Ay_Apu.h +++ /dev/null @@ -1,106 +0,0 @@ -// AY-3-8910 sound chip emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef AY_APU_H -#define AY_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -class Ay_Apu { -public: - // Set buffer to generate all sound into, or disable sound if NULL - void output( Blip_Buffer* ); - - // Reset sound chip - void reset(); - - // Write to register at specified time - enum { reg_count = 16 }; - void write( blip_time_t time, int addr, int data ); - - // Run sound to specified time, end current time frame, then start a new - // time frame at time 0. Time frames have no effect on emulation and each - // can be whatever length is convenient. - void end_frame( blip_time_t length ); - -// Additional features - - // Set sound output of specific oscillator to buffer, where index is - // 0, 1, or 2. If buffer is NULL, the specified oscillator is muted. - enum { osc_count = 3 }; - void osc_output( int index, Blip_Buffer* ); - - // Set overall volume (default is 1.0) - void volume( double ); - - // Set treble equalization (see documentation) - void treble_eq( blip_eq_t const& ); - -public: - Ay_Apu(); - typedef unsigned char byte; -private: - struct osc_t - { - blip_time_t period; - blip_time_t delay; - short last_amp; - short phase; - Blip_Buffer* output; - } oscs [osc_count]; - blip_time_t last_time; - byte regs [reg_count]; - - struct { - blip_time_t delay; - blargg_ulong lfsr; - } noise; - - struct { - blip_time_t delay; - byte const* wave; - int pos; - byte modes [8] [48]; // values already passed through volume table - } env; - - void run_until( blip_time_t ); - void write_data_( int addr, int data ); -public: - enum { amp_range = 255 }; - Blip_Synth synth_; -}; - -inline void Ay_Apu::volume( double v ) { synth_.volume( 0.7 / osc_count / amp_range * v ); } - -inline void Ay_Apu::treble_eq( blip_eq_t const& eq ) { synth_.treble_eq( eq ); } - -inline void Ay_Apu::write( blip_time_t time, int addr, int data ) -{ - run_until( time ); - write_data_( addr, data ); -} - -inline void Ay_Apu::osc_output( int i, Blip_Buffer* buf ) -{ - assert( (unsigned) i < osc_count ); - oscs [i].output = buf; -} - -inline void Ay_Apu::output( Blip_Buffer* buf ) -{ - osc_output( 0, buf ); - osc_output( 1, buf ); - osc_output( 2, buf ); -} - -inline void Ay_Apu::end_frame( blip_time_t time ) -{ - if ( time > last_time ) - run_until( time ); - - assert( last_time >= time ); - last_time -= time; -} - -#endif diff --git a/libraries/game-music-emu/gme/Ay_Cpu.cpp b/libraries/game-music-emu/gme/Ay_Cpu.cpp deleted file mode 100644 index 31c912568..000000000 --- a/libraries/game-music-emu/gme/Ay_Cpu.cpp +++ /dev/null @@ -1,1659 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -/* -Last validated with zexall 2006.11.21 5:26 PM -* Doesn't implement the R register or immediate interrupt after EI. -* Address wrap-around isn't completely correct, but is prevented from crashing emulator. -*/ - -#include "Ay_Cpu.h" - -#include "blargg_endian.h" -#include - -//#include "z80_cpu_log.h" - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -#define SYNC_TIME() (void) (s.time = s_time) -#define RELOAD_TIME() (void) (s_time = s.time) - -// Callbacks to emulator - -#define CPU_OUT( cpu, addr, data, TIME )\ - ay_cpu_out( cpu, TIME, addr, data ) - -#define CPU_IN( cpu, addr, TIME )\ - ay_cpu_in( cpu, addr ) - -#include "blargg_source.h" - -// flags, named with hex value for clarity -int const S80 = 0x80; -int const Z40 = 0x40; -int const F20 = 0x20; -int const H10 = 0x10; -int const F08 = 0x08; -int const V04 = 0x04; -int const P04 = 0x04; -int const N02 = 0x02; -int const C01 = 0x01; - -#define SZ28P( n ) szpc [n] -#define SZ28PC( n ) szpc [n] -#define SZ28C( n ) (szpc [n] & ~P04) -#define SZ28( n ) SZ28C( n ) - -#define SET_R( n ) (void) (r.r = n) -#define GET_R() (r.r) - -Ay_Cpu::Ay_Cpu() -{ - state = &state_; - for ( int i = 0x100; --i >= 0; ) - { - int even = 1; - for ( int p = i; p; p >>= 1 ) - even ^= p; - int n = (i & (S80 | F20 | F08)) | ((even & 1) * P04); - szpc [i] = n; - szpc [i + 0x100] = n | C01; - } - szpc [0x000] |= Z40; - szpc [0x100] |= Z40; -} - -void Ay_Cpu::reset( void* m ) -{ - mem = (uint8_t*) m; - - check( state == &state_ ); - state = &state_; - state_.time = 0; - state_.base = 0; - end_time_ = 0; - - memset( &r, 0, sizeof r ); -} - -#define TIME (s_time + s.base) -#define READ_PROG( addr ) (mem [addr]) -#define INSTR( offset ) READ_PROG( pc + (offset) ) -#define GET_ADDR() GET_LE16( &READ_PROG( pc ) ) -#define READ( addr ) READ_PROG( addr ) -#define WRITE( addr, data ) (void) (READ_PROG( addr ) = data) -#define READ_WORD( addr ) GET_LE16( &READ_PROG( addr ) ) -#define WRITE_WORD( addr, data ) SET_LE16( &READ_PROG( addr ), data ) -#define IN( addr ) CPU_IN( this, addr, TIME ) -#define OUT( addr, data ) CPU_OUT( this, addr, data, TIME ) - -#if BLARGG_BIG_ENDIAN - #define R8( n, offset ) ((r8_ - offset) [n]) -#elif BLARGG_LITTLE_ENDIAN - #define R8( n, offset ) ((r8_ - offset) [(n) ^ 1]) -#else - #error "Byte order of CPU must be known" -#endif - -//#define R16( n, shift, offset ) (r16_ [((n) >> shift) - (offset >> shift)]) - -// help compiler see that it can just adjust stack offset, saving an extra instruction -#define R16( n, shift, offset )\ - (*(uint16_t*) ((char*) r16_ - (offset >> (shift - 1)) + ((n) >> (shift - 1)))) - -#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e -#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f -#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g -#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h - -// high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 -static byte const ed_dd_timing [0x100] = { -//0 1 2 3 4 5 6 7 8 9 A B C D E F -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, -0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, -0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, -0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, -0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, -0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, -0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, -0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, -}; - -bool Ay_Cpu::run( cpu_time_t end_time ) -{ - set_end_time( end_time ); - state_t s = this->state_; - this->state = &s; - bool warning = false; - - union { - regs_t rg; - pairs_t rp; - uint8_t r8_ [8]; // indexed - uint16_t r16_ [4]; - }; - rg = this->r.b; - - cpu_time_t s_time = s.time; - uint8_t* const mem = this->mem; // cache - uint16_t pc = r.pc; - uint16_t sp = r.sp; - uint16_t ix = r.ix; // TODO: keep in memory for direct access? - uint16_t iy = r.iy; - int flags = r.b.flags; - - goto loop; -jr_not_taken: - s_time -= 5; - goto loop; -call_not_taken: - s_time -= 7; -jp_not_taken: - pc += 2; -loop: - - check( (unsigned long) pc < 0x10000 ); - check( (unsigned long) sp < 0x10000 ); - check( (unsigned) flags < 0x100 ); - check( (unsigned) ix < 0x10000 ); - check( (unsigned) iy < 0x10000 ); - - uint8_t opcode; - opcode = READ_PROG( pc ); - pc++; - - static byte const base_timing [0x100] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 - 13,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 - 12,10,16, 6, 4, 4, 7, 4,12,11,16, 6, 4, 4, 7, 4, // 2 - 12,10,13, 6,11,11,10, 4,12,11,13, 6, 4, 4, 7, 4, // 3 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 - 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B - 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C - 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D - 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E - 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F - }; - - uint16_t data; - data = base_timing [opcode]; - if ( (s_time += data) >= 0 ) - goto possibly_out_of_time; -almost_out_of_time: - - data = READ_PROG( pc ); - - #ifdef Z80_CPU_LOG_H - //log_opcode( opcode, READ_PROG( pc ) ); - z80_log_regs( rg.a, rp.bc, rp.de, rp.hl, sp, ix, iy ); - z80_cpu_log( "new", pc - 1, opcode, READ_PROG( pc ), - READ_PROG( pc + 1 ), READ_PROG( pc + 2 ) ); - #endif - - switch ( opcode ) - { -possibly_out_of_time: - if ( s_time < (int) data ) - goto almost_out_of_time; - s_time -= data; - goto out_of_time; - -// Common - - case 0x00: // NOP - CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. - goto loop; - - case 0x08:{// EX AF,AF' - int temp = r.alt.b.a; - r.alt.b.a = rg.a; - rg.a = temp; - - temp = r.alt.b.flags; - r.alt.b.flags = flags; - flags = temp; - goto loop; - } - - case 0xD3: // OUT (imm),A - pc++; - OUT( data + rg.a * 0x100, rg.a ); - goto loop; - - case 0x2E: // LD L,imm - pc++; - rg.l = data; - goto loop; - - case 0x3E: // LD A,imm - pc++; - rg.a = data; - goto loop; - - case 0x3A:{// LD A,(addr) - uint16_t addr = GET_ADDR(); - pc += 2; - rg.a = READ( addr ); - goto loop; - } - -// Conditional - -#define ZERO (flags & Z40) -#define CARRY (flags & C01) -#define EVEN (flags & P04) -#define MINUS (flags & S80) - -// JR -#define JR( cond ) {\ - int disp = (int8_t) data;\ - pc++;\ - if ( !(cond) )\ - goto jr_not_taken;\ - pc += disp;\ - goto loop;\ -} - - case 0x20: JR( !ZERO ) // JR NZ,disp - case 0x28: JR( ZERO ) // JR Z,disp - case 0x30: JR( !CARRY ) // JR NC,disp - case 0x38: JR( CARRY ) // JR C,disp - case 0x18: JR( true ) // JR disp - - case 0x10:{// DJNZ disp - int temp = rg.b - 1; - rg.b = temp; - JR( temp ) - } - -// JP -#define JP( cond ) if ( !(cond) ) goto jp_not_taken; pc = GET_ADDR(); goto loop; - - case 0xC2: JP( !ZERO ) // JP NZ,addr - case 0xCA: JP( ZERO ) // JP Z,addr - case 0xD2: JP( !CARRY ) // JP NC,addr - case 0xDA: JP( CARRY ) // JP C,addr - case 0xE2: JP( !EVEN ) // JP PO,addr - case 0xEA: JP( EVEN ) // JP PE,addr - case 0xF2: JP( !MINUS ) // JP P,addr - case 0xFA: JP( MINUS ) // JP M,addr - - case 0xC3: // JP addr - pc = GET_ADDR(); - goto loop; - - case 0xE9: // JP HL - pc = rp.hl; - goto loop; - -// RET -#define RET( cond ) if ( cond ) goto ret_taken; s_time -= 6; goto loop; - - case 0xC0: RET( !ZERO ) // RET NZ - case 0xC8: RET( ZERO ) // RET Z - case 0xD0: RET( !CARRY ) // RET NC - case 0xD8: RET( CARRY ) // RET C - case 0xE0: RET( !EVEN ) // RET PO - case 0xE8: RET( EVEN ) // RET PE - case 0xF0: RET( !MINUS ) // RET P - case 0xF8: RET( MINUS ) // RET M - - case 0xC9: // RET - ret_taken: - pc = READ_WORD( sp ); - sp = uint16_t (sp + 2); - goto loop; - -// CALL -#define CALL( cond ) if ( cond ) goto call_taken; goto call_not_taken; - - case 0xC4: CALL( !ZERO ) // CALL NZ,addr - case 0xCC: CALL( ZERO ) // CALL Z,addr - case 0xD4: CALL( !CARRY ) // CALL NC,addr - case 0xDC: CALL( CARRY ) // CALL C,addr - case 0xE4: CALL( !EVEN ) // CALL PO,addr - case 0xEC: CALL( EVEN ) // CALL PE,addr - case 0xF4: CALL( !MINUS ) // CALL P,addr - case 0xFC: CALL( MINUS ) // CALL M,addr - - case 0xCD:{// CALL addr - call_taken: - uint16_t addr = pc + 2; - pc = GET_ADDR(); - sp = uint16_t (sp - 2); - WRITE_WORD( sp, addr ); - goto loop; - } - - case 0xFF: // RST - if ( (pc - 1) > 0xFFFF ) - { - pc = uint16_t (pc - 1); - s_time -= 11; - goto loop; - } - CASE7( C7, CF, D7, DF, E7, EF, F7 ): - data = pc; - pc = opcode & 0x38; - goto push_data; - -// PUSH/POP - case 0xF5: // PUSH AF - data = rg.a * 0x100u + flags; - goto push_data; - - case 0xC5: // PUSH BC - case 0xD5: // PUSH DE - case 0xE5: // PUSH HL - data = R16( opcode, 4, 0xC5 ); - push_data: - sp = uint16_t (sp - 2); - WRITE_WORD( sp, data ); - goto loop; - - case 0xF1: // POP AF - flags = READ( sp ); - rg.a = READ( sp + 1 ); - sp = uint16_t (sp + 2); - goto loop; - - case 0xC1: // POP BC - case 0xD1: // POP DE - case 0xE1: // POP HL - R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); - sp = uint16_t (sp + 2); - goto loop; - -// ADC/ADD/SBC/SUB - case 0x96: // SUB (HL) - case 0x86: // ADD (HL) - flags &= ~C01; - case 0x9E: // SBC (HL) - case 0x8E: // ADC (HL) - data = READ( rp.hl ); - goto adc_data; - - case 0xD6: // SUB A,imm - case 0xC6: // ADD imm - flags &= ~C01; - case 0xDE: // SBC A,imm - case 0xCE: // ADC imm - pc++; - goto adc_data; - - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r - flags &= ~C01; - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r - data = R8( opcode & 7, 0 ); - adc_data: { - int result = data + (flags & C01); - data ^= rg.a; - flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes - if ( flags ) - result = -result; - result += rg.a; - data ^= result; - flags |=(data & H10) | - ((data - -0x80) >> 6 & V04) | - SZ28C( result & 0x1FF ); - rg.a = result; - goto loop; - } - -// CP - case 0xBE: // CP (HL) - data = READ( rp.hl ); - goto cp_data; - - case 0xFE: // CP imm - pc++; - goto cp_data; - - CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r - data = R8( opcode, 0xB8 ); - cp_data: { - int result = rg.a - data; - flags = N02 | (data & (F20 | F08)) | (result >> 8 & C01); - data ^= rg.a; - flags |=(((result ^ rg.a) & data) >> 5 & V04) | - (((data & H10) ^ result) & (S80 | H10)); - if ( (uint8_t) result ) - goto loop; - flags |= Z40; - goto loop; - } - -// ADD HL,rp - - case 0x39: // ADD HL,SP - data = sp; - goto add_hl_data; - - case 0x09: // ADD HL,BC - case 0x19: // ADD HL,DE - case 0x29: // ADD HL,HL - data = R16( opcode, 4, 0x09 ); - add_hl_data: { - blargg_ulong sum = rp.hl + data; - data ^= rp.hl; - rp.hl = sum; - flags = (flags & (S80 | Z40 | V04)) | - (sum >> 16) | - (sum >> 8 & (F20 | F08)) | - ((data ^ sum) >> 8 & H10); - goto loop; - } - - case 0x27:{// DAA - int a = rg.a; - if ( a > 0x99 ) - flags |= C01; - - int adjust = 0x60 & -(flags & C01); - - if ( flags & H10 || (a & 0x0F) > 9 ) - adjust |= 0x06; - - if ( flags & N02 ) - adjust = -adjust; - a += adjust; - - flags = (flags & (C01 | N02)) | - ((rg.a ^ a) & H10) | - SZ28P( (uint8_t) a ); - rg.a = a; - goto loop; - } - /* - case 0x27:{// DAA - // more optimized, but probably not worth the obscurity - int f = (rg.a + (0xFF - 0x99)) >> 8 | flags; // (a > 0x99 ? C01 : 0) | flags - int adjust = 0x60 & -(f & C01); // f & C01 ? 0x60 : 0 - - if ( (((rg.a + (0x0F - 9)) ^ rg.a) | f) & H10 ) // flags & H10 || (rg.a & 0x0F) > 9 - adjust |= 0x06; - - if ( f & N02 ) - adjust = -adjust; - int a = rg.a + adjust; - - flags = (f & (N02 | C01)) | ((rg.a ^ a) & H10) | SZ28P( (uint8_t) a ); - rg.a = a; - goto loop; - } - */ - -// INC/DEC - case 0x34: // INC (HL) - data = READ( rp.hl ) + 1; - WRITE( rp.hl, data ); - goto inc_set_flags; - - CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r - data = ++R8( opcode >> 3, 0 ); - inc_set_flags: - flags = (flags & C01) | - (((data & 0x0F) - 1) & H10) | - SZ28( (uint8_t) data ); - if ( data != 0x80 ) - goto loop; - flags |= V04; - goto loop; - - case 0x35: // DEC (HL) - data = READ( rp.hl ) - 1; - WRITE( rp.hl, data ); - goto dec_set_flags; - - CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r - data = --R8( opcode >> 3, 0 ); - dec_set_flags: - flags = (flags & C01) | N02 | - (((data & 0x0F) + 1) & H10) | - SZ28( (uint8_t) data ); - if ( data != 0x7F ) - goto loop; - flags |= V04; - goto loop; - - case 0x03: // INC BC - case 0x13: // INC DE - case 0x23: // INC HL - R16( opcode, 4, 0x03 )++; - goto loop; - - case 0x33: // INC SP - sp = uint16_t (sp + 1); - goto loop; - - case 0x0B: // DEC BC - case 0x1B: // DEC DE - case 0x2B: // DEC HL - R16( opcode, 4, 0x0B )--; - goto loop; - - case 0x3B: // DEC SP - sp = uint16_t (sp - 1); - goto loop; - -// AND - case 0xA6: // AND (HL) - data = READ( rp.hl ); - goto and_data; - - case 0xE6: // AND imm - pc++; - goto and_data; - - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r - data = R8( opcode, 0xA0 ); - and_data: - rg.a &= data; - flags = SZ28P( rg.a ) | H10; - goto loop; - -// OR - case 0xB6: // OR (HL) - data = READ( rp.hl ); - goto or_data; - - case 0xF6: // OR imm - pc++; - goto or_data; - - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r - data = R8( opcode, 0xB0 ); - or_data: - rg.a |= data; - flags = SZ28P( rg.a ); - goto loop; - -// XOR - case 0xAE: // XOR (HL) - data = READ( rp.hl ); - goto xor_data; - - case 0xEE: // XOR imm - pc++; - goto xor_data; - - CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r - data = R8( opcode, 0xA8 ); - xor_data: - rg.a ^= data; - flags = SZ28P( rg.a ); - goto loop; - -// LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r - WRITE( rp.hl, R8( opcode, 0x70 ) ); - goto loop; - - CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r - CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r - CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r - CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r - CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r - CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r - CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r - R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); - goto loop; - - CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm - R8( opcode >> 3, 0 ) = data; - pc++; - goto loop; - - case 0x36: // LD (HL),imm - pc++; - WRITE( rp.hl, data ); - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) - R8( opcode >> 3, 8 ) = READ( rp.hl ); - goto loop; - - case 0x01: // LD rp,imm - case 0x11: - case 0x21: - R16( opcode, 4, 0x01 ) = GET_ADDR(); - pc += 2; - goto loop; - - case 0x31: // LD sp,imm - sp = GET_ADDR(); - pc += 2; - goto loop; - - case 0x2A:{// LD HL,(addr) - uint16_t addr = GET_ADDR(); - pc += 2; - rp.hl = READ_WORD( addr ); - goto loop; - } - - case 0x32:{// LD (addr),A - uint16_t addr = GET_ADDR(); - pc += 2; - WRITE( addr, rg.a ); - goto loop; - } - - case 0x22:{// LD (addr),HL - uint16_t addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, rp.hl ); - goto loop; - } - - case 0x02: // LD (BC),A - case 0x12: // LD (DE),A - WRITE( R16( opcode, 4, 0x02 ), rg.a ); - goto loop; - - case 0x0A: // LD A,(BC) - case 0x1A: // LD A,(DE) - rg.a = READ( R16( opcode, 4, 0x0A ) ); - goto loop; - - case 0xF9: // LD SP,HL - sp = rp.hl; - goto loop; - -// Rotate - - case 0x07:{// RLCA - uint16_t temp = rg.a; - temp = (temp << 1) | (temp >> 7); - flags = (flags & (S80 | Z40 | P04)) | - (temp & (F20 | F08 | C01)); - rg.a = temp; - goto loop; - } - - case 0x0F:{// RRCA - uint16_t temp = rg.a; - flags = (flags & (S80 | Z40 | P04)) | - (temp & C01); - temp = (temp << 7) | (temp >> 1); - flags |= temp & (F20 | F08); - rg.a = temp; - goto loop; - } - - case 0x17:{// RLA - blargg_ulong temp = (rg.a << 1) | (flags & C01); - flags = (flags & (S80 | Z40 | P04)) | - (temp & (F20 | F08)) | - (temp >> 8); - rg.a = temp; - goto loop; - } - - case 0x1F:{// RRA - uint16_t temp = (flags << 7) | (rg.a >> 1); - flags = (flags & (S80 | Z40 | P04)) | - (temp & (F20 | F08)) | - (rg.a & C01); - rg.a = temp; - goto loop; - } - -// Misc - case 0x2F:{// CPL - uint16_t temp = ~rg.a; - flags = (flags & (S80 | Z40 | P04 | C01)) | - (temp & (F20 | F08)) | - (H10 | N02); - rg.a = temp; - goto loop; - } - - case 0x3F:{// CCF - flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) | - (flags << 4 & H10) | - (rg.a & (F20 | F08)); - goto loop; - } - - case 0x37: // SCF - flags = (flags & (S80 | Z40 | P04)) | C01 | - (rg.a & (F20 | F08)); - goto loop; - - case 0xDB: // IN A,(imm) - pc++; - rg.a = IN( data + rg.a * 0x100 ); - goto loop; - - case 0xE3:{// EX (SP),HL - uint16_t temp = READ_WORD( sp ); - WRITE_WORD( sp, rp.hl ); - rp.hl = temp; - goto loop; - } - - case 0xEB:{// EX DE,HL - uint16_t temp = rp.hl; - rp.hl = rp.de; - rp.de = temp; - goto loop; - } - - case 0xD9:{// EXX DE,HL - uint16_t temp = r.alt.w.bc; - r.alt.w.bc = rp.bc; - rp.bc = temp; - - temp = r.alt.w.de; - r.alt.w.de = rp.de; - rp.de = temp; - - temp = r.alt.w.hl; - r.alt.w.hl = rp.hl; - rp.hl = temp; - goto loop; - } - - case 0xF3: // DI - r.iff1 = 0; - r.iff2 = 0; - goto loop; - - case 0xFB: // EI - r.iff1 = 1; - r.iff2 = 1; - // TODO: delayed effect - goto loop; - - case 0x76: // HALT - goto halt; - -//////////////////////////////////////// CB prefix - { - case 0xCB: - unsigned data2; - data2 = INSTR( 1 ); - (void) data2; // TODO is this the same as data in all cases? - pc++; - switch ( data ) - { - - // Rotate left - - #define RLC( read, write ) {\ - uint8_t result = read;\ - result = uint8_t (result << 1) | (result >> 7);\ - flags = SZ28P( result ) | (result & C01);\ - write;\ - goto loop;\ - } - - case 0x06: // RLC (HL) - s_time += 7; - data = rp.hl; - rlc_data_addr: - RLC( READ( data ), WRITE( data, result ) ) - - CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r - uint8_t& reg = R8( data, 0 ); - RLC( reg, reg = result ) - } - - #define RL( read, write ) {\ - uint16_t result = (read << 1) | (flags & C01);\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x16: // RL (HL) - s_time += 7; - data = rp.hl; - rl_data_addr: - RL( READ( data ), WRITE( data, result ) ) - - CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r - uint8_t& reg = R8( data, 0x10 ); - RL( reg, reg = result ) - } - - #define SLA( read, add, write ) {\ - uint16_t result = (read << 1) | add;\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x26: // SLA (HL) - s_time += 7; - data = rp.hl; - sla_data_addr: - SLA( READ( data ), 0, WRITE( data, result ) ) - - CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r - uint8_t& reg = R8( data, 0x20 ); - SLA( reg, 0, reg = result ) - } - - case 0x36: // SLL (HL) - s_time += 7; - data = rp.hl; - sll_data_addr: - SLA( READ( data ), 1, WRITE( data, result ) ) - - CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r - uint8_t& reg = R8( data, 0x30 ); - SLA( reg, 1, reg = result ) - } - - // Rotate right - - #define RRC( read, write ) {\ - uint8_t result = read;\ - flags = result & C01;\ - result = uint8_t (result << 7) | (result >> 1);\ - flags |= SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x0E: // RRC (HL) - s_time += 7; - data = rp.hl; - rrc_data_addr: - RRC( READ( data ), WRITE( data, result ) ) - - CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r - uint8_t& reg = R8( data, 0x08 ); - RRC( reg, reg = result ) - } - - #define RR( read, write ) {\ - uint8_t result = read;\ - uint8_t temp = result & C01;\ - result = uint8_t (flags << 7) | (result >> 1);\ - flags = SZ28P( result ) | temp;\ - write;\ - goto loop;\ - } - - case 0x1E: // RR (HL) - s_time += 7; - data = rp.hl; - rr_data_addr: - RR( READ( data ), WRITE( data, result ) ) - - CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r - uint8_t& reg = R8( data, 0x18 ); - RR( reg, reg = result ) - } - - #define SRA( read, write ) {\ - uint8_t result = read;\ - flags = result & C01;\ - result = (result & 0x80) | (result >> 1);\ - flags |= SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x2E: // SRA (HL) - data = rp.hl; - s_time += 7; - sra_data_addr: - SRA( READ( data ), WRITE( data, result ) ) - - CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r - uint8_t& reg = R8( data, 0x28 ); - SRA( reg, reg = result ) - } - - #define SRL( read, write ) {\ - uint8_t result = read;\ - flags = result & C01;\ - result >>= 1;\ - flags |= SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x3E: // SRL (HL) - s_time += 7; - data = rp.hl; - srl_data_addr: - SRL( READ( data ), WRITE( data, result ) ) - - CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r - uint8_t& reg = R8( data, 0x38 ); - SRL( reg, reg = result ) - } - - // BIT - { - unsigned temp; - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) - s_time += 4; - temp = READ( rp.hl ); - flags &= C01; - goto bit_temp; - CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r - CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r - CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r - CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r - CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r - CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r - CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r - temp = R8( data & 7, 0 ); - flags = (flags & C01) | (temp & (F20 | F08)); - bit_temp: - int masked = temp & 1 << (data >> 3 & 7); - flags |=(masked & S80) | H10 | - ((masked - 1) >> 8 & (Z40 | P04)); - goto loop; - } - - // SET/RES - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) - s_time += 7; - int temp = READ( rp.hl ); - int bit = 1 << (data >> 3 & 7); - temp |= bit; // SET - if ( !(data & 0x40) ) - temp ^= bit; // RES - WRITE( rp.hl, temp ); - goto loop; - } - - CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r - CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r - CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r - CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r - CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r - CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r - CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r - CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r - R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); - goto loop; - - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r - CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r - CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r - R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); - goto loop; - } - assert( false ); - } - -//////////////////////////////////////// ED prefix - { - case 0xED: - pc++; - s_time += ed_dd_timing [data] >> 4; - switch ( data ) - { - { - blargg_ulong temp; - case 0x72: // SBC HL,SP - case 0x7A: // ADC HL,SP - temp = sp; - if ( 0 ) - case 0x42: // SBC HL,BC - case 0x52: // SBC HL,DE - case 0x62: // SBC HL,HL - case 0x4A: // ADC HL,BC - case 0x5A: // ADC HL,DE - case 0x6A: // ADC HL,HL - temp = R16( data >> 3 & 6, 1, 0 ); - blargg_ulong sum = temp + (flags & C01); - flags = ~data >> 2 & N02; - if ( flags ) - sum = -sum; - sum += rp.hl; - temp ^= rp.hl; - temp ^= sum; - flags |=(sum >> 16 & C01) | - (temp >> 8 & H10) | - (sum >> 8 & (S80 | F20 | F08)) | - ((temp - -0x8000) >> 14 & V04); - rp.hl = sum; - if ( (uint16_t) sum ) - goto loop; - flags |= Z40; - goto loop; - } - - CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) - int temp = IN( rp.bc ); - R8( data >> 3, 8 ) = temp; - flags = (flags & C01) | SZ28P( temp ); - goto loop; - } - - case 0x71: // OUT (C),0 - rg.flags = 0; - CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r - OUT( rp.bc, R8( data >> 3, 8 ) ); - goto loop; - - { - unsigned temp; - case 0x73: // LD (ADDR),SP - temp = sp; - if ( 0 ) - case 0x43: // LD (ADDR),BC - case 0x53: // LD (ADDR),DE - temp = R16( data, 4, 0x43 ); - uint16_t addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, temp ); - goto loop; - } - - case 0x4B: // LD BC,(ADDR) - case 0x5B:{// LD DE,(ADDR) - uint16_t addr = GET_ADDR(); - pc += 2; - R16( data, 4, 0x4B ) = READ_WORD( addr ); - goto loop; - } - - case 0x7B:{// LD SP,(ADDR) - uint16_t addr = GET_ADDR(); - pc += 2; - sp = READ_WORD( addr ); - goto loop; - } - - case 0x67:{// RRD - uint8_t temp = READ( rp.hl ); - WRITE( rp.hl, (rg.a << 4) | (temp >> 4) ); - temp = (rg.a & 0xF0) | (temp & 0x0F); - flags = (flags & C01) | SZ28P( temp ); - rg.a = temp; - goto loop; - } - - case 0x6F:{// RLD - uint8_t temp = READ( rp.hl ); - WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) ); - temp = (rg.a & 0xF0) | (temp >> 4); - flags = (flags & C01) | SZ28P( temp ); - rg.a = temp; - goto loop; - } - - CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG - opcode = 0x10; // flag to do SBC instead of ADC - flags &= ~C01; - data = rg.a; - rg.a = 0; - goto adc_data; - - { - int inc; - case 0xA9: // CPD - case 0xB9: // CPDR - inc = -1; - if ( 0 ) - case 0xA1: // CPI - case 0xB1: // CPIR - inc = +1; - uint16_t addr = rp.hl; - rp.hl = addr + inc; - int temp = READ( addr ); - - int result = rg.a - temp; - flags = (flags & C01) | N02 | - ((((temp ^ rg.a) & H10) ^ result) & (S80 | H10)); - - if ( !(uint8_t) result ) flags |= Z40; - result -= (flags & H10) >> 4; - flags |= result & F08; - flags |= result << 4 & F20; - if ( !--rp.bc ) - goto loop; - - flags |= V04; - if ( flags & Z40 || data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xA8: // LDD - case 0xB8: // LDDR - inc = -1; - if ( 0 ) - case 0xA0: // LDI - case 0xB0: // LDIR - inc = +1; - uint16_t addr = rp.hl; - rp.hl = addr + inc; - int temp = READ( addr ); - - addr = rp.de; - rp.de = addr + inc; - WRITE( addr, temp ); - - temp += rg.a; - flags = (flags & (S80 | Z40 | C01)) | - (temp & F08) | (temp << 4 & F20); - if ( !--rp.bc ) - goto loop; - - flags |= V04; - if ( data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xAB: // OUTD - case 0xBB: // OTDR - inc = -1; - if ( 0 ) - case 0xA3: // OUTI - case 0xB3: // OTIR - inc = +1; - uint16_t addr = rp.hl; - rp.hl = addr + inc; - int temp = READ( addr ); - - int b = --rg.b; - flags = (temp >> 6 & N02) | SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - OUT( rp.bc, temp ); - goto loop; - } - - { - int inc; - case 0xAA: // IND - case 0xBA: // INDR - inc = -1; - if ( 0 ) - case 0xA2: // INI - case 0xB2: // INIR - inc = +1; - - uint16_t addr = rp.hl; - rp.hl = addr + inc; - - int temp = IN( rp.bc ); - - int b = --rg.b; - flags = (temp >> 6 & N02) | SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - WRITE( addr, temp ); - goto loop; - } - - case 0x47: // LD I,A - r.i = rg.a; - goto loop; - - case 0x4F: // LD R,A - SET_R( rg.a ); - debug_printf( "LD R,A not supported\n" ); - warning = true; - goto loop; - - case 0x57: // LD A,I - rg.a = r.i; - goto ld_ai_common; - - case 0x5F: // LD A,R - rg.a = GET_R(); - debug_printf( "LD A,R not supported\n" ); - warning = true; - ld_ai_common: - flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04); - goto loop; - - CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN - r.iff1 = r.iff2; - goto ret_taken; - - case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 - r.im = 0; - goto loop; - - case 0x56: case 0x76: // IM 1 - r.im = 1; - goto loop; - - case 0x5E: case 0x7E: // IM 2 - r.im = 2; - goto loop; - - default: - debug_printf( "Opcode $ED $%02X not supported\n", data ); - warning = true; - goto loop; - } - assert( false ); - } - -//////////////////////////////////////// DD/FD prefix - { - uint16_t ixy; - case 0xDD: - ixy = ix; - goto ix_prefix; - case 0xFD: - ixy = iy; - ix_prefix: - pc++; - unsigned data2 = READ_PROG( pc ); - s_time += ed_dd_timing [data] & 0x0F; - switch ( data ) - { - // TODO: more efficient way of avoid negative address - #define IXY_DISP( ixy, disp ) uint16_t ((ixy) + (disp)) - - #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; - - // ADD/ADC/SUB/SBC - - case 0x96: // SUB (IXY+disp) - case 0x86: // ADD (IXY+disp) - flags &= ~C01; - case 0x9E: // SBC (IXY+disp) - case 0x8E: // ADC (IXY+disp) - pc++; - opcode = data; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto adc_data; - - case 0x94: // SUB HXY - case 0x84: // ADD HXY - flags &= ~C01; - case 0x9C: // SBC HXY - case 0x8C: // ADC HXY - opcode = data; - data = ixy >> 8; - goto adc_data; - - case 0x95: // SUB LXY - case 0x85: // ADD LXY - flags &= ~C01; - case 0x9D: // SBC LXY - case 0x8D: // ADC LXY - opcode = data; - data = (uint8_t) ixy; - goto adc_data; - - { - unsigned temp; - case 0x39: // ADD IXY,SP - temp = sp; - goto add_ixy_data; - - case 0x29: // ADD IXY,HL - temp = ixy; - goto add_ixy_data; - - case 0x09: // ADD IXY,BC - case 0x19: // ADD IXY,DE - temp = R16( data, 4, 0x09 ); - add_ixy_data: { - blargg_ulong sum = ixy + temp; - temp ^= ixy; - ixy = (uint16_t) sum; - flags = (flags & (S80 | Z40 | V04)) | - (sum >> 16) | - (sum >> 8 & (F20 | F08)) | - ((temp ^ sum) >> 8 & H10); - goto set_ixy; - } - } - - // AND - case 0xA6: // AND (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto and_data; - - case 0xA4: // AND HXY - data = ixy >> 8; - goto and_data; - - case 0xA5: // AND LXY - data = (uint8_t) ixy; - goto and_data; - - // OR - case 0xB6: // OR (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto or_data; - - case 0xB4: // OR HXY - data = ixy >> 8; - goto or_data; - - case 0xB5: // OR LXY - data = (uint8_t) ixy; - goto or_data; - - // XOR - case 0xAE: // XOR (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto xor_data; - - case 0xAC: // XOR HXY - data = ixy >> 8; - goto xor_data; - - case 0xAD: // XOR LXY - data = (uint8_t) ixy; - goto xor_data; - - // CP - case 0xBE: // CP (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto cp_data; - - case 0xBC: // CP HXY - data = ixy >> 8; - goto cp_data; - - case 0xBD: // CP LXY - data = (uint8_t) ixy; - goto cp_data; - - // LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r - data = R8( data, 0x70 ); - if ( 0 ) - case 0x36: // LD (IXY+disp),imm - pc++, data = READ_PROG( pc ); - pc++; - WRITE( IXY_DISP( ixy, (int8_t) data2 ), data ); - goto loop; - - CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY - R8( data >> 3, 8 ) = ixy >> 8; - goto loop; - - case 0x64: // LD HXY,HXY - case 0x6D: // LD LXY,LXY - goto loop; - - CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY - R8( data >> 3, 8 ) = ixy; - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) - pc++; - R8( data >> 3, 8 ) = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto loop; - - case 0x26: // LD HXY,imm - pc++; - goto ld_hxy_data; - - case 0x65: // LD HXY,LXY - data2 = (uint8_t) ixy; - goto ld_hxy_data; - - CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r - data2 = R8( data, 0x60 ); - ld_hxy_data: - ixy = (uint8_t) ixy | (data2 << 8); - goto set_ixy; - - case 0x2E: // LD LXY,imm - pc++; - goto ld_lxy_data; - - case 0x6C: // LD LXY,HXY - data2 = ixy >> 8; - goto ld_lxy_data; - - CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r - data2 = R8( data, 0x68 ); - ld_lxy_data: - ixy = (ixy & 0xFF00) | data2; - set_ixy: - if ( opcode == 0xDD ) - { - ix = ixy; - goto loop; - } - iy = ixy; - goto loop; - - case 0xF9: // LD SP,IXY - sp = ixy; - goto loop; - - case 0x22:{// LD (ADDR),IXY - uint16_t addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, ixy ); - goto loop; - } - - case 0x21: // LD IXY,imm - ixy = GET_ADDR(); - pc += 2; - goto set_ixy; - - case 0x2A:{// LD IXY,(addr) - uint16_t addr = GET_ADDR(); - ixy = READ_WORD( addr ); - pc += 2; - goto set_ixy; - } - - // DD/FD CB prefix - case 0xCB: { - data = IXY_DISP( ixy, (int8_t) data2 ); - pc++; - data2 = READ_PROG( pc ); - pc++; - switch ( data2 ) - { - case 0x06: goto rlc_data_addr; // RLC (IXY) - case 0x16: goto rl_data_addr; // RL (IXY) - case 0x26: goto sla_data_addr; // SLA (IXY) - case 0x36: goto sll_data_addr; // SLL (IXY) - case 0x0E: goto rrc_data_addr; // RRC (IXY) - case 0x1E: goto rr_data_addr; // RR (IXY) - case 0x2E: goto sra_data_addr; // SRA (IXY) - case 0x3E: goto srl_data_addr; // SRL (IXY) - - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) - uint8_t temp = READ( data ); - int masked = temp & 1 << (data2 >> 3 & 7); - flags = (flags & C01) | H10 | - (masked & S80) | - ((masked - 1) >> 8 & (Z40 | P04)); - goto loop; - } - - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) - int temp = READ( data ); - int bit = 1 << (data2 >> 3 & 7); - temp |= bit; // SET - if ( !(data2 & 0x40) ) - temp ^= bit; // RES - WRITE( data, temp ); - goto loop; - } - - default: - debug_printf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); - warning = true; - goto loop; - } - assert( false ); - } - - // INC/DEC - case 0x23: // INC IXY - ixy = uint16_t (ixy + 1); - goto set_ixy; - - case 0x2B: // DEC IXY - ixy = uint16_t (ixy - 1); - goto set_ixy; - - case 0x34: // INC (IXY+disp) - ixy = IXY_DISP( ixy, (int8_t) data2 ); - pc++; - data = READ( ixy ) + 1; - WRITE( ixy, data ); - goto inc_set_flags; - - case 0x35: // DEC (IXY+disp) - ixy = IXY_DISP( ixy, (int8_t) data2 ); - pc++; - data = READ( ixy ) - 1; - WRITE( ixy, data ); - goto dec_set_flags; - - case 0x24: // INC HXY - ixy = uint16_t (ixy + 0x100); - data = ixy >> 8; - goto inc_xy_common; - - case 0x2C: // INC LXY - data = uint8_t (ixy + 1); - ixy = (ixy & 0xFF00) | data; - inc_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto inc_set_flags; - } - iy = ixy; - goto inc_set_flags; - - case 0x25: // DEC HXY - ixy = uint16_t (ixy - 0x100); - data = ixy >> 8; - goto dec_xy_common; - - case 0x2D: // DEC LXY - data = uint8_t (ixy - 1); - ixy = (ixy & 0xFF00) | data; - dec_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto dec_set_flags; - } - iy = ixy; - goto dec_set_flags; - - // PUSH/POP - case 0xE5: // PUSH IXY - data = ixy; - goto push_data; - - case 0xE1:{// POP IXY - ixy = READ_WORD( sp ); - sp = uint16_t (sp + 2); - goto set_ixy; - } - - // Misc - - case 0xE9: // JP (IXY) - pc = ixy; - goto loop; - - case 0xE3:{// EX (SP),IXY - uint16_t temp = READ_WORD( sp ); - WRITE_WORD( sp, ixy ); - ixy = temp; - goto set_ixy; - } - - default: - debug_printf( "Unnecessary DD/FD prefix encountered\n" ); - warning = true; - pc--; - goto loop; - } - assert( false ); - } - - } - debug_printf( "Unhandled main opcode: $%02X\n", opcode ); - assert( false ); - -halt: - s_time &= 3; // increment by multiple of 4 -out_of_time: - pc--; - - s.time = s_time; - rg.flags = flags; - r.ix = ix; - r.iy = iy; - r.sp = sp; - r.pc = pc; - this->r.b = rg; - this->state_ = s; - this->state = &this->state_; - - return warning; -} diff --git a/libraries/game-music-emu/gme/Ay_Cpu.h b/libraries/game-music-emu/gme/Ay_Cpu.h deleted file mode 100644 index 6984b42dc..000000000 --- a/libraries/game-music-emu/gme/Ay_Cpu.h +++ /dev/null @@ -1,89 +0,0 @@ -// Z80 CPU emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef AY_CPU_H -#define AY_CPU_H - -#include "blargg_endian.h" - -typedef blargg_long cpu_time_t; - -// must be defined by caller -void ay_cpu_out( class Ay_Cpu*, cpu_time_t, unsigned addr, int data ); -int ay_cpu_in( class Ay_Cpu*, unsigned addr ); - -class Ay_Cpu { -public: - // Clear all registers and keep pointer to 64K memory passed in - void reset( void* mem_64k ); - - // Run until specified time is reached. Returns true if suspicious/unsupported - // instruction was encountered at any point during run. - bool run( cpu_time_t end_time ); - - // Time of beginning of next instruction - cpu_time_t time() const { return state->time + state->base; } - - // Alter current time. Not supported during run() call. - void set_time( cpu_time_t t ) { state->time = t - state->base; } - void adjust_time( int delta ) { state->time += delta; } - - #if BLARGG_BIG_ENDIAN - struct regs_t { uint8_t b, c, d, e, h, l, flags, a; }; - #else - struct regs_t { uint8_t c, b, e, d, l, h, a, flags; }; - #endif - BOOST_STATIC_ASSERT( sizeof (regs_t) == 8 ); - - struct pairs_t { uint16_t bc, de, hl, fa; }; - - // Registers are not updated until run() returns - struct registers_t { - uint16_t pc; - uint16_t sp; - uint16_t ix; - uint16_t iy; - union { - regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a - pairs_t w; // w.bc, w.de, w.hl. w.fa - }; - union { - regs_t b; - pairs_t w; - } alt; - uint8_t iff1; - uint8_t iff2; - uint8_t r; - uint8_t i; - uint8_t im; - }; - //registers_t r; (below for efficiency) - - // can read this far past end of memory - enum { cpu_padding = 0x100 }; - -public: - Ay_Cpu(); -private: - uint8_t szpc [0x200]; - uint8_t* mem; - cpu_time_t end_time_; - struct state_t { - cpu_time_t base; - cpu_time_t time; - }; - state_t* state; // points to state_ or a local copy within run() - state_t state_; - void set_end_time( cpu_time_t t ); -public: - registers_t r; -}; - -inline void Ay_Cpu::set_end_time( cpu_time_t t ) -{ - cpu_time_t delta = state->base - t; - state->base = t; - state->time += delta; -} - -#endif diff --git a/libraries/game-music-emu/gme/Ay_Emu.cpp b/libraries/game-music-emu/gme/Ay_Emu.cpp deleted file mode 100644 index a973ba0f1..000000000 --- a/libraries/game-music-emu/gme/Ay_Emu.cpp +++ /dev/null @@ -1,405 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Ay_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -long const spectrum_clock = 3546900; -long const cpc_clock = 2000000; - -unsigned const ram_start = 0x4000; -int const osc_count = Ay_Apu::osc_count + 1; - -Ay_Emu::Ay_Emu() -{ - beeper_output = 0; - set_type( gme_ay_type ); - - static const char* const names [osc_count] = { - "Wave 1", "Wave 2", "Wave 3", "Beeper" - }; - set_voice_names( names ); - - static int const types [osc_count] = { - wave_type | 0, wave_type | 1, wave_type | 2, mixed_type | 0 - }; - set_voice_types( types ); - set_silence_lookahead( 6 ); -} - -Ay_Emu::~Ay_Emu() { } - -// Track info - -static byte const* get_data( Ay_Emu::file_t const& file, byte const* ptr, int min_size ) -{ - long pos = ptr - (byte const*) file.header; - long file_size = file.end - (byte const*) file.header; - assert( (unsigned long) pos <= (unsigned long) file_size - 2 ); - int offset = (int16_t) get_be16( ptr ); - if ( !offset || blargg_ulong (pos + offset) > blargg_ulong (file_size - min_size) ) - return 0; - return ptr + offset; -} - -static blargg_err_t parse_header( byte const* in, long size, Ay_Emu::file_t* out ) -{ - typedef Ay_Emu::header_t header_t; - out->header = (header_t const*) in; - out->end = in + size; - - if ( size < Ay_Emu::header_size ) - return gme_wrong_file_type; - - header_t const& h = *(header_t const*) in; - if ( memcmp( h.tag, "ZXAYEMUL", 8 ) ) - return gme_wrong_file_type; - - out->tracks = get_data( *out, h.track_info, (h.max_track + 1) * 4 ); - if ( !out->tracks ) - return "Missing track data"; - - return 0; -} - -static void copy_ay_fields( Ay_Emu::file_t const& file, track_info_t* out, int track ) -{ - Gme_File::copy_field_( out->song, (char const*) get_data( file, file.tracks + track * 4, 1 ) ); - byte const* track_info = get_data( file, file.tracks + track * 4 + 2, 6 ); - if ( track_info ) - out->length = get_be16( track_info + 4 ) * (1000L / 50); // frames to msec - - Gme_File::copy_field_( out->author, (char const*) get_data( file, file.header->author, 1 ) ); - Gme_File::copy_field_( out->comment, (char const*) get_data( file, file.header->comment, 1 ) ); -} - -blargg_err_t Ay_Emu::track_info_( track_info_t* out, int track ) const -{ - copy_ay_fields( file, out, track ); - return 0; -} - -struct Ay_File : Gme_Info_ -{ - Ay_Emu::file_t file; - - Ay_File() { set_type( gme_ay_type ); } - - blargg_err_t load_mem_( byte const* begin, long size ) - { - RETURN_ERR( parse_header( begin, size, &file ) ); - set_track_count( file.header->max_track + 1 ); - return 0; - } - - blargg_err_t track_info_( track_info_t* out, int track ) const - { - copy_ay_fields( file, out, track ); - return 0; - } -}; - -static Music_Emu* new_ay_emu () { return BLARGG_NEW Ay_Emu ; } -static Music_Emu* new_ay_file() { return BLARGG_NEW Ay_File; } - -static gme_type_t_ const gme_ay_type_ = { "ZX Spectrum", 0, &new_ay_emu, &new_ay_file, "AY", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_ay_type = &gme_ay_type_; - -// Setup - -blargg_err_t Ay_Emu::load_mem_( byte const* in, long size ) -{ - assert( offsetof (header_t,track_info [2]) == header_size ); - - RETURN_ERR( parse_header( in, size, &file ) ); - set_track_count( file.header->max_track + 1 ); - - if ( file.header->vers > 2 ) - set_warning( "Unknown file version" ); - - set_voice_count( osc_count ); - apu.volume( gain() ); - - return setup_buffer( spectrum_clock ); -} - -void Ay_Emu::update_eq( blip_eq_t const& eq ) -{ - apu.treble_eq( eq ); -} - -void Ay_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer*, Blip_Buffer* ) -{ - if ( i >= Ay_Apu::osc_count ) - beeper_output = center; - else - apu.osc_output( i, center ); -} - -// Emulation - -void Ay_Emu::set_tempo_( double t ) -{ - play_period = blip_time_t (clock_rate() / 50 / t); -} - -blargg_err_t Ay_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - memset( mem.ram + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET - memset( mem.ram + 0x0100, 0xFF, 0x4000 - 0x100 ); - memset( mem.ram + ram_start, 0x00, sizeof mem.ram - ram_start ); - memset( mem.padding1, 0xFF, sizeof mem.padding1 ); - memset( mem.ram + 0x10000, 0xFF, sizeof mem.ram - 0x10000 ); - - // locate data blocks - byte const* const data = get_data( file, file.tracks + track * 4 + 2, 14 ); - if ( !data ) return "File data missing"; - - byte const* const more_data = get_data( file, data + 10, 6 ); - if ( !more_data ) return "File data missing"; - - byte const* blocks = get_data( file, data + 12, 8 ); - if ( !blocks ) return "File data missing"; - - // initial addresses - cpu::reset( mem.ram ); - r.sp = get_be16( more_data ); - r.b.a = r.b.b = r.b.d = r.b.h = data [8]; - r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; - r.alt.w = r.w; - r.ix = r.iy = r.w.hl; - - unsigned addr = get_be16( blocks ); - if ( !addr ) return "File data missing"; - - unsigned init = get_be16( more_data + 2 ); - if ( !init ) - init = addr; - - // copy blocks into memory - do - { - blocks += 2; - unsigned len = get_be16( blocks ); blocks += 2; - if ( addr + len > 0x10000 ) - { - set_warning( "Bad data block size" ); - len = 0x10000 - addr; - } - check( len ); - byte const* in = get_data( file, blocks, 0 ); blocks += 2; - if ( len > blargg_ulong (file.end - in) ) - { - set_warning( "Missing file data" ); - len = file.end - in; - } - //debug_printf( "addr: $%04X, len: $%04X\n", addr, len ); - if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data - debug_printf( "Block addr in ROM\n" ); - memcpy( mem.ram + addr, in, len ); - - if ( file.end - blocks < 8 ) - { - set_warning( "Missing file data" ); - break; - } - } - while ( (addr = get_be16( blocks )) != 0 ); - - // copy and configure driver - static byte const passive [] = { - 0xF3, // DI - 0xCD, 0, 0, // CALL init - 0xED, 0x5E, // LOOP: IM 2 - 0xFB, // EI - 0x76, // HALT - 0x18, 0xFA // JR LOOP - }; - static byte const active [] = { - 0xF3, // DI - 0xCD, 0, 0, // CALL init - 0xED, 0x56, // LOOP: IM 1 - 0xFB, // EI - 0x76, // HALT - 0xCD, 0, 0, // CALL play - 0x18, 0xF7 // JR LOOP - }; - memcpy( mem.ram, passive, sizeof passive ); - unsigned play_addr = get_be16( more_data + 4 ); - //debug_printf( "Play: $%04X\n", play_addr ); - if ( play_addr ) - { - memcpy( mem.ram, active, sizeof active ); - mem.ram [ 9] = play_addr; - mem.ram [10] = play_addr >> 8; - } - mem.ram [2] = init; - mem.ram [3] = init >> 8; - - mem.ram [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) - - memcpy( mem.ram + 0x10000, mem.ram, 0x80 ); // some code wraps around (ugh) - - beeper_delta = int (apu.amp_range * 0.65); - last_beeper = 0; - apu.reset(); - next_play = play_period; - - // start at spectrum speed - change_clock_rate( spectrum_clock ); - set_tempo( tempo() ); - - spectrum_mode = false; - cpc_mode = false; - cpc_latch = 0; - - return 0; -} - -// Emulation - -void Ay_Emu::cpu_out_misc( cpu_time_t time, unsigned addr, int data ) -{ - if ( !cpc_mode ) - { - switch ( addr & 0xFEFF ) - { - case 0xFEFD: - spectrum_mode = true; - apu_addr = data & 0x0F; - return; - - case 0xBEFD: - spectrum_mode = true; - apu.write( time, apu_addr, data ); - return; - } - } - - if ( !spectrum_mode ) - { - switch ( addr >> 8 ) - { - case 0xF6: - switch ( data & 0xC0 ) - { - case 0xC0: - apu_addr = cpc_latch & 0x0F; - goto enable_cpc; - - case 0x80: - apu.write( time, apu_addr, cpc_latch ); - goto enable_cpc; - } - break; - - case 0xF4: - cpc_latch = data; - goto enable_cpc; - } - } - - debug_printf( "Unmapped OUT: $%04X <- $%02X\n", addr, data ); - return; - -enable_cpc: - if ( !cpc_mode ) - { - cpc_mode = true; - change_clock_rate( cpc_clock ); - set_tempo( tempo() ); - } -} - -void ay_cpu_out( Ay_Cpu* cpu, cpu_time_t time, unsigned addr, int data ) -{ - Ay_Emu& emu = STATIC_CAST(Ay_Emu&,*cpu); - - if ( (addr & 0xFF) == 0xFE && !emu.cpc_mode ) - { - int delta = emu.beeper_delta; - data &= 0x10; - if ( emu.last_beeper != data ) - { - emu.last_beeper = data; - emu.beeper_delta = -delta; - emu.spectrum_mode = true; - if ( emu.beeper_output ) - emu.apu.synth_.offset( time, delta, emu.beeper_output ); - } - } - else - { - emu.cpu_out_misc( time, addr, data ); - } -} - -int ay_cpu_in( Ay_Cpu*, unsigned addr ) -{ - // keyboard read and other things - if ( (addr & 0xFF) == 0xFE ) - return 0xFF; // other values break some beeper tunes - - debug_printf( "Unmapped IN : $%04X\n", addr ); - return 0xFF; -} - -blargg_err_t Ay_Emu::run_clocks( blip_time_t& duration, int ) -{ - set_time( 0 ); - if ( !(spectrum_mode | cpc_mode) ) - duration /= 2; // until mode is set, leave room for halved clock rate - - while ( time() < duration ) - { - cpu::run( min( duration, (blip_time_t) next_play ) ); - - if ( time() >= next_play ) - { - next_play += play_period; - - if ( r.iff1 ) - { - if ( mem.ram [r.pc] == 0x76 ) - r.pc++; - - r.iff1 = r.iff2 = 0; - - mem.ram [--r.sp] = uint8_t (r.pc >> 8); - mem.ram [--r.sp] = uint8_t (r.pc); - r.pc = 0x38; - cpu::adjust_time( 12 ); - if ( r.im == 2 ) - { - cpu::adjust_time( 6 ); - unsigned addr = r.i * 0x100u + 0xFF; - r.pc = mem.ram [(addr + 1) & 0xFFFF] * 0x100u + mem.ram [addr]; - } - } - } - } - duration = time(); - next_play -= duration; - check( next_play >= 0 ); - adjust_time( -duration ); - - apu.end_frame( duration ); - - return 0; -} diff --git a/libraries/game-music-emu/gme/Ay_Emu.h b/libraries/game-music-emu/gme/Ay_Emu.h deleted file mode 100644 index 6726f0157..000000000 --- a/libraries/game-music-emu/gme/Ay_Emu.h +++ /dev/null @@ -1,69 +0,0 @@ -// Sinclair Spectrum AY music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef AY_EMU_H -#define AY_EMU_H - -#include "Classic_Emu.h" -#include "Ay_Apu.h" -#include "Ay_Cpu.h" - -class Ay_Emu : private Ay_Cpu, public Classic_Emu { - typedef Ay_Cpu cpu; -public: - // AY file header - enum { header_size = 0x14 }; - struct header_t - { - byte tag [8]; - byte vers; - byte player; - byte unused [2]; - byte author [2]; - byte comment [2]; - byte max_track; - byte first_track; - byte track_info [2]; - }; - - static gme_type_t static_type() { return gme_ay_type; } -public: - Ay_Emu(); - ~Ay_Emu(); - struct file_t { - header_t const* header; - byte const* end; - byte const* tracks; - }; -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_mem_( byte const*, long ); - blargg_err_t start_track_( int ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); -private: - file_t file; - - cpu_time_t play_period; - cpu_time_t next_play; - Blip_Buffer* beeper_output; - int beeper_delta; - int last_beeper; - int apu_addr; - int cpc_latch; - bool spectrum_mode; - bool cpc_mode; - - // large items - struct { - byte padding1 [0x100]; - byte ram [0x10000 + 0x100]; - } mem; - Ay_Apu apu; - friend void ay_cpu_out( Ay_Cpu*, cpu_time_t, unsigned addr, int data ); - void cpu_out_misc( cpu_time_t, unsigned addr, int data ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Blip_Buffer.cpp b/libraries/game-music-emu/gme/Blip_Buffer.cpp deleted file mode 100644 index 2b88cd4f8..000000000 --- a/libraries/game-music-emu/gme/Blip_Buffer.cpp +++ /dev/null @@ -1,460 +0,0 @@ -// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ - -#include "Blip_Buffer.h" - -#include -#include -#include -#include -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -int const silent_buf_size = 1; // size used for Silent_Blip_Buffer - -Blip_Buffer::Blip_Buffer() -{ - factor_ = (blip_ulong)-1 / 2; - offset_ = 0; - buffer_ = 0; - buffer_size_ = 0; - sample_rate_ = 0; - reader_accum_ = 0; - bass_shift_ = 0; - clock_rate_ = 0; - bass_freq_ = 16; - length_ = 0; - - // assumptions code makes about implementation-defined features - #ifndef NDEBUG - // right shift of negative value preserves sign - buf_t_ i = -0x7FFFFFFE; - assert( (i >> 1) == -0x3FFFFFFF ); - - // casting to short truncates to 16 bits and sign-extends - i = 0x18000; - assert( (short) i == -0x8000 ); - #endif -} - -Blip_Buffer::~Blip_Buffer() -{ - if ( buffer_size_ != silent_buf_size ) - free( buffer_ ); -} - -Silent_Blip_Buffer::Silent_Blip_Buffer() -{ - factor_ = 0; - buffer_ = buf; - buffer_size_ = silent_buf_size; - memset( buf, 0, sizeof buf ); // in case machine takes exception for signed overflow -} - -void Blip_Buffer::clear( int entire_buffer ) -{ - offset_ = 0; - reader_accum_ = 0; - modified_ = 0; - if ( buffer_ ) - { - long count = (entire_buffer ? buffer_size_ : samples_avail()); - memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) ); - } -} - -Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec ) -{ - if ( buffer_size_ == silent_buf_size ) - { - assert( 0 ); - return "Internal (tried to resize Silent_Blip_Buffer)"; - } - - // start with maximum length that resampled time can represent - long new_size = (UINT_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64; - if ( msec != blip_max_length ) - { - long s = (new_rate * (msec + 1) + 999) / 1000; - if ( s < new_size ) - new_size = s; - else - assert( 0 ); // fails if requested buffer length exceeds limit - } - - if ( buffer_size_ != new_size ) - { - void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ ); - if ( !p ) - return "Out of memory"; - buffer_ = (buf_t_*) p; - } - - buffer_size_ = new_size; - assert( buffer_size_ != silent_buf_size ); - - // update things based on the sample rate - sample_rate_ = new_rate; - length_ = new_size * 1000 / new_rate - 1; - if ( msec ) - assert( length_ == msec ); // ensure length is same as that passed in - if ( clock_rate_ ) - clock_rate( clock_rate_ ); - bass_freq( bass_freq_ ); - - clear(); - - return 0; // success -} - -blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const -{ - double ratio = (double) sample_rate_ / rate; - blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 ); - assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large - return (blip_resampled_time_t) factor; -} - -void Blip_Buffer::bass_freq( int freq ) -{ - bass_freq_ = freq; - int shift = 31; - if ( freq > 0 ) - { - shift = 13; - long f = (freq << 16) / sample_rate_; - while ( (f >>= 1) && --shift ) { } - } - bass_shift_ = shift; -} - -void Blip_Buffer::end_frame( blip_time_t t ) -{ - offset_ += t * factor_; - assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length -} - -void Blip_Buffer::remove_silence( long count ) -{ - assert( count <= samples_avail() ); // tried to remove more samples than available - offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; -} - -long Blip_Buffer::count_samples( blip_time_t t ) const -{ - unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY; - unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY; - return (long) (last_sample - first_sample); -} - -blip_time_t Blip_Buffer::count_clocks( long count ) const -{ - if ( !factor_ ) - { - assert( 0 ); // sample rate and clock rates must be set first - return 0; - } - - if ( count > buffer_size_ ) - count = buffer_size_; - blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY; - return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_); -} - -void Blip_Buffer::remove_samples( long count ) -{ - if ( count ) - { - remove_silence( count ); - - // copy remaining samples to beginning and clear old samples - long remain = samples_avail() + blip_buffer_extra_; - memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ ); - memset( buffer_ + remain, 0, count * sizeof *buffer_ ); - } -} - -// Blip_Synth_ - -Blip_Synth_Fast_::Blip_Synth_Fast_() -{ - buf = 0; - last_amp = 0; - delta_factor = 0; -} - -void Blip_Synth_Fast_::volume_unit( double new_unit ) -{ - delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5); -} - -#if !BLIP_BUFFER_FAST - -Blip_Synth_::Blip_Synth_( short* p, int w ) : - impulses( p ), - width( w ) -{ - volume_unit_ = 0.0; - kernel_unit = 0; - buf = 0; - last_amp = 0; - delta_factor = 0; -} - -#undef PI -#define PI 3.1415926535897932384626433832795029 - -static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff ) -{ - if ( cutoff >= 0.999 ) - cutoff = 0.999; - - if ( treble < -300.0 ) - treble = -300.0; - if ( treble > 5.0 ) - treble = 5.0; - - double const maxh = 4096.0; - double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) ); - double const pow_a_n = pow( rolloff, maxh - maxh * cutoff ); - double const to_angle = PI / 2 / maxh / oversample; - for ( int i = 0; i < count; i++ ) - { - double angle = ((i - count) * 2 + 1) * to_angle; - double angle_maxh = angle * maxh; - double angle_maxh_mid = angle_maxh * cutoff; - - double y = maxh; - - // 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; - } -} - -void blip_eq_t::generate( float* out, int count ) const -{ - // lower cutoff freq for narrow kernels with their wider transition band - // (8 points->1.49, 16 points->1.15) - double oversample = blip_res * 2.25 / count + 0.85; - double half_rate = sample_rate * 0.5; - if ( cutoff_freq ) - oversample = half_rate / cutoff_freq; - double cutoff = rolloff_freq * oversample / half_rate; - - gen_sinc( out, count, blip_res * oversample, treble, cutoff ); - - // apply (half of) hamming window - double to_fraction = PI / (count - 1); - for ( int i = count; i--; ) - out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction ); -} - -void Blip_Synth_::adjust_impulse() -{ - // sum pairs for each phase and add error correction to end of first half - int const size = impulses_size(); - for ( int p = blip_res; p-- >= blip_res / 2; ) - { - int p2 = blip_res - 2 - p; - long error = kernel_unit; - for ( int i = 1; i < size; i += blip_res ) - { - error -= impulses [i + p ]; - error -= impulses [i + p2]; - } - if ( p == p2 ) - error /= 2; // phase = 0.5 impulse uses same half for both sides - impulses [size - blip_res + p] += (short) error; - //printf( "error: %ld\n", error ); - } - - //for ( int i = blip_res; i--; printf( "\n" ) ) - // for ( int j = 0; j < width / 2; j++ ) - // printf( "%5ld,", impulses [j * blip_res + i + 1] ); -} - -void Blip_Synth_::treble_eq( blip_eq_t const& eq ) -{ - float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2]; - - int const half_size = blip_res / 2 * (width - 1); - eq.generate( &fimpulse [blip_res], half_size ); - - int i; - - // need mirror slightly past center for calculation - for ( i = blip_res; i--; ) - fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i]; - - // starts at 0 - for ( i = 0; i < blip_res; i++ ) - fimpulse [i] = 0.0f; - - // find rescale factor - double total = 0.0; - for ( i = 0; i < half_size; i++ ) - total += fimpulse [blip_res + i]; - - //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB - //double const base_unit = 37888.0; // allows treble to +5 dB - double const base_unit = 32768.0; // necessary for blip_unscaled to work - double rescale = base_unit / 2 / total; - kernel_unit = (long) base_unit; - - // integrate, first difference, rescale, convert to int - double sum = 0.0; - double next = 0.0; - int const impulses_size = this->impulses_size(); - for ( i = 0; i < impulses_size; i++ ) - { - impulses [i] = (short) floor( (next - sum) * rescale + 0.5 ); - sum += fimpulse [i]; - next += fimpulse [i + blip_res]; - } - adjust_impulse(); - - // volume might require rescaling - double vol = volume_unit_; - if ( vol ) - { - volume_unit_ = 0.0; - volume_unit( vol ); - } -} - -void Blip_Synth_::volume_unit( double new_unit ) -{ - if ( new_unit != volume_unit_ ) - { - // use default eq if it hasn't been set yet - if ( !kernel_unit ) - treble_eq( -8.0 ); - - volume_unit_ = new_unit; - double factor = new_unit * (1L << blip_sample_bits) / kernel_unit; - - if ( factor > 0.0 ) - { - int shift = 0; - - // if unit is really small, might need to attenuate kernel - while ( factor < 2.0 ) - { - shift++; - factor *= 2.0; - } - - if ( shift ) - { - kernel_unit >>= shift; - assert( kernel_unit > 0 ); // fails if volume unit is too low - - // keep values positive to avoid round-towards-zero of sign-preserving - // right shift for negative values - long offset = 0x8000 + (1 << (shift - 1)); - long offset2 = 0x8000 >> shift; - for ( int i = impulses_size(); i--; ) - impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2); - adjust_impulse(); - } - } - delta_factor = (int) floor( factor + 0.5 ); - //printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit ); - } -} -#endif - -long Blip_Buffer::read_samples( blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo ) -{ - long count = samples_avail(); - if ( count > max_samples ) - count = max_samples; - - if ( count ) - { - int const bass = BLIP_READER_BASS( *this ); - BLIP_READER_BEGIN( reader, *this ); - - if ( !stereo ) - { - for ( blip_long n = count; n; --n ) - { - blip_long s = BLIP_READER_READ( reader ); - if ( (blip_sample_t) s != s ) - s = 0x7FFF - (s >> 24); - *out++ = (blip_sample_t) s; - BLIP_READER_NEXT( reader, bass ); - } - } - else - { - for ( blip_long n = count; n; --n ) - { - blip_long s = BLIP_READER_READ( reader ); - if ( (blip_sample_t) s != s ) - s = 0x7FFF - (s >> 24); - *out = (blip_sample_t) s; - out += 2; - BLIP_READER_NEXT( reader, bass ); - } - } - BLIP_READER_END( reader, *this ); - - remove_samples( count ); - } - return count; -} - -void Blip_Buffer::mix_samples( blip_sample_t const* in, long count ) -{ - if ( buffer_size_ == silent_buf_size ) - { - assert( 0 ); - return; - } - - buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2; - - int const sample_shift = blip_sample_bits - 16; - int prev = 0; - while ( count-- ) - { - blip_long s = (blip_long) *in++ << sample_shift; - *out += s - prev; - prev = s; - ++out; - } - *out -= prev; -} - diff --git a/libraries/game-music-emu/gme/Blip_Buffer.h b/libraries/game-music-emu/gme/Blip_Buffer.h deleted file mode 100644 index e6facc820..000000000 --- a/libraries/game-music-emu/gme/Blip_Buffer.h +++ /dev/null @@ -1,490 +0,0 @@ -// Band-limited sound synthesis buffer - -// Blip_Buffer 0.4.1 -#ifndef BLIP_BUFFER_H -#define BLIP_BUFFER_H - - // internal - #include - #if INT_MAX < 0x7FFFFFFF - #error "int must be at least 32 bits" - #endif - - typedef int blip_long; - typedef unsigned blip_ulong; - -// Time unit at source clock rate -typedef blip_long blip_time_t; - -// Output samples are 16-bit signed, with a range of -32768 to 32767 -typedef short blip_sample_t; -enum { blip_sample_max = 32767 }; - -class Blip_Buffer { -public: - typedef const char* blargg_err_t; - - // Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults - // to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there - // isn't enough memory, returns error without affecting current buffer setup. - blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 ); - - // Set number of source time units per second - void clock_rate( long ); - - // End current time frame of specified duration and make its samples available - // (along with any still-unread samples) for reading with read_samples(). Begins - // a new time frame at the end of the current frame. - void end_frame( blip_time_t time ); - - // Read at most 'max_samples' out of buffer into 'dest', removing them from from - // the buffer. Returns number of samples actually read and removed. If stereo is - // true, increments 'dest' one extra time after writing each sample, to allow - // easy interleving of two channels into a stereo output buffer. - long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 ); - -// Additional optional features - - // Current output sample rate - long sample_rate() const; - - // Length of buffer, in milliseconds - int length() const; - - // Number of source time units per second - long clock_rate() const; - - // Set frequency high-pass filter frequency, where higher values reduce bass more - void bass_freq( int frequency ); - - // Number of samples delay from synthesis to samples read out - int output_latency() const; - - // Remove all available samples and clear buffer to silence. If 'entire_buffer' is - // false, just clears out any samples waiting rather than the entire buffer. - void clear( int entire_buffer = 1 ); - - // Number of samples available for reading with read_samples() - long samples_avail() const; - - // Remove 'count' samples from those waiting to be read - void remove_samples( long count ); - -// Experimental features - - // Count number of clocks needed until 'count' samples will be available. - // If buffer can't even hold 'count' samples, returns number of clocks until - // buffer becomes full. - blip_time_t count_clocks( long count ) const; - - // Number of raw samples that can be mixed within frame of specified duration. - long count_samples( blip_time_t duration ) const; - - // Mix 'count' samples from 'buf' into buffer. - void mix_samples( blip_sample_t const* buf, long count ); - - // not documented yet - void set_modified() { modified_ = 1; } - int clear_modified() { int b = modified_; modified_ = 0; return b; } - typedef blip_ulong blip_resampled_time_t; - void remove_silence( long count ); - blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; } - blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; } - blip_resampled_time_t clock_rate_factor( long clock_rate ) const; -public: - Blip_Buffer(); - ~Blip_Buffer(); - - Blip_Buffer(Blip_Buffer &&) = default; - - // Deprecated - typedef blip_resampled_time_t resampled_time_t; - blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); } - blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); } -private: - // noncopyable - Blip_Buffer( const Blip_Buffer& ); - Blip_Buffer& operator = ( const Blip_Buffer& ); -public: - typedef blip_time_t buf_t_; - blip_ulong factor_; - blip_resampled_time_t offset_; - buf_t_* buffer_; - blip_long buffer_size_; - blip_long reader_accum_; - int bass_shift_; -private: - long sample_rate_; - long clock_rate_; - int bass_freq_; - int length_; - int modified_; - friend class Blip_Reader; -}; - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -// Number of bits in resample ratio fraction. Higher values give a more accurate ratio -// but reduce maximum buffer size. -#ifndef BLIP_BUFFER_ACCURACY - #define BLIP_BUFFER_ACCURACY 16 -#endif - -// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in -// noticeable broadband noise when synthesizing high frequency square waves. -// Affects size of Blip_Synth objects since they store the waveform directly. -#ifndef BLIP_PHASE_BITS - #if BLIP_BUFFER_FAST - #define BLIP_PHASE_BITS 8 - #else - #define BLIP_PHASE_BITS 6 - #endif -#endif - - // Internal - typedef blip_ulong blip_resampled_time_t; - int const blip_widest_impulse_ = 16; - int const blip_buffer_extra_ = blip_widest_impulse_ + 2; - int const blip_res = 1 << BLIP_PHASE_BITS; - class blip_eq_t; - - class Blip_Synth_Fast_ { - public: - Blip_Buffer* buf; - int last_amp; - int delta_factor; - - void volume_unit( double ); - Blip_Synth_Fast_(); - void treble_eq( blip_eq_t const& ) { } - }; - - class Blip_Synth_ { - public: - Blip_Buffer* buf; - int last_amp; - int delta_factor; - - void volume_unit( double ); - Blip_Synth_( short* impulses, int width ); - void treble_eq( blip_eq_t const& ); - private: - double volume_unit_; - short* const impulses; - int const width; - blip_long kernel_unit; - int impulses_size() const { return blip_res / 2 * width + 1; } - void adjust_impulse(); - }; - -// Quality level. Start with blip_good_quality. -const int blip_med_quality = 8; -const int blip_good_quality = 12; -const int blip_high_quality = 16; - -// Range specifies the greatest expected change in amplitude. Calculate it -// by finding the difference between the maximum and minimum expected -// amplitudes (max - min). -template -class Blip_Synth { -public: - // Set overall volume of waveform - void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); } - - // Configure low-pass filter (see blip_buffer.txt) - void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); } - - // Get/set Blip_Buffer used for output - Blip_Buffer* output() const { return impl.buf; } - void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; } - - // Update amplitude of waveform at given time. Using this requires a separate - // Blip_Synth for each waveform. - void update( blip_time_t time, int amplitude ); - -// Low-level interface - - // Add an amplitude transition of specified delta, optionally into specified buffer - // rather than the one set with output(). Delta can be positive or negative. - // The actual change in amplitude is delta * (volume / range) - void offset( blip_time_t, int delta, Blip_Buffer* ) const; - void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); } - - // Works directly in terms of fractional output samples. Contact author for more info. - void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const; - - // Same as offset(), except code is inlined for higher performance - void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const { - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); - } - void offset_inline( blip_time_t t, int delta ) const { - offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf ); - } - -private: -#if BLIP_BUFFER_FAST - Blip_Synth_Fast_ impl; -#else - Blip_Synth_ impl; - typedef short imp_t; - imp_t impulses [blip_res * (quality / 2) + 1]; -public: - Blip_Synth() : impl( impulses, quality ) { } -#endif -}; - -// Low-pass equalization parameters -class blip_eq_t { -public: - // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce - // treble, small positive values (0 to 5.0) increase treble. - blip_eq_t( double treble_db = 0 ); - - // See blip_buffer.txt - blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 ); - -private: - double treble; - long rolloff_freq; - long sample_rate; - long cutoff_freq; - void generate( float* out, int count ) const; - friend class Blip_Synth_; -}; - -int const blip_sample_bits = 30; - -// Dummy Blip_Buffer to direct sound output to, for easy muting without -// having to stop sound code. -class Silent_Blip_Buffer : public Blip_Buffer { - buf_t_ buf [blip_buffer_extra_ + 1]; -public: - // The following cannot be used (an assertion will fail if attempted): - blargg_err_t set_sample_rate( long samples_per_sec, int msec_length ); - blip_time_t count_clocks( long count ) const; - void mix_samples( blip_sample_t const* buf, long count ); - - Silent_Blip_Buffer(); -}; - - #if defined (__GNUC__) || _MSC_VER >= 1100 - #define BLIP_RESTRICT __restrict - #else - #define BLIP_RESTRICT - #endif - -// Optimized reading from Blip_Buffer, for use in custom sample output - -// Begin reading from buffer. Name should be unique to the current block. -#define BLIP_READER_BEGIN( name, blip_buffer ) \ - const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\ - blip_long name##_reader_accum = (blip_buffer).reader_accum_ - -// Get value to pass to BLIP_READER_NEXT() -#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_) - -// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal -// code at the cost of having no bass control -int const blip_reader_default_bass = 9; - -// Current sample -#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16)) - -// Current raw sample in full internal resolution -#define BLIP_READER_READ_RAW( name ) (name##_reader_accum) - -// Advance to next sample -#define BLIP_READER_NEXT( name, bass ) \ - (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass))) - -// End reading samples from buffer. The number of samples read must now be removed -// using Blip_Buffer::remove_samples(). -#define BLIP_READER_END( name, blip_buffer ) \ - (void) ((blip_buffer).reader_accum_ = name##_reader_accum) - - -// Compatibility with older version -const long blip_unscaled = 65535; -const int blip_low_quality = blip_med_quality; -const int blip_best_quality = blip_high_quality; - -// Deprecated; use BLIP_READER macros as follows: -// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf ); -// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf ); -// r.read() -> BLIP_READER_READ( r ) -// r.read_raw() -> BLIP_READER_READ_RAW( r ) -// r.next( bass ) -> BLIP_READER_NEXT( r, bass ) -// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass ) -// r.end( buf ) -> BLIP_READER_END( r, buf ) -class Blip_Reader { -public: - int begin( Blip_Buffer& ); - blip_long read() const { return accum >> (blip_sample_bits - 16); } - blip_long read_raw() const { return accum; } - void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); } - void end( Blip_Buffer& b ) { b.reader_accum_ = accum; } - -private: - const Blip_Buffer::buf_t_* buf; - blip_long accum; -}; - -// End of public interface - -#include - -template -inline void Blip_Synth::offset_resampled( blip_resampled_time_t time, - int delta, Blip_Buffer* blip_buf ) const -{ - // Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the - // need for a longer buffer as set by set_sample_rate(). - assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ ); - delta *= impl.delta_factor; - blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY); - int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1)); - -#if BLIP_BUFFER_FAST - blip_long left = buf [0] + delta; - - // Kind of crappy, but doing shift after multiply results in overflow. - // Alternate way of delaying multiply by delta_factor results in worse - // sub-sample resolution. - blip_long right = (delta >> BLIP_PHASE_BITS) * phase; - left -= right; - right += buf [1]; - - buf [0] = left; - buf [1] = right; -#else - - int const fwd = (blip_widest_impulse_ - quality) / 2; - int const rev = fwd + quality - 2; - int const mid = quality / 2 - 1; - - imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase; - - #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ - defined (__x86_64__) || defined (__ia64__) || defined (__i386__) - - // straight forward implementation resulted in better code on GCC for x86 - - #define ADD_IMP( out, in ) \ - buf [out] += (blip_long) imp [blip_res * (in)] * delta - - #define BLIP_FWD( i ) {\ - ADD_IMP( fwd + i, i );\ - ADD_IMP( fwd + 1 + i, i + 1 );\ - } - #define BLIP_REV( r ) {\ - ADD_IMP( rev - r, r + 1 );\ - ADD_IMP( rev + 1 - r, r );\ - } - - BLIP_FWD( 0 ) - if ( quality > 8 ) BLIP_FWD( 2 ) - if ( quality > 12 ) BLIP_FWD( 4 ) - { - ADD_IMP( fwd + mid - 1, mid - 1 ); - ADD_IMP( fwd + mid , mid ); - imp = impulses + phase; - } - if ( quality > 12 ) BLIP_REV( 6 ) - if ( quality > 8 ) BLIP_REV( 4 ) - BLIP_REV( 2 ) - - ADD_IMP( rev , 1 ); - ADD_IMP( rev + 1, 0 ); - - #else - - // for RISC processors, help compiler by reading ahead of writes - - #define BLIP_FWD( i ) {\ - blip_long t0 = i0 * delta + buf [fwd + i];\ - blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\ - i0 = imp [blip_res * (i + 2)];\ - buf [fwd + i] = t0;\ - buf [fwd + 1 + i] = t1;\ - } - #define BLIP_REV( r ) {\ - blip_long t0 = i0 * delta + buf [rev - r];\ - blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\ - i0 = imp [blip_res * (r - 1)];\ - buf [rev - r] = t0;\ - buf [rev + 1 - r] = t1;\ - } - - blip_long i0 = *imp; - BLIP_FWD( 0 ) - if ( quality > 8 ) BLIP_FWD( 2 ) - if ( quality > 12 ) BLIP_FWD( 4 ) - { - blip_long t0 = i0 * delta + buf [fwd + mid - 1]; - blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ]; - imp = impulses + phase; - i0 = imp [blip_res * mid]; - buf [fwd + mid - 1] = t0; - buf [fwd + mid ] = t1; - } - if ( quality > 12 ) BLIP_REV( 6 ) - if ( quality > 8 ) BLIP_REV( 4 ) - BLIP_REV( 2 ) - - blip_long t0 = i0 * delta + buf [rev ]; - blip_long t1 = *imp * delta + buf [rev + 1]; - buf [rev ] = t0; - buf [rev + 1] = t1; - #endif - -#endif -} - -#undef BLIP_FWD -#undef BLIP_REV - -template -#if BLIP_BUFFER_FAST - inline -#endif -void Blip_Synth::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const -{ - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); -} - -template -#if BLIP_BUFFER_FAST - inline -#endif -void Blip_Synth::update( blip_time_t t, int amp ) -{ - int delta = amp - impl.last_amp; - impl.last_amp = amp; - offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf ); -} - -inline blip_eq_t::blip_eq_t( double t ) : - treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { } -inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) : - treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { } - -inline int Blip_Buffer::length() const { return length_; } -inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); } -inline long Blip_Buffer::sample_rate() const { return sample_rate_; } -inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; } -inline long Blip_Buffer::clock_rate() const { return clock_rate_; } -inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); } - -inline int Blip_Reader::begin( Blip_Buffer& blip_buf ) -{ - buf = blip_buf.buffer_; - accum = blip_buf.reader_accum_; - return blip_buf.bass_shift_; -} - -int const blip_max_length = 0; -int const blip_default_length = 250; - -#endif diff --git a/libraries/game-music-emu/gme/CMakeLists.txt b/libraries/game-music-emu/gme/CMakeLists.txt deleted file mode 100644 index 1e0010fc0..000000000 --- a/libraries/game-music-emu/gme/CMakeLists.txt +++ /dev/null @@ -1,204 +0,0 @@ -# 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 - ) - -# static builds need to find static zlib (and static forms of other needed -# libraries. Ensure CMake looks only for static libs if we're doing a static -# build. See https://stackoverflow.com/a/44738756 -if(NOT BUILD_SHARED_LIBS) - set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") -endif() - -find_package(ZLIB QUIET) - -# Ay_Apu is very popular around here -if (USE_GME_AY OR USE_GME_KSS) - set(libgme_SRCS ${libgme_SRCS} - Ay_Apu.cpp - ) -endif() - -# so is Ym2612_Emu -if (USE_GME_VGM OR USE_GME_GYM) - if(GME_YM2612_EMU STREQUAL "Nuked") - add_definitions(-DVGM_YM2612_NUKED) - set(libgme_SRCS ${libgme_SRCS} - Ym2612_Nuked.cpp - ) - message("VGM/GYM: Nuked OPN2 emulator will be used") - elseif(GME_YM2612_EMU STREQUAL "MAME") - add_definitions(-DVGM_YM2612_MAME) - set(libgme_SRCS ${libgme_SRCS} - Ym2612_MAME.cpp - ) - message("VGM/GYM: MAME YM2612 emulator will be used") - else() - add_definitions(-DVGM_YM2612_GENS) - set(libgme_SRCS ${libgme_SRCS} - Ym2612_GENS.cpp - ) - message("VGM/GYM: GENS 2.10 emulator will be used") - endif() -endif() - -# But none are as popular as Sms_Apu -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) - -# 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. - -# Not needed -#add_definitions(-DBLARGG_BUILD_DLL) - -# For the gme_types.h -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -# Add library to be compiled. -add_library(gme STATIC ${libgme_SRCS}) - -if(ZLIB_FOUND) - message(" ** ZLib library located, compressed file formats will be supported") - target_compile_definitions(gme PRIVATE -DHAVE_ZLIB_H) - target_include_directories(gme PRIVATE ${ZLIB_INCLUDE_DIRS}) - target_link_libraries(gme ${ZLIB_LIBRARIES}) - # Is not to be installed though - - set(PKG_CONFIG_ZLIB -lz) # evaluated in libgme.pc.in -else() - message("ZLib library not found, disabling support for compressed formats such as VGZ") -endif() - -# Not needed. -if( FALSE ) -# The version is the release. The "soversion" is the API version. As long -# as only build fixes are performed (i.e. no backwards-incompatible changes -# to the API), the SOVERSION should be the same even when bumping up VERSION. -# The way gme.h is designed, SOVERSION should very rarely be bumped, if ever. -# Hopefully the API can stay compatible with old versions. -set_target_properties(gme - PROPERTIES VERSION ${GME_VERSION} - SOVERSION 0) - -install(TARGETS gme LIBRARY DESTINATION lib${LIB_SUFFIX} - RUNTIME DESTINATION bin # DLL platforms - ARCHIVE DESTINATION lib) # DLL platforms - -# Run during cmake phase, so this is available during make -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gme_types.h.in - ${CMAKE_CURRENT_BINARY_DIR}/gme_types.h) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libgme.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc @ONLY) - -install(FILES ${EXPORTED_HEADERS} DESTINATION include/gme) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgme.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig) -endif() diff --git a/libraries/game-music-emu/gme/Classic_Emu.cpp b/libraries/game-music-emu/gme/Classic_Emu.cpp deleted file mode 100644 index c572d9b5c..000000000 --- a/libraries/game-music-emu/gme/Classic_Emu.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Classic_Emu.h" - -#include "Multi_Buffer.h" -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -Classic_Emu::Classic_Emu() -{ - buf = 0; - stereo_buffer = 0; - voice_types = 0; - - // avoid inconsistency in our duplicated constants - assert( (int) wave_type == (int) Multi_Buffer::wave_type ); - assert( (int) noise_type == (int) Multi_Buffer::noise_type ); - assert( (int) mixed_type == (int) Multi_Buffer::mixed_type ); -} - -Classic_Emu::~Classic_Emu() -{ - delete stereo_buffer; -} - -void Classic_Emu::set_equalizer_( equalizer_t const& eq ) -{ - Music_Emu::set_equalizer_( eq ); - update_eq( eq.treble ); - if ( buf ) - buf->bass_freq( (int) equalizer().bass ); -} - -blargg_err_t Classic_Emu::set_sample_rate_( long rate ) -{ - if ( !buf ) - { - if ( !stereo_buffer ) - CHECK_ALLOC( stereo_buffer = BLARGG_NEW Stereo_Buffer ); - buf = stereo_buffer; - } - return buf->set_sample_rate( rate, 1000 / 20 ); -} - -blargg_err_t Classic_Emu::set_multi_channel ( bool is_enabled ) -{ - RETURN_ERR( Music_Emu::set_multi_channel_( is_enabled ) ); - return 0; -} - -void Classic_Emu::mute_voices_( int mask ) -{ - Music_Emu::mute_voices_( mask ); - for ( int i = voice_count(); i--; ) - { - if ( mask & (1 << i) ) - { - set_voice( i, 0, 0, 0 ); - } - else - { - Multi_Buffer::channel_t ch = buf->channel( i, (voice_types ? voice_types [i] : 0) ); - assert( (ch.center && ch.left && ch.right) || - (!ch.center && !ch.left && !ch.right) ); // all or nothing - set_voice( i, ch.center, ch.left, ch.right ); - } - } -} - -void Classic_Emu::change_clock_rate( long rate ) -{ - clock_rate_ = rate; - buf->clock_rate( rate ); -} - -blargg_err_t Classic_Emu::setup_buffer( long rate ) -{ - change_clock_rate( rate ); - RETURN_ERR( buf->set_channel_count( voice_count() ) ); - set_equalizer( equalizer() ); - buf_changed_count = buf->channels_changed_count(); - return 0; -} - -blargg_err_t Classic_Emu::start_track_( int track ) -{ - RETURN_ERR( Music_Emu::start_track_( track ) ); - buf->clear(); - return 0; -} - -blargg_err_t Classic_Emu::play_( long count, sample_t* out ) -{ - long remain = count; - while ( remain ) - { - remain -= buf->read_samples( &out [count - remain], remain ); - if ( remain ) - { - if ( buf_changed_count != buf->channels_changed_count() ) - { - buf_changed_count = buf->channels_changed_count(); - remute_voices(); - } - int msec = buf->length(); - blip_time_t clocks_emulated = (blargg_long) msec * clock_rate_ / 1000; - RETURN_ERR( run_clocks( clocks_emulated, msec ) ); - assert( clocks_emulated ); - buf->end_frame( clocks_emulated ); - } - } - return 0; -} - -// Rom_Data - -blargg_err_t Rom_Data_::load_rom_data_( Data_Reader& in, - int header_size, void* header_out, int fill, long pad_size ) -{ - long file_offset = pad_size - header_size; - - rom_addr = 0; - mask = 0; - size_ = 0; - rom.clear(); - - file_size_ = in.remain(); - if ( file_size_ <= header_size ) // <= because there must be data after header - return gme_wrong_file_type; - blargg_err_t err = rom.resize( file_offset + file_size_ + pad_size ); - if ( !err ) - err = in.read( rom.begin() + file_offset, file_size_ ); - if ( err ) - { - rom.clear(); - return err; - } - - file_size_ -= header_size; - memcpy( header_out, &rom [file_offset], header_size ); - - memset( rom.begin() , fill, pad_size ); - memset( rom.end() - pad_size, fill, pad_size ); - - return 0; -} - -void Rom_Data_::set_addr_( long addr, int unit ) -{ - rom_addr = addr - unit - pad_extra; - - long rounded = (addr + file_size_ + unit - 1) / unit * unit; - if ( rounded <= 0 ) - { - rounded = 0; - } - else - { - int shift = 0; - unsigned long max_addr = (unsigned long) (rounded - 1); - while ( max_addr >> shift ) - shift++; - mask = (1L << shift) - 1; - } - - if ( addr < 0 ) - addr = 0; - size_ = rounded; - if ( rom.resize( rounded - rom_addr + pad_extra ) ) { } // OK if shrink fails - - if ( 0 ) - { - debug_printf( "addr: %X\n", addr ); - debug_printf( "file_size: %d\n", file_size_ ); - debug_printf( "rounded: %d\n", rounded ); - debug_printf( "mask: $%X\n", mask ); - } -} diff --git a/libraries/game-music-emu/gme/Classic_Emu.h b/libraries/game-music-emu/gme/Classic_Emu.h deleted file mode 100644 index 57cdd5c32..000000000 --- a/libraries/game-music-emu/gme/Classic_Emu.h +++ /dev/null @@ -1,128 +0,0 @@ -// Common aspects of emulators which use Blip_Buffer for sound output - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef CLASSIC_EMU_H -#define CLASSIC_EMU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" -#include "Music_Emu.h" - -class Classic_Emu : public Music_Emu { -public: - Classic_Emu(); - ~Classic_Emu(); - void set_buffer( Multi_Buffer* ); - blargg_err_t set_multi_channel( bool is_enabled ) override; -protected: - // Services - enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; - void set_voice_types( int const* t ) { voice_types = t; } - blargg_err_t setup_buffer( long clock_rate ); - long clock_rate() const { return clock_rate_; } - void change_clock_rate( long ); // experimental - - // Overridable - virtual void set_voice( int index, Blip_Buffer* center, - Blip_Buffer* left, Blip_Buffer* right ) = 0; - virtual void update_eq( blip_eq_t const& ) = 0; - virtual blargg_err_t start_track_( int track ) = 0; - virtual blargg_err_t run_clocks( blip_time_t& time_io, int msec ) = 0; -protected: - blargg_err_t set_sample_rate_( long sample_rate ); - void mute_voices_( int ); - void set_equalizer_( equalizer_t const& ); - blargg_err_t play_( long, sample_t* ); -private: - Multi_Buffer* buf; - Multi_Buffer* stereo_buffer; // NULL if using custom buffer - long clock_rate_; - unsigned buf_changed_count; - int const* voice_types; -}; - -inline void Classic_Emu::set_buffer( Multi_Buffer* new_buf ) -{ - assert( !buf && new_buf ); - buf = new_buf; -} - -// ROM data handler, used by several Classic_Emu derivitives. Loads file data -// with padding on both sides, allowing direct use in bank mapping. The main purpose -// is to allow all file data to be loaded with only one read() call (for efficiency). - -class Rom_Data_ { -public: - typedef unsigned char byte; -protected: - enum { pad_extra = 8 }; - blargg_vector rom; - long file_size_; - blargg_long rom_addr; - blargg_long mask; - blargg_long size_; // TODO: eliminate - - blargg_err_t load_rom_data_( Data_Reader& in, int header_size, void* header_out, - int fill, long pad_size ); - void set_addr_( long addr, int unit ); -}; - -template -class Rom_Data : public Rom_Data_ { - enum { pad_size = unit + pad_extra }; -public: - // Load file data, using already-loaded header 'h' if not NULL. Copy header - // from loaded file data into *out and fill unmapped bytes with 'fill'. - blargg_err_t load( Data_Reader& in, int header_size, void* header_out, int fill ) - { - return load_rom_data_( in, header_size, header_out, fill, pad_size ); - } - - // Size of file data read in (excluding header) - long file_size() const { return file_size_; } - - // Pointer to beginning of file data - byte* begin() const { return rom.begin() + pad_size; } - - // Set address that file data should start at - void set_addr( long addr ) { set_addr_( addr, unit ); } - - // Free data - void clear() { rom.clear(); } - - // Size of data + start addr, rounded to a multiple of unit - long size() const { return size_; } - - // Pointer to unmapped page filled with same value - byte* unmapped() { return rom.begin(); } - - // Mask address to nearest power of two greater than size() - blargg_long mask_addr( blargg_long addr ) const - { - #ifdef check - check( addr <= mask ); - #endif - return addr & mask; - } - - // Pointer to page starting at addr. Returns unmapped() if outside data. - byte* at_addr( blargg_long addr ) - { - blargg_ulong offset = mask_addr( addr ) - rom_addr; - if ( offset > blargg_ulong (rom.size() - pad_size) ) - offset = 0; // unmapped - return &rom [offset]; - } -}; - -#ifndef GME_APU_HOOK - #define GME_APU_HOOK( emu, addr, data ) ((void) 0) -#endif - -#ifndef GME_FRAME_HOOK - #define GME_FRAME_HOOK( emu ) ((void) 0) -#else - #define GME_FRAME_HOOK_DEFINED 1 -#endif - -#endif diff --git a/libraries/game-music-emu/gme/Data_Reader.cpp b/libraries/game-music-emu/gme/Data_Reader.cpp deleted file mode 100644 index 1556c329f..000000000 --- a/libraries/game-music-emu/gme/Data_Reader.cpp +++ /dev/null @@ -1,449 +0,0 @@ -// File_Extractor 0.4.0. http://www.slack.net/~ant/ - -#include "Data_Reader.h" - -#include "blargg_endian.h" -#include -#include -#include - -/* 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 -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" - -#ifdef HAVE_ZLIB_H -#include -#include -#include -static const unsigned char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ -#endif /* HAVE_ZLIB_H */ - -const char Data_Reader::eof_error [] = "Unexpected end of file"; - -#define RETURN_VALIDITY_CHECK( cond ) \ - do { if ( unlikely( !(cond) ) ) return "Corrupt file"; } while(0) - -blargg_err_t Data_Reader::read( void* p, long s ) -{ - RETURN_VALIDITY_CHECK( s > 0 ); - - long result = read_avail( p, s ); - if ( result != s ) - { - if ( result >= 0 && result < s ) - return eof_error; - - return "Read error"; - } - - return 0; -} - -blargg_err_t Data_Reader::skip( long count ) -{ - RETURN_VALIDITY_CHECK( count >= 0 ); - - char buf [512]; - while ( count ) - { - long n = sizeof buf; - if ( n > count ) - n = count; - count -= n; - RETURN_ERR( read( buf, n ) ); - } - return 0; -} - -long File_Reader::remain() const { return size() - tell(); } - -blargg_err_t File_Reader::skip( long n ) -{ - RETURN_VALIDITY_CHECK( n >= 0 ); - - if ( !n ) - return 0; - return seek( tell() + n ); -} - -// Subset_Reader - -Subset_Reader::Subset_Reader( Data_Reader* dr, long size ) -{ - in = dr; - remain_ = dr->remain(); - if ( remain_ > size ) - remain_ = max( 0l, size ); -} - -long Subset_Reader::remain() const { return remain_; } - -long Subset_Reader::read_avail( void* p, long s ) -{ - s = max( 0l, s ); - if ( s > remain_ ) - s = remain_; - remain_ -= s; - return in->read_avail( p, s ); -} - -// Remaining_Reader - -Remaining_Reader::Remaining_Reader( void const* h, long size, Data_Reader* r ) -{ - header = (char const*) h; - header_end = header + max( 0l, size ); - in = r; -} - -long Remaining_Reader::remain() const { return header_end - header + in->remain(); } - -long Remaining_Reader::read_first( void* out, long count ) -{ - count = max( 0l, count ); - long first = header_end - header; - if ( first ) - { - if ( first > count || first < 0 ) - first = count; - void const* old = header; - header += first; - memcpy( out, old, (size_t) first ); - } - return first; -} - -long Remaining_Reader::read_avail( void* out, long count ) -{ - count = max( 0l, count ); - long first = read_first( out, count ); - long second = max( 0l, count - first ); - if ( second ) - { - second = in->read_avail( (char*) out + first, second ); - if ( second <= 0 ) - return second; - } - return first + second; -} - -blargg_err_t Remaining_Reader::read( void* out, long count ) -{ - count = max( 0l, count ); - long first = read_first( out, count ); - long second = max( 0l, count - first ); - if ( !second ) - return 0; - return in->read( (char*) out + first, second ); -} - -// Mem_File_Reader - -Mem_File_Reader::Mem_File_Reader( const void* p, long s ) : - m_begin( (const char*) p ), - m_size( max( 0l, s ) ), - m_pos( 0l ) -{ -#ifdef HAVE_ZLIB_H - if( !m_begin ) - return; - - if ( gz_decompress() ) - { - debug_printf( "Loaded compressed data\n" ); - m_ownedPtr = true; - } -#endif /* HAVE_ZLIB_H */ -} - -#ifdef HAVE_ZLIB_H -Mem_File_Reader::~Mem_File_Reader() -{ - if ( m_ownedPtr ) - free( const_cast( m_begin ) ); // see gz_compress for the malloc -} -#endif - -long Mem_File_Reader::size() const { return m_size; } - -long Mem_File_Reader::read_avail( void* p, long s ) -{ - long r = remain(); - if ( s > r || s < 0 ) - s = r; - memcpy( p, m_begin + m_pos, static_cast(s) ); - m_pos += s; - return s; -} - -long Mem_File_Reader::tell() const { return m_pos; } - -blargg_err_t Mem_File_Reader::seek( long n ) -{ - RETURN_VALIDITY_CHECK( n >= 0 ); - if ( n > m_size ) - return eof_error; - m_pos = n; - return 0; -} - -#ifdef HAVE_ZLIB_H - -bool Mem_File_Reader::gz_decompress() -{ - if ( m_size >= 2 && memcmp(m_begin, gz_magic, 2) != 0 ) - { - /* Don't try to decompress non-GZ files, just assign input pointer */ - return false; - } - - using vec_size = size_t; - const vec_size full_length = static_cast( m_size ); - const vec_size half_length = static_cast( m_size / 2 ); - - // We use malloc/friends here so we can realloc to grow buffer if needed - char *raw_data = reinterpret_cast ( malloc( full_length ) ); - size_t raw_data_size = full_length; - if ( !raw_data ) - return false; - - z_stream strm; - strm.next_in = const_cast( reinterpret_cast( m_begin ) ); - strm.avail_in = static_cast( m_size ); - strm.total_out = 0; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - - bool done = false; - - // Adding 16 sets bit 4, which enables zlib to auto-detect the - // header. - if ( inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK ) - { - free( raw_data ); - return false; - } - - while ( !done ) - { - /* If our output buffer is too small */ - if ( strm.total_out >= raw_data_size ) - { - raw_data_size += half_length; - raw_data = reinterpret_cast( realloc( raw_data, raw_data_size ) ); - if ( !raw_data ) { - return false; - } - } - - strm.next_out = reinterpret_cast( raw_data + strm.total_out ); - strm.avail_out = static_cast( static_cast( raw_data_size ) - strm.total_out ); - - /* Inflate another chunk. */ - int err = inflate( &strm, Z_SYNC_FLUSH ); - if ( err == Z_STREAM_END ) - done = true; - else if ( err != Z_OK ) - break; - } - - if ( inflateEnd(&strm) != Z_OK ) - { - free( raw_data ); - return false; - } - - m_begin = raw_data; - m_size = static_cast( strm.total_out ); - - return true; -} - -#endif /* HAVE_ZLIB_H */ - - -// Callback_Reader - -Callback_Reader::Callback_Reader( callback_t c, long size, void* d ) : - callback( c ), - data( d ) -{ - remain_ = max( 0l, size ); -} - -long Callback_Reader::remain() const { return remain_; } - -long Callback_Reader::read_avail( void* out, long count ) -{ - if ( count > remain_ ) - count = remain_; - if ( count < 0 || Callback_Reader::read( out, count ) ) - count = -1; - return count; -} - -blargg_err_t Callback_Reader::read( void* out, long count ) -{ - RETURN_VALIDITY_CHECK( count >= 0 ); - if ( count > remain_ ) - return eof_error; - return callback( data, out, (int) count ); -} - -// Std_File_Reader - -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - -static const char* get_gzip_eof( const char* path, long* eof ) -{ - FILE* file = fopen( path, "rb" ); - if ( !file ) - return "Couldn't open file"; - - unsigned char buf [4]; - bool found_eof = false; - if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B ) - { - fseek( file, -4, SEEK_END ); - if ( fread( buf, 4, 1, file ) > 0 ) { - *eof = get_le32( buf ); - found_eof = true; - } - } - if ( !found_eof ) - { - fseek( file, 0, SEEK_END ); - *eof = ftell( file ); - } - const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : nullptr; - fclose( file ); - return err; -} -#endif - - -Std_File_Reader::Std_File_Reader() : - file_( nullptr ) -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - , size_( 0 ) -#endif -{ } - -Std_File_Reader::~Std_File_Reader() { close(); } - -blargg_err_t Std_File_Reader::open( const char* path ) -{ -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - // zlib transparently handles uncompressed data if magic header - // not present but we still need to grab size - RETURN_ERR( get_gzip_eof( path, &size_ ) ); - file_ = gzopen( path, "rb" ); -#else - file_ = fopen( path, "rb" ); -#endif - - if ( !file_ ) - return "Couldn't open file"; - return nullptr; -} - -long Std_File_Reader::size() const -{ -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - if ( file_ ) - return size_; // Set for both compressed and uncompressed modes -#endif - long pos = tell(); - fseek( (FILE*) file_, 0, SEEK_END ); - long result = tell(); - fseek( (FILE*) file_, pos, SEEK_SET ); - return result; -} - -long Std_File_Reader::read_avail( void* p, long s ) -{ -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - if ( file_ && s > 0 && s <= UINT_MAX ) { - return gzread( reinterpret_cast(file_), - p, static_cast(s) ); - } - return 0l; -#else - const size_t readLength = static_cast( max( 0l, s ) ); - const auto result = fread( p, 1, readLength, reinterpret_cast(file_) ); - return static_cast( result ); -#endif /* HAVE_ZLIB_H */ -} - -blargg_err_t Std_File_Reader::read( void* p, long s ) -{ - RETURN_VALIDITY_CHECK( s > 0 && s <= UINT_MAX ); -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - if ( file_ ) - { - const auto &gzfile = reinterpret_cast( file_ ); - if ( s == gzread( gzfile, p, static_cast( s ) ) ) - return nullptr; - if ( gzeof( gzfile ) ) - return eof_error; - return "Couldn't read from GZ file"; - } -#endif - const auto &file = reinterpret_cast( file_ ); - if ( s == static_cast( fread( p, 1, static_cast(s), file ) ) ) - return 0; - if ( feof( file ) ) - return eof_error; - return "Couldn't read from file"; -} - -long Std_File_Reader::tell() const -{ -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - if ( file_ ) - return gztell( reinterpret_cast( file_ ) ); -#endif - return ftell( reinterpret_cast( file_ ) ); -} - -blargg_err_t Std_File_Reader::seek( long n ) -{ -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - if ( file_ ) - { - if ( gzseek( reinterpret_cast( file_ ), n, SEEK_SET ) >= 0 ) - return nullptr; - if ( n > size_ ) - return eof_error; - return "Error seeking in GZ file"; - } -#endif - if ( !fseek( reinterpret_cast( file_ ), n, SEEK_SET ) ) - return nullptr; - if ( n > size() ) - return eof_error; - return "Error seeking in file"; -} - -void Std_File_Reader::close() -{ - if ( file_ ) - { -#if 0//[ZDOOM:unneeded]def HAVE_ZLIB_H - gzclose( reinterpret_cast( file_ ) ); -#else - fclose( reinterpret_cast( file_ ) ); -#endif - file_ = nullptr; - } -} - diff --git a/libraries/game-music-emu/gme/Data_Reader.h b/libraries/game-music-emu/gme/Data_Reader.h deleted file mode 100644 index 59357767e..000000000 --- a/libraries/game-music-emu/gme/Data_Reader.h +++ /dev/null @@ -1,149 +0,0 @@ -// Data reader interface for uniform access - -// File_Extractor 0.4.0 -#ifndef DATA_READER_H -#define DATA_READER_H - -#include "blargg_common.h" - -#ifdef HAVE_ZLIB_H -#include -#endif - -// Supports reading and finding out how many bytes are remaining -class Data_Reader { -public: - virtual ~Data_Reader() { } - - static const char eof_error []; // returned by read() when request goes beyond end - - // Read at most count bytes and return number actually read, or <= 0 if error - virtual long read_avail( void*, long n ) = 0; - - // Read exactly count bytes and return error if they couldn't be read - virtual blargg_err_t read( void*, long count ); - - // Number of bytes remaining until end of file - virtual long remain() const = 0; - - // Read and discard count bytes - virtual blargg_err_t skip( long count ); - -public: - Data_Reader() { } - typedef blargg_err_t error_t; // deprecated -private: - // noncopyable - Data_Reader( const Data_Reader& ); - Data_Reader& operator = ( const Data_Reader& ); -}; - -// Supports seeking in addition to Data_Reader operations -class File_Reader : public Data_Reader { -public: - // Size of file - virtual long size() const = 0; - - // Current position in file - virtual long tell() const = 0; - - // Go to new position - virtual blargg_err_t seek( long ) = 0; - - long remain() const; - blargg_err_t skip( long n ); -}; - -// Disk file reader -class Std_File_Reader : public File_Reader { -public: - blargg_err_t open( const char* path ); - void close(); - -public: - Std_File_Reader(); - ~Std_File_Reader(); - long size() const; - blargg_err_t read( void*, long ); - long read_avail( void*, long ); - long tell() const; - blargg_err_t seek( long ); -private: - void* file_; // Either FILE* or zlib's gzFile -#if 0//[ZDOOM:unneeded] def HAVE_ZLIB_H - long size_; // TODO: Fix ABI compat -#endif /* HAVE_ZLIB_H */ -}; - -// Treats range of memory as a file -class Mem_File_Reader : public File_Reader { -public: - Mem_File_Reader( const void*, long size ); -#ifdef HAVE_ZLIB_H - ~Mem_File_Reader( ); -#endif /* HAVE_ZLIB_H */ - -public: - long size() const; - long read_avail( void*, long ); - long tell() const; - blargg_err_t seek( long ); -private: -#ifdef HAVE_ZLIB_H - bool gz_decompress(); -#endif /* HAVE_ZLIB_H */ - - const char* m_begin; - long m_size; - long m_pos; -#ifdef HAVE_ZLIB_H - bool m_ownedPtr = false; // set if we must free m_begin -#endif /* HAVE_ZLIB_H */ -}; - - -// Makes it look like there are only count bytes remaining -class Subset_Reader : public Data_Reader { -public: - Subset_Reader( Data_Reader*, long count ); - -public: - long remain() const; - long read_avail( void*, long ); -private: - Data_Reader* in; - long remain_; -}; - -// Joins already-read header and remaining data into original file (to avoid seeking) -class Remaining_Reader : public Data_Reader { -public: - Remaining_Reader( void const* header, long size, Data_Reader* ); - -public: - long remain() const; - long read_avail( void*, long ); - blargg_err_t read( void*, long ); -private: - char const* header; - char const* header_end; - Data_Reader* in; - long read_first( void* out, long count ); -}; - -// Invokes callback function to read data. Size of data must be specified in advance. -class Callback_Reader : public Data_Reader { -public: - typedef const char* (*callback_t)( void* data, void* out, int count ); - Callback_Reader( callback_t, long size, void* data = 0 ); -public: - long read_avail( void*, long ); - blargg_err_t read( void*, long ); - long remain() const; -private: - callback_t const callback; - void* const data; - long remain_; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Dual_Resampler.cpp b/libraries/game-music-emu/gme/Dual_Resampler.cpp deleted file mode 100644 index e774d85f8..000000000 --- a/libraries/game-music-emu/gme/Dual_Resampler.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Dual_Resampler.h" - -#include -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -unsigned const resampler_extra = 256; - -Dual_Resampler::Dual_Resampler() : - sample_buf_size(0), - oversamples_per_frame(-1), - buf_pos(-1), - resampler_size(0) -{ -} - -Dual_Resampler::~Dual_Resampler() { } - -blargg_err_t Dual_Resampler::reset( int pairs ) -{ - // expand allocations a bit - RETURN_ERR( sample_buf.resize( (pairs + (pairs >> 2)) * 2 ) ); - resize( pairs ); - resampler_size = oversamples_per_frame + (oversamples_per_frame >> 2); - return resampler.buffer_size( resampler_size ); -} - -void Dual_Resampler::resize( int pairs ) -{ - int new_sample_buf_size = pairs * 2; - if ( sample_buf_size != new_sample_buf_size ) - { - if ( (unsigned) new_sample_buf_size > sample_buf.size() ) - { - check( false ); - return; - } - sample_buf_size = new_sample_buf_size; - oversamples_per_frame = int (pairs * resampler.ratio()) * 2 + 2; - clear(); - } -} - -void Dual_Resampler::play_frame_( Blip_Buffer& blip_buf, dsample_t* out ) -{ - long pair_count = sample_buf_size >> 1; - blip_time_t blip_time = blip_buf.count_clocks( pair_count ); - int sample_count = oversamples_per_frame - resampler.written(); - - int new_count = play_frame( blip_time, sample_count, resampler.buffer() ); - assert( new_count < resampler_size ); - - blip_buf.end_frame( blip_time ); - assert( blip_buf.samples_avail() == pair_count ); - - resampler.write( new_count ); - -#ifdef NDEBUG // Avoid warning when asserts are disabled - resampler.read( sample_buf.begin(), sample_buf_size ); -#else - long count = resampler.read( sample_buf.begin(), sample_buf_size ); - assert( count == (long) sample_buf_size ); -#endif - - mix_samples( blip_buf, out ); - blip_buf.remove_samples( pair_count ); -} - -void Dual_Resampler::dual_play( long count, dsample_t* out, Blip_Buffer& blip_buf ) -{ - // empty extra buffer - long remain = sample_buf_size - buf_pos; - if ( remain ) - { - if ( remain > count ) - remain = count; - count -= remain; - memcpy( out, &sample_buf [buf_pos], remain * sizeof *out ); - out += remain; - buf_pos += remain; - } - - // entire frames - while ( count >= (long) sample_buf_size ) - { - play_frame_( blip_buf, out ); - out += sample_buf_size; - count -= sample_buf_size; - } - - // extra - if ( count ) - { - play_frame_( blip_buf, sample_buf.begin() ); - buf_pos = count; - memcpy( out, sample_buf.begin(), count * sizeof *out ); - out += count; - } -} - -void Dual_Resampler::mix_samples( Blip_Buffer& blip_buf, dsample_t* out ) -{ - Blip_Reader sn; - int bass = sn.begin( blip_buf ); - const dsample_t* in = sample_buf.begin(); - - for ( int n = sample_buf_size >> 1; n--; ) - { - int s = sn.read(); - blargg_long l = (blargg_long) in [0] * 2 + s; - if ( (int16_t) l != l ) - l = 0x7FFF - (l >> 24); - - sn.next( bass ); - blargg_long r = (blargg_long) in [1] * 2 + s; - if ( (int16_t) r != r ) - r = 0x7FFF - (r >> 24); - - in += 2; - out [0] = l; - out [1] = r; - out += 2; - } - - sn.end( blip_buf ); -} - diff --git a/libraries/game-music-emu/gme/Dual_Resampler.h b/libraries/game-music-emu/gme/Dual_Resampler.h deleted file mode 100644 index 512fd97d0..000000000 --- a/libraries/game-music-emu/gme/Dual_Resampler.h +++ /dev/null @@ -1,50 +0,0 @@ -// Combination of Fir_Resampler and Blip_Buffer mixing. Used by Sega FM emulators. - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef DUAL_RESAMPLER_H -#define DUAL_RESAMPLER_H - -#include "Fir_Resampler.h" -#include "Blip_Buffer.h" - -class Dual_Resampler { -public: - Dual_Resampler(); - virtual ~Dual_Resampler(); - - typedef short dsample_t; - - double setup( double oversample, double rolloff, double gain ); - blargg_err_t reset( int max_pairs ); - void resize( int pairs_per_frame ); - void clear(); - - void dual_play( long count, dsample_t* out, Blip_Buffer& ); - -protected: - virtual int play_frame( blip_time_t, int pcm_count, dsample_t* pcm_out ) = 0; -private: - - blargg_vector sample_buf; - int sample_buf_size; - int oversamples_per_frame; - int buf_pos; - int resampler_size; - - Fir_Resampler<12> resampler; - void mix_samples( Blip_Buffer&, dsample_t* ); - void play_frame_( Blip_Buffer&, dsample_t* ); -}; - -inline double Dual_Resampler::setup( double oversample, double rolloff, double gain ) -{ - return resampler.time_ratio( oversample, rolloff, gain * 0.5 ); -} - -inline void Dual_Resampler::clear() -{ - buf_pos = sample_buf_size; - resampler.clear(); -} - -#endif diff --git a/libraries/game-music-emu/gme/Effects_Buffer.cpp b/libraries/game-music-emu/gme/Effects_Buffer.cpp deleted file mode 100644 index 56b0c5b5c..000000000 --- a/libraries/game-music-emu/gme/Effects_Buffer.cpp +++ /dev/null @@ -1,595 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Effects_Buffer.h" - -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -typedef blargg_long fixed_t; - -#define TO_FIXED( f ) fixed_t ((f) * (1L << 15) + 0.5) -#define FMUL( x, y ) (((x) * (y)) >> 15) - -const unsigned echo_size = 4096; -const unsigned echo_mask = echo_size - 1; -BOOST_STATIC_ASSERT( (echo_size & echo_mask) == 0 ); // must be power of 2 - -const unsigned reverb_size = 8192 * 2; -const unsigned reverb_mask = reverb_size - 1; -BOOST_STATIC_ASSERT( (reverb_size & reverb_mask) == 0 ); // must be power of 2 - -Effects_Buffer::config_t::config_t() -{ - pan_1 = -0.15f; - pan_2 = 0.15f; - reverb_delay = 88.0f; - reverb_level = 0.12f; - echo_delay = 61.0f; - echo_level = 0.10f; - delay_variance = 18.0f; - effects_enabled = false; -} - -void Effects_Buffer::set_depth( double d ) -{ - float f = (float) d; - config_t c; - c.pan_1 = -0.6f * f; - c.pan_2 = 0.6f * f; - c.reverb_delay = 880 * 0.1f; - c.echo_delay = 610 * 0.1f; - if ( f > 0.5 ) - f = 0.5; // TODO: more linear reduction of extreme reverb/echo - c.reverb_level = 0.5f * f; - c.echo_level = 0.30f * f; - c.delay_variance = 180 * 0.1f; - c.effects_enabled = (d > 0.0f); - config( c ); -} - -Effects_Buffer::Effects_Buffer( int num_voices, bool center_only ) - : Multi_Buffer( 2*num_voices ) - , max_voices(num_voices) - , bufs(max_voices * (center_only ? (max_buf_count - 4) : max_buf_count)) - , chan_types(max_voices * chan_types_count) - , stereo_remain(0) - , effect_remain(0) - // TODO: Reorder buf_count to be initialized before bufs to factor out channel sizing - , buf_count(max_voices * (center_only ? (max_buf_count - 4) : max_buf_count)) - , effects_enabled(false) - , reverb_buf(max_voices, std::vector(reverb_size)) - , echo_buf(max_voices, std::vector(echo_size)) - , reverb_pos(max_voices) - , echo_pos(max_voices) -{ - set_depth( 0 ); -} - -Effects_Buffer::~Effects_Buffer() -{} - -blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec ) -{ - try - { - for(int i=0; i max ) - return max; - return n; -} - -void Effects_Buffer::config( const config_t& cfg ) -{ - channels_changed(); - - // clear echo and reverb buffers - // ensure the echo/reverb buffers have already been allocated, so this method can be - // called before set_sample_rate is called - if ( !config_.effects_enabled && cfg.effects_enabled && echo_buf[0].size() ) - { - for(int i=0; i chan_types_count-1 ) - out = chan_types_count-1; - } - else if ( !(type & noise_type) && (type & type_index_mask) % 3 != 0 ) - { - out = type & 1; - } - return chan_types [(i%max_voices)*chan_types_count+out]; -} - -void Effects_Buffer::end_frame( blip_time_t clock_count ) -{ - int bufs_used = 0; - int stereo_mask = (config_.effects_enabled ? 0x78 : 0x06); - - const int buf_count_per_voice = buf_count/max_voices; - for ( int v = 0; v < max_voices; v++ ) // foreach voice - { - for ( int i = 0; i < buf_count_per_voice; i++) // foreach buffer of that voice - { - bufs_used |= bufs [v*buf_count_per_voice + i].clear_modified() << i; - bufs [v*buf_count_per_voice + i].end_frame( clock_count ); - - if ( (bufs_used & stereo_mask) && buf_count == max_voices*max_buf_count ) - stereo_remain = max(stereo_remain, bufs [v*buf_count_per_voice + i].samples_avail() + bufs [v*buf_count_per_voice + i].output_latency()); - if ( effects_enabled || config_.effects_enabled ) - effect_remain = max(effect_remain, bufs [v*buf_count_per_voice + i].samples_avail() + bufs [v*buf_count_per_voice + i].output_latency()); - } - bufs_used = 0; - } - - effects_enabled = config_.effects_enabled; -} - -long Effects_Buffer::samples_avail() const -{ - return bufs [0].samples_avail() * 2; -} - -long Effects_Buffer::read_samples( blip_sample_t* out, long total_samples ) -{ - const int n_channels = max_voices * 2; - const int buf_count_per_voice = buf_count/max_voices; - - require( total_samples % n_channels == 0 ); // as many items needed to fill at least one frame - - long remain = bufs [0].samples_avail(); - total_samples = remain = min( remain, total_samples/n_channels ); - - while ( remain ) - { - int active_bufs = buf_count_per_voice; - long count = remain; - - // optimizing mixing to skip any channels which had nothing added - if ( effect_remain ) - { - if ( count > effect_remain ) - count = effect_remain; - - if ( stereo_remain ) - { - mix_enhanced( out, count ); - } - else - { - mix_mono_enhanced( out, count ); - active_bufs = 3; - } - } - else if ( stereo_remain ) - { - mix_stereo( out, count ); - active_bufs = 3; - } - else - { - mix_mono( out, count ); - active_bufs = 1; - } - - out += count * n_channels; - remain -= count; - - stereo_remain -= count; - if ( stereo_remain < 0 ) - stereo_remain = 0; - - effect_remain -= count; - if ( effect_remain < 0 ) - effect_remain = 0; - - // skip the output from any buffers that didn't contribute to the sound output - // during this frame (e.g. if we only render mono then only the very first buf - // is 'active') - for ( int v = 0; v < max_voices; v++ ) // foreach voice - { - for ( int i = 0; i < buf_count_per_voice; i++) // foreach buffer of that voice - { - if ( i < active_bufs ) - bufs [v*buf_count_per_voice + i].remove_samples( count ); - else // keep time synchronized - bufs [v*buf_count_per_voice + i].remove_silence( count ); - } - } - } - - return total_samples * n_channels; -} - -void Effects_Buffer::mix_mono( blip_sample_t* out_, blargg_long count ) -{ - for(int i=0; i> 1; n; --n ) - { - blargg_long cs0 = BLIP_READER_READ( c ); - BLIP_READER_NEXT( c, bass ); - - blargg_long cs1 = BLIP_READER_READ( c ); - BLIP_READER_NEXT( c, bass ); - - if ( (int16_t) cs0 != cs0 ) - cs0 = 0x7FFF - (cs0 >> 24); - ((uint32_t*) out) [i*2+0] = ((uint16_t) cs0) | (uint16_t(cs0) << 16); - - if ( (int16_t) cs1 != cs1 ) - cs1 = 0x7FFF - (cs1 >> 24); - ((uint32_t*) out) [i*2+1] = ((uint16_t) cs1) | (uint16_t(cs1) << 16); - out += max_voices*4; - } - - if ( count & 1 ) - { - int s = BLIP_READER_READ( c ); - BLIP_READER_NEXT( c, bass ); - out [i*2+0] = s; - out [i*2+1] = s; - if ( (int16_t) s != s ) - { - s = 0x7FFF - (s >> 24); - out [i*2+0] = s; - out [i*2+1] = s; - } - } - - BLIP_READER_END( c, bufs [i*max_buf_count+0] ); - } -} - -void Effects_Buffer::mix_stereo( blip_sample_t* out_, blargg_long frames ) -{ - for(int i=0; i> 24); - - if ( (int16_t) right != right ) - right = 0x7FFF - (right >> 24); - - out [i*2+0] = left; - out [i*2+1] = right; - - out += max_voices*2; - - } - - BLIP_READER_END( r, bufs [i*max_buf_count+2] ); - BLIP_READER_END( l, bufs [i*max_buf_count+1] ); - BLIP_READER_END( c, bufs [i*max_buf_count+0] ); - } -} - -void Effects_Buffer::mix_mono_enhanced( blip_sample_t* out_, blargg_long frames ) -{ - for(int i=0; ireverb_buf[i][0]; - blip_sample_t* const echo_buf = &this->echo_buf[i][0]; - int echo_pos = this->echo_pos[i]; - int reverb_pos = this->reverb_pos[i]; - - int count = frames; - while ( count-- ) - { - int sum1_s = BLIP_READER_READ( sq1 ); - int sum2_s = BLIP_READER_READ( sq2 ); - - BLIP_READER_NEXT( sq1, bass ); - BLIP_READER_NEXT( sq2, bass ); - - int new_reverb_l = FMUL( sum1_s, chans.pan_1_levels [0] ) + - FMUL( sum2_s, chans.pan_2_levels [0] ) + - reverb_buf [(reverb_pos + chans.reverb_delay_l) & reverb_mask]; - - int new_reverb_r = FMUL( sum1_s, chans.pan_1_levels [1] ) + - FMUL( sum2_s, chans.pan_2_levels [1] ) + - reverb_buf [(reverb_pos + chans.reverb_delay_r) & reverb_mask]; - - fixed_t reverb_level = chans.reverb_level; - reverb_buf [reverb_pos] = (blip_sample_t) FMUL( new_reverb_l, reverb_level ); - reverb_buf [reverb_pos + 1] = (blip_sample_t) FMUL( new_reverb_r, reverb_level ); - reverb_pos = (reverb_pos + 2) & reverb_mask; - - int sum3_s = BLIP_READER_READ( center ); - BLIP_READER_NEXT( center, bass ); - - int left = new_reverb_l + sum3_s + FMUL( chans.echo_level, - echo_buf [(echo_pos + chans.echo_delay_l) & echo_mask] ); - int right = new_reverb_r + sum3_s + FMUL( chans.echo_level, - echo_buf [(echo_pos + chans.echo_delay_r) & echo_mask] ); - - echo_buf [echo_pos] = sum3_s; - echo_pos = (echo_pos + 1) & echo_mask; - - if ( (int16_t) left != left ) - left = 0x7FFF - (left >> 24); - - if ( (int16_t) right != right ) - right = 0x7FFF - (right >> 24); - - out [i*2+0] = left; - out [i*2+1] = right; - out += max_voices*2; - } - this->reverb_pos[i] = reverb_pos; - this->echo_pos[i] = echo_pos; - - BLIP_READER_END( sq1, bufs [i*max_buf_count+0] ); - BLIP_READER_END( sq2, bufs [i*max_buf_count+1] ); - BLIP_READER_END( center, bufs [i*max_buf_count+2] ); - } -} - -void Effects_Buffer::mix_enhanced( blip_sample_t* out_, blargg_long frames ) -{ - for(int i=0; ireverb_buf[i][0]; - blip_sample_t* const echo_buf = &this->echo_buf[i][0]; - int echo_pos = this->echo_pos[i]; - int reverb_pos = this->reverb_pos[i]; - - int count = frames; - while ( count-- ) - { - int sum1_s = BLIP_READER_READ( sq1 ); - int sum2_s = BLIP_READER_READ( sq2 ); - - BLIP_READER_NEXT( sq1, bass ); - BLIP_READER_NEXT( sq2, bass ); - - int new_reverb_l = FMUL( sum1_s, chans.pan_1_levels [0] ) + - FMUL( sum2_s, chans.pan_2_levels [0] ) + BLIP_READER_READ( l1 ) + - reverb_buf [(reverb_pos + chans.reverb_delay_l) & reverb_mask]; - - int new_reverb_r = FMUL( sum1_s, chans.pan_1_levels [1] ) + - FMUL( sum2_s, chans.pan_2_levels [1] ) + BLIP_READER_READ( r1 ) + - reverb_buf [(reverb_pos + chans.reverb_delay_r) & reverb_mask]; - - BLIP_READER_NEXT( l1, bass ); - BLIP_READER_NEXT( r1, bass ); - - fixed_t reverb_level = chans.reverb_level; - reverb_buf [reverb_pos] = (blip_sample_t) FMUL( new_reverb_l, reverb_level ); - reverb_buf [reverb_pos + 1] = (blip_sample_t) FMUL( new_reverb_r, reverb_level ); - reverb_pos = (reverb_pos + 2) & reverb_mask; - - int sum3_s = BLIP_READER_READ( center ); - BLIP_READER_NEXT( center, bass ); - - int left = new_reverb_l + sum3_s + BLIP_READER_READ( l2 ) + FMUL( chans.echo_level, - echo_buf [(echo_pos + chans.echo_delay_l) & echo_mask] ); - int right = new_reverb_r + sum3_s + BLIP_READER_READ( r2 ) + FMUL( chans.echo_level, - echo_buf [(echo_pos + chans.echo_delay_r) & echo_mask] ); - - BLIP_READER_NEXT( l2, bass ); - BLIP_READER_NEXT( r2, bass ); - - echo_buf [echo_pos] = sum3_s; - echo_pos = (echo_pos + 1) & echo_mask; - - if ( (int16_t) left != left ) - left = 0x7FFF - (left >> 24); - - if ( (int16_t) right != right ) - right = 0x7FFF - (right >> 24); - - out [i*2+0] = left; - out [i*2+1] = right; - - out += max_voices*2; - } - this->reverb_pos[i] = reverb_pos; - this->echo_pos[i] = echo_pos; - - BLIP_READER_END( l1, bufs [i*max_buf_count+3] ); - BLIP_READER_END( r1, bufs [i*max_buf_count+4] ); - BLIP_READER_END( l2, bufs [i*max_buf_count+5] ); - BLIP_READER_END( r2, bufs [i*max_buf_count+6] ); - BLIP_READER_END( sq1, bufs [i*max_buf_count+0] ); - BLIP_READER_END( sq2, bufs [i*max_buf_count+1] ); - BLIP_READER_END( center, bufs [i*max_buf_count+2] ); - } -} - diff --git a/libraries/game-music-emu/gme/Effects_Buffer.h b/libraries/game-music-emu/gme/Effects_Buffer.h deleted file mode 100644 index ec634d622..000000000 --- a/libraries/game-music-emu/gme/Effects_Buffer.h +++ /dev/null @@ -1,90 +0,0 @@ -// Multi-channel effects buffer with panning, echo and reverb - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef EFFECTS_BUFFER_H -#define EFFECTS_BUFFER_H - -#include "Multi_Buffer.h" - -#include - -// Effects_Buffer uses several buffers and outputs stereo sample pairs. -class Effects_Buffer : public Multi_Buffer { -public: - // nVoices indicates the number of voices for which buffers will be allocated - // to make Effects_Buffer work as "mix everything to one", nVoices will be 1 - // If center_only is true, only center buffers are created and - // less memory is used. - Effects_Buffer( int nVoices = 1, bool center_only = false ); - - // Channel Effect Center Pan - // --------------------------------- - // 0,5 reverb pan_1 - // 1,6 reverb pan_2 - // 2,7 echo - - // 3 echo - - // 4 echo - - - // Channel configuration - struct config_t { - double pan_1; // -1.0 = left, 0.0 = center, 1.0 = right - double pan_2; - double echo_delay; // msec - double echo_level; // 0.0 to 1.0 - double reverb_delay; // msec - double delay_variance; // difference between left/right delays (msec) - double reverb_level; // 0.0 to 1.0 - bool effects_enabled; // if false, use optimized simple mixer - config_t(); - }; - - // Set configuration of buffer - virtual void config( const config_t& ); - void set_depth( double ); - -public: - ~Effects_Buffer(); - blargg_err_t set_sample_rate( long samples_per_sec, int msec = blip_default_length ); - void clock_rate( long ); - void bass_freq( int ); - void clear(); - channel_t channel( int, int ); - void end_frame( blip_time_t ); - long read_samples( blip_sample_t*, long ); - long samples_avail() const; -private: - typedef long fixed_t; - int max_voices; - enum { max_buf_count = 7 }; - std::vector bufs; - enum { chan_types_count = 3 }; - std::vector chan_types; - config_t config_; - long stereo_remain; - long effect_remain; - int buf_count; - bool effects_enabled; - - std::vector > reverb_buf; - std::vector > echo_buf; - std::vector reverb_pos; - std::vector echo_pos; - - struct { - fixed_t pan_1_levels [2]; - fixed_t pan_2_levels [2]; - int echo_delay_l; - int echo_delay_r; - fixed_t echo_level; - int reverb_delay_l; - int reverb_delay_r; - fixed_t reverb_level; - } chans; - - void mix_mono( blip_sample_t*, blargg_long ); - void mix_stereo( blip_sample_t*, blargg_long ); - void mix_enhanced( blip_sample_t*, blargg_long ); - void mix_mono_enhanced( blip_sample_t*, blargg_long ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Fir_Resampler.cpp b/libraries/game-music-emu/gme/Fir_Resampler.cpp deleted file mode 100644 index d8dd6837c..000000000 --- a/libraries/game-music-emu/gme/Fir_Resampler.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Fir_Resampler.h" - -#include -#include -#include -#include - -/* Copyright (C) 2004-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -#undef PI -#define PI 3.1415926535897932384626433832795029 - -static void gen_sinc( double rolloff, int width, double offset, double spacing, double scale, - int count, short* out ) -{ - double const maxh = 256; - double const step = PI / maxh * spacing; - double const to_w = maxh * 2 / width; - double const pow_a_n = pow( rolloff, maxh ); - scale /= maxh * 2; - - double angle = (count / 2 - 1 + offset) * -step; - while ( count-- ) - { - *out++ = 0; - double w = angle * to_w; - if ( fabs( w ) < PI ) - { - double rolloff_cos_a = rolloff * cos( angle ); - double num = 1 - rolloff_cos_a - - pow_a_n * cos( maxh * angle ) + - pow_a_n * rolloff * cos( (maxh - 1) * angle ); - double den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; - double sinc = scale * num / den - scale; - - out [-1] = (short) (cos( w ) * sinc + sinc); - } - angle += step; - } -} - -Fir_Resampler_::Fir_Resampler_( int width, sample_t* impulses_ ) : - width_( width ), - write_offset( width * stereo - stereo ), - impulses( impulses_ ) -{ - write_pos = 0; - res = 1; - imp_phase = 0; - skip_bits = 0; - step = stereo; - ratio_ = 1.0; -} - -Fir_Resampler_::~Fir_Resampler_() { } - -void Fir_Resampler_::clear() -{ - imp_phase = 0; - if ( buf.size() ) - { - write_pos = &buf [write_offset]; - memset( buf.begin(), 0, write_offset * sizeof buf [0] ); - } -} - -blargg_err_t Fir_Resampler_::buffer_size( int new_size ) -{ - RETURN_ERR( buf.resize( new_size + write_offset ) ); - clear(); - return 0; -} - -double Fir_Resampler_::time_ratio( double new_factor, double rolloff, double gain ) -{ - ratio_ = new_factor; - - double fstep = 0.0; - { - double least_error = 2; - double pos = 0; - res = -1; - for ( int r = 1; r <= max_res; r++ ) - { - pos += ratio_; - double nearest = floor( pos + 0.5 ); - double error = fabs( pos - nearest ); - if ( error < least_error ) - { - res = r; - fstep = nearest / res; - least_error = error; - } - } - } - - skip_bits = 0; - - step = stereo * (int) floor( fstep ); - - ratio_ = fstep; - fstep = fmod( fstep, 1.0 ); - - double filter = (ratio_ < 1.0) ? 1.0 : 1.0 / ratio_; - double pos = 0.0; - input_per_cycle = 0; - for ( int i = 0; i < res; i++ ) - { - gen_sinc( rolloff, int (width_ * filter + 1) & ~1, pos, filter, - double (0x7FFF * gain * filter), - (int) width_, impulses + i * width_ ); - - pos += fstep; - input_per_cycle += step; - if ( pos >= 0.9999999 ) - { - pos -= 1.0; - skip_bits |= 1 << i; - input_per_cycle++; - } - } - - clear(); - - return ratio_; -} - -int Fir_Resampler_::input_needed( blargg_long output_count ) const -{ - blargg_long input_count = 0; - - unsigned long skip = skip_bits >> imp_phase; - int remain = res - imp_phase; - while ( (output_count -= 2) > 0 ) - { - input_count += step + (skip & 1) * stereo; - skip >>= 1; - if ( !--remain ) - { - skip = skip_bits; - remain = res; - } - output_count -= 2; - } - - long input_extra = input_count - (write_pos - &buf [(width_ - 1) * stereo]); - if ( input_extra < 0 ) - input_extra = 0; - return input_extra; -} - -int Fir_Resampler_::avail_( blargg_long input_count ) const -{ - int cycle_count = input_count / input_per_cycle; - int output_count = cycle_count * res * stereo; - input_count -= cycle_count * input_per_cycle; - - blargg_ulong skip = skip_bits >> imp_phase; - int remain = res - imp_phase; - while ( input_count >= 0 ) - { - input_count -= step + (skip & 1) * stereo; - skip >>= 1; - if ( !--remain ) - { - skip = skip_bits; - remain = res; - } - output_count += 2; - } - return output_count; -} - -int Fir_Resampler_::skip_input( long count ) -{ - int remain = write_pos - buf.begin(); - int max_count = remain - width_ * stereo; - if ( count > max_count ) - count = max_count; - - remain -= count; - write_pos = &buf [remain]; - memmove( buf.begin(), &buf [count], remain * sizeof buf [0] ); - - return count; -} diff --git a/libraries/game-music-emu/gme/Fir_Resampler.h b/libraries/game-music-emu/gme/Fir_Resampler.h deleted file mode 100644 index d637ec41c..000000000 --- a/libraries/game-music-emu/gme/Fir_Resampler.h +++ /dev/null @@ -1,171 +0,0 @@ -// Finite impulse response (FIR) resampler with adjustable FIR size - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef FIR_RESAMPLER_H -#define FIR_RESAMPLER_H - -#include "blargg_common.h" -#include - -class Fir_Resampler_ { -public: - - // Use Fir_Resampler (below) - - // Set input/output resampling ratio and optionally low-pass rolloff and gain. - // Returns actual ratio used (rounded to internal precision). - double time_ratio( double factor, double rolloff = 0.999, double gain = 1.0 ); - - // Current input/output ratio - double ratio() const { return ratio_; } - -// Input - - typedef short sample_t; - - // Resize and clear input buffer - blargg_err_t buffer_size( int ); - - // Clear input buffer. At least two output samples will be available after - // two input samples are written. - void clear(); - - // Number of input samples that can be written - int max_write() const { return buf.end() - write_pos; } - - // Pointer to place to write input samples - sample_t* buffer() { return write_pos; } - - // Notify resampler that 'count' input samples have been written - void write( long count ); - - // Number of input samples in buffer - int written() const { return write_pos - &buf [write_offset]; } - - // Skip 'count' input samples. Returns number of samples actually skipped. - int skip_input( long count ); - -// Output - - // Number of extra input samples needed until 'count' output samples are available - int input_needed( blargg_long count ) const; - - // Number of output samples available - int avail() const { return avail_( write_pos - &buf [width_ * stereo] ); } - -public: - ~Fir_Resampler_(); -protected: - enum { stereo = 2 }; - enum { max_res = 32 }; - blargg_vector buf; - sample_t* write_pos; - int res; - int imp_phase; - int const width_; - int const write_offset; - blargg_ulong skip_bits; - int step; - int input_per_cycle; - double ratio_; - sample_t* impulses; - - Fir_Resampler_( int width, sample_t* ); - int avail_( blargg_long input_count ) const; -}; - -// Width is number of points in FIR. Must be even and 4 or more. More points give -// better quality and rolloff effectiveness, and take longer to calculate. -template -class Fir_Resampler : public Fir_Resampler_ { - BOOST_STATIC_ASSERT( width >= 4 && width % 2 == 0 ); - short impulses [max_res] [width]; -public: - Fir_Resampler() : Fir_Resampler_( width, impulses [0] ) { } - - // Read at most 'count' samples. Returns number of samples actually read. - typedef short sample_t; - int read( sample_t* out, blargg_long count ); -}; - -// End of public interface - -inline void Fir_Resampler_::write( long count ) -{ - write_pos += count; - assert( write_pos <= buf.end() ); -} - -template -int Fir_Resampler::read( sample_t* out_begin, blargg_long count ) -{ - sample_t* out = out_begin; - const sample_t* in = buf.begin(); - sample_t* end_pos = write_pos; - blargg_ulong skip = skip_bits >> imp_phase; - sample_t const* imp = impulses [imp_phase]; - int remain = res - imp_phase; - int const step = this->step; - - count >>= 1; - - if ( end_pos - in >= width * stereo ) - { - end_pos -= width * stereo; - do - { - count--; - - // accumulate in extended precision - blargg_long l = 0; - blargg_long r = 0; - - const sample_t* i = in; - if ( count < 0 ) - break; - - for ( int n = width / 2; n; --n ) - { - int pt0 = imp [0]; - l += pt0 * i [0]; - r += pt0 * i [1]; - int pt1 = imp [1]; - imp += 2; - l += pt1 * i [2]; - r += pt1 * i [3]; - i += 4; - } - - remain--; - - l >>= 15; - r >>= 15; - - in += (skip * stereo) & stereo; - skip >>= 1; - in += step; - - if ( !remain ) - { - imp = impulses [0]; - skip = skip_bits; - remain = res; - } - - out [0] = (sample_t) l; - out [1] = (sample_t) r; - out += 2; - } - while ( in <= end_pos ); - } - - imp_phase = res - remain; - - int left = write_pos - in; - write_pos = &buf [left]; - memmove( buf.begin(), in, left * sizeof *in ); - - return out - out_begin; -} - -#endif diff --git a/libraries/game-music-emu/gme/Gb_Apu.cpp b/libraries/game-music-emu/gme/Gb_Apu.cpp deleted file mode 100644 index 82a9cc1b6..000000000 --- a/libraries/game-music-emu/gme/Gb_Apu.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Gb_Snd_Emu 0.1.5. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -unsigned const vol_reg = 0xFF24; -unsigned const status_reg = 0xFF26; - -Gb_Apu::Gb_Apu() -{ - square1.synth = &square_synth; - square2.synth = &square_synth; - wave.synth = &other_synth; - noise.synth = &other_synth; - - oscs [0] = &square1; - oscs [1] = &square2; - oscs [2] = &wave; - oscs [3] = &noise; - - for ( int i = 0; i < osc_count; i++ ) - { - Gb_Osc& osc = *oscs [i]; - osc.regs = ®s [i * 5]; - osc.output = 0; - osc.outputs [0] = 0; - osc.outputs [1] = 0; - osc.outputs [2] = 0; - osc.outputs [3] = 0; - } - - set_tempo( 1.0 ); - volume( 1.0 ); - reset(); -} - -void Gb_Apu::treble_eq( const blip_eq_t& eq ) -{ - square_synth.treble_eq( eq ); - other_synth.treble_eq( eq ); -} - -void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - require( (unsigned) index < osc_count ); - require( (center && left && right) || (!center && !left && !right) ); - Gb_Osc& osc = *oscs [index]; - osc.outputs [1] = right; - osc.outputs [2] = left; - osc.outputs [3] = center; - osc.output = osc.outputs [osc.output_select]; -} - -void Gb_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, center, left, right ); -} - -void Gb_Apu::update_volume() -{ - // TODO: doesn't handle differing left/right global volume (support would - // require modification to all oscillator code) - int data = regs [vol_reg - start_addr]; - double vol = (max( data & 7, data >> 4 & 7 ) + 1) * volume_unit; - square_synth.volume( vol ); - other_synth.volume( vol ); -} - -static unsigned char const powerup_regs [0x20] = { - 0x80,0x3F,0x00,0xFF,0xBF, // square 1 - 0xFF,0x3F,0x00,0xFF,0xBF, // square 2 - 0x7F,0xFF,0x9F,0xFF,0xBF, // wave - 0xFF,0xFF,0x00,0x00,0xBF, // noise - 0x00, // left/right enables - 0x77, // master volume - 0x80, // power - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF -}; - -void Gb_Apu::set_tempo( double t ) -{ - frame_period = 4194304 / 256; // 256 Hz - if ( t != 1.0 ) - frame_period = blip_time_t (frame_period / t); -} - -void Gb_Apu::reset() -{ - next_frame_time = 0; - last_time = 0; - frame_count = 0; - - square1.reset(); - square2.reset(); - wave.reset(); - noise.reset(); - noise.bits = 1; - wave.wave_pos = 0; - - // avoid click at beginning - regs [vol_reg - start_addr] = 0x77; - update_volume(); - - regs [status_reg - start_addr] = 0x01; // force power - write_register( 0, status_reg, 0x00 ); - - static unsigned char const initial_wave [] = { - 0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table - 0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA - }; - memcpy( wave.wave, initial_wave, sizeof initial_wave ); -} - -void Gb_Apu::run_until( blip_time_t end_time ) -{ - require( end_time >= last_time ); // end_time must not be before previous time - if ( end_time == last_time ) - return; - - while ( true ) - { - blip_time_t time = next_frame_time; - if ( time > end_time ) - time = end_time; - - // run oscillators - for ( int i = 0; i < osc_count; ++i ) - { - Gb_Osc& osc = *oscs [i]; - if ( osc.output ) - { - osc.output->set_modified(); // TODO: misses optimization opportunities? - int playing = false; - if ( osc.enabled && osc.volume && - (!(osc.regs [4] & osc.len_enabled_mask) || osc.length) ) - playing = -1; - switch ( i ) - { - case 0: square1.run( last_time, time, playing ); break; - case 1: square2.run( last_time, time, playing ); break; - case 2: wave .run( last_time, time, playing ); break; - case 3: noise .run( last_time, time, playing ); break; - } - } - } - last_time = time; - - if ( time == end_time ) - break; - - next_frame_time += frame_period; - - // 256 Hz actions - square1.clock_length(); - square2.clock_length(); - wave.clock_length(); - noise.clock_length(); - - frame_count = (frame_count + 1) & 3; - if ( frame_count == 0 ) - { - // 64 Hz actions - square1.clock_envelope(); - square2.clock_envelope(); - noise.clock_envelope(); - } - - if ( frame_count & 1 ) - square1.clock_sweep(); // 128 Hz action - } -} - -void Gb_Apu::end_frame( blip_time_t end_time ) -{ - if ( end_time > last_time ) - run_until( end_time ); - - assert( next_frame_time >= end_time ); - next_frame_time -= end_time; - - assert( last_time >= end_time ); - last_time -= end_time; -} - -void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data ) -{ - require( (unsigned) data < 0x100 ); - - int reg = addr - start_addr; - if ( (unsigned) reg >= register_count ) - return; - - run_until( time ); - - int old_reg = regs [reg]; - regs [reg] = data; - - if ( addr < vol_reg ) - { - write_osc( reg / 5, reg, data ); - } - else if ( addr == vol_reg && data != old_reg ) // global volume - { - // return all oscs to 0 - for ( int i = 0; i < osc_count; i++ ) - { - Gb_Osc& osc = *oscs [i]; - int amp = osc.last_amp; - osc.last_amp = 0; - if ( amp && osc.enabled && osc.output ) - other_synth.offset( time, -amp, osc.output ); - } - - if ( wave.outputs [3] ) - other_synth.offset( time, 30, wave.outputs [3] ); - - update_volume(); - - if ( wave.outputs [3] ) - other_synth.offset( time, -30, wave.outputs [3] ); - - // oscs will update with new amplitude when next run - } - else if ( addr == 0xFF25 || addr == status_reg ) - { - int mask = (regs [status_reg - start_addr] & 0x80) ? ~0 : 0; - int flags = regs [0xFF25 - start_addr] & mask; - - // left/right assignments - for ( int i = 0; i < osc_count; i++ ) - { - Gb_Osc& osc = *oscs [i]; - osc.enabled &= mask; - int bits = flags >> i; - Blip_Buffer* old_output = osc.output; - osc.output_select = (bits >> 3 & 2) | (bits & 1); - osc.output = osc.outputs [osc.output_select]; - if ( osc.output != old_output ) - { - int amp = osc.last_amp; - osc.last_amp = 0; - if ( amp && old_output ) - other_synth.offset( time, -amp, old_output ); - } - } - - if ( addr == status_reg && data != old_reg ) - { - if ( !(data & 0x80) ) - { - for ( unsigned i = 0; i < sizeof powerup_regs; i++ ) - { - if ( i != status_reg - start_addr ) - write_register( time, i + start_addr, powerup_regs [i] ); - } - } - else - { - //debug_printf( "APU powered on\n" ); - } - } - } - else if ( addr >= 0xFF30 ) - { - int index = (addr & 0x0F) * 2; - wave.wave [index] = data >> 4; - wave.wave [index + 1] = data & 0x0F; - } -} - -int Gb_Apu::read_register( blip_time_t time, unsigned addr ) -{ - run_until( time ); - - int index = addr - start_addr; - require( (unsigned) index < register_count ); - int data = regs [index]; - - if ( addr == status_reg ) - { - data = (data & 0x80) | 0x70; - for ( int i = 0; i < osc_count; i++ ) - { - const Gb_Osc& osc = *oscs [i]; - if ( osc.enabled && (osc.length || !(osc.regs [4] & osc.len_enabled_mask)) ) - data |= 1 << i; - } - } - - return data; -} diff --git a/libraries/game-music-emu/gme/Gb_Apu.h b/libraries/game-music-emu/gme/Gb_Apu.h deleted file mode 100644 index 9b251262f..000000000 --- a/libraries/game-music-emu/gme/Gb_Apu.h +++ /dev/null @@ -1,90 +0,0 @@ -// Nintendo Game Boy PAPU sound chip emulator - -// Gb_Snd_Emu 0.1.5 -#ifndef GB_APU_H -#define GB_APU_H - -#include "Gb_Oscs.h" - -class Gb_Apu { -public: - - // Set overall volume of all oscillators, where 1.0 is full volume - void volume( double ); - - // Set treble equalization - void treble_eq( const blip_eq_t& ); - - // Outputs can be assigned to a single buffer for mono output, or to three - // buffers for stereo output (using Stereo_Buffer to do the mixing). - - // Assign all oscillator outputs to specified buffer(s). If buffer - // is NULL, silences all oscillators. - void output( Blip_Buffer* mono ); - void output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ); - - // Assign single oscillator output to buffer(s). Valid indicies are 0 to 3, - // which refer to Square 1, Square 2, Wave, and Noise. If buffer is NULL, - // silences oscillator. - enum { osc_count = 4 }; - void osc_output( int index, Blip_Buffer* mono ); - void osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ); - - // Reset oscillators and internal state - void reset(); - - // Reads and writes at addr must satisfy start_addr <= addr <= end_addr - enum { start_addr = 0xFF10 }; - enum { end_addr = 0xFF3F }; - enum { register_count = end_addr - start_addr + 1 }; - - // Write 'data' to address at specified time - void write_register( blip_time_t, unsigned addr, int data ); - - // Read from address at specified time - int read_register( blip_time_t, unsigned addr ); - - // Run all oscillators up to specified time, end current time frame, then - // start a new frame at time 0. - void end_frame( blip_time_t ); - - void set_tempo( double ); - -public: - Gb_Apu(); -private: - // noncopyable - Gb_Apu( const Gb_Apu& ); - Gb_Apu& operator = ( const Gb_Apu& ); - - Gb_Osc* oscs [osc_count]; - blip_time_t next_frame_time; - blip_time_t last_time; - blip_time_t frame_period; - double volume_unit; - int frame_count; - - Gb_Square square1; - Gb_Square square2; - Gb_Wave wave; - Gb_Noise noise; - uint8_t regs [register_count]; - Gb_Square::Synth square_synth; // used by squares - Gb_Wave::Synth other_synth; // used by wave and noise - - void update_volume(); - void run_until( blip_time_t ); - void write_osc( int index, int reg, int data ); -}; - -inline void Gb_Apu::output( Blip_Buffer* b ) { output( b, b, b ); } - -inline void Gb_Apu::osc_output( int i, Blip_Buffer* b ) { osc_output( i, b, b, b ); } - -inline void Gb_Apu::volume( double vol ) -{ - volume_unit = 0.60 / osc_count / 15 /*steps*/ / 2 /*?*/ / 8 /*master vol range*/ * vol; - update_volume(); -} - -#endif diff --git a/libraries/game-music-emu/gme/Gb_Cpu.cpp b/libraries/game-music-emu/gme/Gb_Cpu.cpp deleted file mode 100644 index db1abee58..000000000 --- a/libraries/game-music-emu/gme/Gb_Cpu.cpp +++ /dev/null @@ -1,1054 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Gb_Cpu.h" - -#include - -//#include "gb_cpu_log.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 "gb_cpu_io.h" - -#include "blargg_source.h" - -// Common instructions: -// -// 365880 FA LD A,IND16 -// 355863 20 JR NZ -// 313655 21 LD HL,IMM -// 274580 28 JR Z -// 252878 FE CMP IMM -// 230541 7E LD A,(HL) -// 226209 2A LD A,(HL+) -// 217467 CD CALL -// 212034 C9 RET -// 208376 CB CB prefix -// -// 27486 CB 7E BIT 7,(HL) -// 15925 CB 76 BIT 6,(HL) -// 13035 CB 19 RR C -// 11557 CB 7F BIT 7,A -// 10898 CB 37 SWAP A -// 10208 CB 66 BIT 4,(HL) - -#if BLARGG_NONPORTABLE - #define PAGE_OFFSET( addr ) (addr) -#else - #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) -#endif - -inline void Gb_Cpu::set_code_page( int i, uint8_t* p ) -{ - state->code_map [i] = p - PAGE_OFFSET( i * (blargg_long) page_size ); -} - -void Gb_Cpu::reset( void* unmapped ) -{ - check( state == &state_ ); - state = &state_; - - state_.remain = 0; - - for ( int i = 0; i < page_count + 1; i++ ) - set_code_page( i, (uint8_t*) unmapped ); - - memset( &r, 0, sizeof r ); - //interrupts_enabled = false; - - blargg_verify_byte_order(); -} - -void Gb_Cpu::map_code( gb_addr_t start, unsigned size, void* data ) -{ - // address range must begin and end on page boundaries - require( start % page_size == 0 ); - require( size % page_size == 0 ); - - unsigned first_page = start / page_size; - for ( unsigned i = size / page_size; i--; ) - set_code_page( first_page + i, (uint8_t*) data + i * page_size ); -} - -#define READ( addr ) CPU_READ( this, (addr), s.remain ) -#define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), s.remain );} -#define READ_FAST( addr, out ) CPU_READ_FAST( this, (addr), s.remain, out ) -#define READ_PROG( addr ) (s.code_map [(addr) >> page_shift] [PAGE_OFFSET( addr )]) - -unsigned const z_flag = 0x80; -unsigned const n_flag = 0x40; -unsigned const h_flag = 0x20; -unsigned const c_flag = 0x10; - -bool Gb_Cpu::run( blargg_long cycle_count ) -{ - state_.remain = blargg_ulong (cycle_count + clocks_per_instr) / clocks_per_instr; - state_t s; - this->state = &s; - memcpy( &s, &this->state_, sizeof s ); - -#if BLARGG_BIG_ENDIAN - #define R8( n ) (r8_ [n]) -#elif BLARGG_LITTLE_ENDIAN - #define R8( n ) (r8_ [(n) ^ 1]) -#else - #error "Byte order of CPU must be known" -#endif - - union { - core_regs_t rg; // individual registers - - struct { - uint16_t bc, de, hl, unused; // pairs - } rp; - - uint8_t r8_ [8]; // indexed registers (use R8 macro due to endian dependence) - uint16_t r16 [4]; // indexed pairs - }; - BOOST_STATIC_ASSERT( sizeof rg == 8 && sizeof rp == 8 ); - - rg = r; - unsigned pc = r.pc; - unsigned sp = r.sp; - unsigned flags = r.flags; - -loop: - - check( (unsigned long) pc < 0x10000 ); - check( (unsigned long) sp < 0x10000 ); - check( (flags & ~0xF0) == 0 ); - - uint8_t const* instr = s.code_map [pc >> page_shift]; - unsigned op; - - // TODO: eliminate this special case - #if BLARGG_NONPORTABLE - op = instr [pc]; - pc++; - instr += pc; - #else - instr += PAGE_OFFSET( pc ); - op = *instr++; - pc++; - #endif - -#define GET_ADDR() GET_LE16( instr ) - - if ( !--s.remain ) - goto stop; - - unsigned data; - data = *instr; - - #ifdef GB_CPU_LOG_H - gb_cpu_log( "new", pc - 1, op, data, instr [1] ); - #endif - - switch ( op ) - { - -// TODO: more efficient way to handle negative branch that wraps PC around -#define BRANCH( cond )\ -{\ - pc++;\ - int offset = (int8_t) data;\ - if ( !(cond) ) goto loop;\ - pc = uint16_t (pc + offset);\ - goto loop;\ -} - -// Most Common - - case 0x20: // JR NZ - BRANCH( !(flags & z_flag) ) - - case 0x21: // LD HL,IMM (common) - rp.hl = GET_ADDR(); - pc += 2; - goto loop; - - case 0x28: // JR Z - BRANCH( flags & z_flag ) - - { - unsigned temp; - case 0xF0: // LD A,(0xFF00+imm) - temp = data | 0xFF00; - pc++; - goto ld_a_ind_comm; - - case 0xF2: // LD A,(0xFF00+C) - temp = rg.c | 0xFF00; - goto ld_a_ind_comm; - - case 0x0A: // LD A,(BC) - temp = rp.bc; - goto ld_a_ind_comm; - - case 0x3A: // LD A,(HL-) - temp = rp.hl; - rp.hl = temp - 1; - goto ld_a_ind_comm; - - case 0x1A: // LD A,(DE) - temp = rp.de; - goto ld_a_ind_comm; - - case 0x2A: // LD A,(HL+) (common) - temp = rp.hl; - rp.hl = temp + 1; - goto ld_a_ind_comm; - - case 0xFA: // LD A,IND16 (common) - temp = GET_ADDR(); - pc += 2; - ld_a_ind_comm: - READ_FAST( temp, rg.a ); - goto loop; - } - - case 0xBE: // CMP (HL) - data = READ( rp.hl ); - goto cmp_comm; - - case 0xB8: // CMP B - case 0xB9: // CMP C - case 0xBA: // CMP D - case 0xBB: // CMP E - case 0xBC: // CMP H - case 0xBD: // CMP L - data = R8( op & 7 ); - goto cmp_comm; - - case 0xFE: // CMP IMM - pc++; - cmp_comm: - op = rg.a; - data = op - data; - sub_set_flags: - flags = ((op & 15) - (data & 15)) & h_flag; - flags |= (data >> 4) & c_flag; - flags |= n_flag; - if ( data & 0xFF ) - goto loop; - flags |= z_flag; - goto loop; - - case 0x46: // LD B,(HL) - case 0x4E: // LD C,(HL) - case 0x56: // LD D,(HL) - case 0x5E: // LD E,(HL) - case 0x66: // LD H,(HL) - case 0x6E: // LD L,(HL) - case 0x7E:{// LD A,(HL) - unsigned addr = rp.hl; - READ_FAST( addr, R8( (op >> 3) & 7 ) ); - goto loop; - } - - case 0xC4: // CNZ (next-most-common) - pc += 2; - if ( flags & z_flag ) - goto loop; - call: - pc -= 2; - case 0xCD: // CALL (most-common) - data = pc + 2; - pc = GET_ADDR(); - push: - sp = (sp - 1) & 0xFFFF; - WRITE( sp, data >> 8 ); - sp = (sp - 1) & 0xFFFF; - WRITE( sp, data & 0xFF ); - goto loop; - - case 0xC8: // RNZ (next-most-common) - if ( !(flags & z_flag) ) - goto loop; - case 0xC9: // RET (most common) - ret: - pc = READ( sp ); - pc += 0x100 * READ( sp + 1 ); - sp = (sp + 2) & 0xFFFF; - goto loop; - - case 0x00: // NOP - case 0x40: // LD B,B - case 0x49: // LD C,C - case 0x52: // LD D,D - case 0x5B: // LD E,E - case 0x64: // LD H,H - case 0x6D: // LD L,L - case 0x7F: // LD A,A - goto loop; - -// CB Instructions - - case 0xCB: - pc++; - // now data is the opcode - switch ( data ) { - - { - int temp; - case 0x46: // BIT b,(HL) - case 0x4E: - case 0x56: - case 0x5E: - case 0x66: - case 0x6E: - case 0x76: - case 0x7E: - { - unsigned addr = rp.hl; - READ_FAST( addr, temp ); - goto bit_comm; - } - - case 0x40: case 0x41: case 0x42: case 0x43: // BIT b,r - case 0x44: case 0x45: case 0x47: case 0x48: - case 0x49: case 0x4A: case 0x4B: case 0x4C: - case 0x4D: case 0x4F: case 0x50: case 0x51: - case 0x52: case 0x53: case 0x54: case 0x55: - case 0x57: case 0x58: case 0x59: case 0x5A: - case 0x5B: case 0x5C: case 0x5D: case 0x5F: - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x67: case 0x68: - case 0x69: case 0x6A: case 0x6B: case 0x6C: - case 0x6D: case 0x6F: case 0x70: case 0x71: - case 0x72: case 0x73: case 0x74: case 0x75: - case 0x77: case 0x78: case 0x79: case 0x7A: - case 0x7B: case 0x7C: case 0x7D: case 0x7F: - temp = R8( data & 7 ); - bit_comm: - int bit = (~data >> 3) & 7; - flags &= ~n_flag; - flags |= h_flag | z_flag; - flags ^= (temp << bit) & z_flag; - goto loop; - } - - case 0x86: // RES b,(HL) - case 0x8E: - case 0x96: - case 0x9E: - case 0xA6: - case 0xAE: - case 0xB6: - case 0xBE: - case 0xC6: // SET b,(HL) - case 0xCE: - case 0xD6: - case 0xDE: - case 0xE6: - case 0xEE: - case 0xF6: - case 0xFE: { - int temp = READ( rp.hl ); - int bit = 1 << ((data >> 3) & 7); - temp &= ~bit; - if ( !(data & 0x40) ) - bit = 0; - WRITE( rp.hl, temp | bit ); - goto loop; - } - - case 0xC0: case 0xC1: case 0xC2: case 0xC3: // SET b,r - case 0xC4: case 0xC5: case 0xC7: case 0xC8: - case 0xC9: case 0xCA: case 0xCB: case 0xCC: - case 0xCD: case 0xCF: case 0xD0: case 0xD1: - case 0xD2: case 0xD3: case 0xD4: case 0xD5: - case 0xD7: case 0xD8: case 0xD9: case 0xDA: - case 0xDB: case 0xDC: case 0xDD: case 0xDF: - case 0xE0: case 0xE1: case 0xE2: case 0xE3: - case 0xE4: case 0xE5: case 0xE7: case 0xE8: - case 0xE9: case 0xEA: case 0xEB: case 0xEC: - case 0xED: case 0xEF: case 0xF0: case 0xF1: - case 0xF2: case 0xF3: case 0xF4: case 0xF5: - case 0xF7: case 0xF8: case 0xF9: case 0xFA: - case 0xFB: case 0xFC: case 0xFD: case 0xFF: - R8( data & 7 ) |= 1 << ((data >> 3) & 7); - goto loop; - - case 0x80: case 0x81: case 0x82: case 0x83: // RES b,r - case 0x84: case 0x85: case 0x87: case 0x88: - case 0x89: case 0x8A: case 0x8B: case 0x8C: - case 0x8D: case 0x8F: case 0x90: case 0x91: - case 0x92: case 0x93: case 0x94: case 0x95: - case 0x97: case 0x98: case 0x99: case 0x9A: - case 0x9B: case 0x9C: case 0x9D: case 0x9F: - case 0xA0: case 0xA1: case 0xA2: case 0xA3: - case 0xA4: case 0xA5: case 0xA7: case 0xA8: - case 0xA9: case 0xAA: case 0xAB: case 0xAC: - case 0xAD: case 0xAF: case 0xB0: case 0xB1: - case 0xB2: case 0xB3: case 0xB4: case 0xB5: - case 0xB7: case 0xB8: case 0xB9: case 0xBA: - case 0xBB: case 0xBC: case 0xBD: case 0xBF: - R8( data & 7 ) &= ~(1 << ((data >> 3) & 7)); - goto loop; - - { - int temp; - case 0x36: // SWAP (HL) - temp = READ( rp.hl ); - goto swap_comm; - - case 0x30: // SWAP B - case 0x31: // SWAP C - case 0x32: // SWAP D - case 0x33: // SWAP E - case 0x34: // SWAP H - case 0x35: // SWAP L - case 0x37: // SWAP A - temp = R8( data & 7 ); - swap_comm: - op = (temp >> 4) | (temp << 4); - flags = 0; - goto shift_comm; - } - -// Shift/Rotate - - case 0x06: // RLC (HL) - case 0x16: // RL (HL) - case 0x26: // SLA (HL) - op = READ( rp.hl ); - goto rl_comm; - - case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x27: // SLA A - case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x07: // RLC A - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x17: // RL A - op = R8( data & 7 ); - goto rl_comm; - - case 0x3E: // SRL (HL) - data += 0x10; // bump up to 0x4n to avoid preserving sign bit - case 0x1E: // RR (HL) - case 0x0E: // RRC (HL) - case 0x2E: // SRA (HL) - op = READ( rp.hl ); - goto rr_comm; - - case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3F: // SRL A - data += 0x10; // bump up to 0x4n - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1F: // RR A - case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0F: // RRC A - case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2F: // SRA A - op = R8( data & 7 ); - goto rr_comm; - - } // CB op - assert( false ); // unhandled CB op - - case 0x07: // RLCA - case 0x17: // RLA - data = op; - op = rg.a; - rl_comm: - op <<= 1; - op |= ((data & flags) >> 4) & 1; // RL and carry is set - flags = (op >> 4) & c_flag; // C = bit shifted out - if ( data < 0x10 ) // RLC - op |= op >> 8; - // SLA doesn't fill lower bit - goto shift_comm; - - case 0x0F: // RRCA - case 0x1F: // RRA - data = op; - op = rg.a; - rr_comm: - op |= (data & flags) << 4; // RR and carry is set - flags = (op << 4) & c_flag; // C = bit shifted out - if ( data < 0x10 ) // RRC - op |= op << 8; - op >>= 1; - if ( data & 0x20 ) // SRA propagates sign bit - op |= (op << 1) & 0x80; - shift_comm: - data &= 7; - if ( !(op & 0xFF) ) - flags |= z_flag; - if ( data == 6 ) - goto write_hl_op_ff; - R8( data ) = op; - goto loop; - -// Load - - case 0x70: // LD (HL),B - case 0x71: // LD (HL),C - case 0x72: // LD (HL),D - case 0x73: // LD (HL),E - case 0x74: // LD (HL),H - case 0x75: // LD (HL),L - case 0x77: // LD (HL),A - op = R8( op & 7 ); - write_hl_op_ff: - WRITE( rp.hl, op & 0xFF ); - goto loop; - - case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x47: // LD r,r - case 0x48: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4F: - case 0x50: case 0x51: case 0x53: case 0x54: case 0x55: case 0x57: - case 0x58: case 0x59: case 0x5A: case 0x5C: case 0x5D: case 0x5F: - case 0x60: case 0x61: case 0x62: case 0x63: case 0x65: case 0x67: - case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6F: - case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: - R8( (op >> 3) & 7 ) = R8( op & 7 ); - goto loop; - - case 0x08: // LD IND16,SP - data = GET_ADDR(); - pc += 2; - WRITE( data, sp&0xFF ); - data++; - WRITE( data, sp >> 8 ); - goto loop; - - case 0xF9: // LD SP,HL - sp = rp.hl; - goto loop; - - case 0x31: // LD SP,IMM - sp = GET_ADDR(); - pc += 2; - goto loop; - - case 0x01: // LD BC,IMM - case 0x11: // LD DE,IMM - r16 [op >> 4] = GET_ADDR(); - pc += 2; - goto loop; - - { - unsigned temp; - case 0xE0: // LD (0xFF00+imm),A - temp = data | 0xFF00; - pc++; - goto write_data_rg_a; - - case 0xE2: // LD (0xFF00+C),A - temp = rg.c | 0xFF00; - goto write_data_rg_a; - - case 0x32: // LD (HL-),A - temp = rp.hl; - rp.hl = temp - 1; - goto write_data_rg_a; - - case 0x02: // LD (BC),A - temp = rp.bc; - goto write_data_rg_a; - - case 0x12: // LD (DE),A - temp = rp.de; - goto write_data_rg_a; - - case 0x22: // LD (HL+),A - temp = rp.hl; - rp.hl = temp + 1; - goto write_data_rg_a; - - case 0xEA: // LD IND16,A (common) - temp = GET_ADDR(); - pc += 2; - write_data_rg_a: - WRITE( temp, rg.a ); - goto loop; - } - - case 0x06: // LD B,IMM - rg.b = data; - pc++; - goto loop; - - case 0x0E: // LD C,IMM - rg.c = data; - pc++; - goto loop; - - case 0x16: // LD D,IMM - rg.d = data; - pc++; - goto loop; - - case 0x1E: // LD E,IMM - rg.e = data; - pc++; - goto loop; - - case 0x26: // LD H,IMM - rg.h = data; - pc++; - goto loop; - - case 0x2E: // LD L,IMM - rg.l = data; - pc++; - goto loop; - - case 0x36: // LD (HL),IMM - WRITE( rp.hl, data ); - pc++; - goto loop; - - case 0x3E: // LD A,IMM - rg.a = data; - pc++; - goto loop; - -// Increment/Decrement - - case 0x03: // INC BC - case 0x13: // INC DE - case 0x23: // INC HL - r16 [op >> 4]++; - goto loop; - - case 0x33: // INC SP - sp = (sp + 1) & 0xFFFF; - goto loop; - - case 0x0B: // DEC BC - case 0x1B: // DEC DE - case 0x2B: // DEC HL - r16 [op >> 4]--; - goto loop; - - case 0x3B: // DEC SP - sp = (sp - 1) & 0xFFFF; - goto loop; - - case 0x34: // INC (HL) - op = rp.hl; - data = READ( op ); - data++; - WRITE( op, data & 0xFF ); - goto inc_comm; - - case 0x04: // INC B - case 0x0C: // INC C (common) - case 0x14: // INC D - case 0x1C: // INC E - case 0x24: // INC H - case 0x2C: // INC L - case 0x3C: // INC A - op = (op >> 3) & 7; - R8( op ) = data = R8( op ) + 1; - inc_comm: - flags = (flags & c_flag) | (((data & 15) - 1) & h_flag) | ((data >> 1) & z_flag); - goto loop; - - case 0x35: // DEC (HL) - op = rp.hl; - data = READ( op ); - data--; - WRITE( op, data & 0xFF ); - goto dec_comm; - - case 0x05: // DEC B - case 0x0D: // DEC C - case 0x15: // DEC D - case 0x1D: // DEC E - case 0x25: // DEC H - case 0x2D: // DEC L - case 0x3D: // DEC A - op = (op >> 3) & 7; - data = R8( op ) - 1; - R8( op ) = data; - dec_comm: - flags = (flags & c_flag) | n_flag | (((data & 15) + 0x31) & h_flag); - if ( data & 0xFF ) - goto loop; - flags |= z_flag; - goto loop; - -// Add 16-bit - - { - blargg_ulong temp; // need more than 16 bits for carry - unsigned prev; - - case 0xF8: // LD HL,SP+imm - temp = int8_t (data); // sign-extend to 16 bits - pc++; - flags = 0; - temp += sp; - prev = sp; - goto add_16_hl; - - case 0xE8: // ADD SP,IMM - temp = int8_t (data); // sign-extend to 16 bits - pc++; - flags = 0; - temp += sp; - prev = sp; - sp = temp & 0xFFFF; - goto add_16_comm; - - case 0x39: // ADD HL,SP - temp = sp; - goto add_hl_comm; - - case 0x09: // ADD HL,BC - case 0x19: // ADD HL,DE - case 0x29: // ADD HL,HL - temp = r16 [op >> 4]; - add_hl_comm: - prev = rp.hl; - temp += prev; - flags &= z_flag; - add_16_hl: - rp.hl = temp; - add_16_comm: - flags |= (temp >> 12) & c_flag; - flags |= (((temp & 0x0FFF) - (prev & 0x0FFF)) >> 7) & h_flag; - goto loop; - } - - case 0x86: // ADD (HL) - data = READ( rp.hl ); - goto add_comm; - - case 0x80: // ADD B - case 0x81: // ADD C - case 0x82: // ADD D - case 0x83: // ADD E - case 0x84: // ADD H - case 0x85: // ADD L - case 0x87: // ADD A - data = R8( op & 7 ); - goto add_comm; - - case 0xC6: // ADD IMM - pc++; - add_comm: - flags = rg.a; - data += flags; - flags = ((data & 15) - (flags & 15)) & h_flag; - flags |= (data >> 4) & c_flag; - rg.a = data; - if ( data & 0xFF ) - goto loop; - flags |= z_flag; - goto loop; - -// Add/Subtract - - case 0x8E: // ADC (HL) - data = READ( rp.hl ); - goto adc_comm; - - case 0x88: // ADC B - case 0x89: // ADC C - case 0x8A: // ADC D - case 0x8B: // ADC E - case 0x8C: // ADC H - case 0x8D: // ADC L - case 0x8F: // ADC A - data = R8( op & 7 ); - goto adc_comm; - - case 0xCE: // ADC IMM - pc++; - adc_comm: - data += (flags >> 4) & 1; - data &= 0xFF; // to do: does carry get set when sum + carry = 0x100? - goto add_comm; - - case 0x96: // SUB (HL) - data = READ( rp.hl ); - goto sub_comm; - - case 0x90: // SUB B - case 0x91: // SUB C - case 0x92: // SUB D - case 0x93: // SUB E - case 0x94: // SUB H - case 0x95: // SUB L - case 0x97: // SUB A - data = R8( op & 7 ); - goto sub_comm; - - case 0xD6: // SUB IMM - pc++; - sub_comm: - op = rg.a; - data = op - data; - rg.a = data; - goto sub_set_flags; - - case 0x9E: // SBC (HL) - data = READ( rp.hl ); - goto sbc_comm; - - case 0x98: // SBC B - case 0x99: // SBC C - case 0x9A: // SBC D - case 0x9B: // SBC E - case 0x9C: // SBC H - case 0x9D: // SBC L - case 0x9F: // SBC A - data = R8( op & 7 ); - goto sbc_comm; - - case 0xDE: // SBC IMM - pc++; - sbc_comm: - data += (flags >> 4) & 1; - data &= 0xFF; // to do: does carry get set when sum + carry = 0x100? - goto sub_comm; - -// Logical - - case 0xA0: // AND B - case 0xA1: // AND C - case 0xA2: // AND D - case 0xA3: // AND E - case 0xA4: // AND H - case 0xA5: // AND L - data = R8( op & 7 ); - goto and_comm; - - case 0xA6: // AND (HL) - data = READ( rp.hl ); - pc--; - case 0xE6: // AND IMM - pc++; - and_comm: - rg.a &= data; - case 0xA7: // AND A - flags = h_flag | (((rg.a - 1) >> 1) & z_flag); - goto loop; - - case 0xB0: // OR B - case 0xB1: // OR C - case 0xB2: // OR D - case 0xB3: // OR E - case 0xB4: // OR H - case 0xB5: // OR L - data = R8( op & 7 ); - goto or_comm; - - case 0xB6: // OR (HL) - data = READ( rp.hl ); - pc--; - case 0xF6: // OR IMM - pc++; - or_comm: - rg.a |= data; - case 0xB7: // OR A - flags = ((rg.a - 1) >> 1) & z_flag; - goto loop; - - case 0xA8: // XOR B - case 0xA9: // XOR C - case 0xAA: // XOR D - case 0xAB: // XOR E - case 0xAC: // XOR H - case 0xAD: // XOR L - data = R8( op & 7 ); - goto xor_comm; - - case 0xAE: // XOR (HL) - data = READ( rp.hl ); - pc--; - case 0xEE: // XOR IMM - pc++; - xor_comm: - data ^= rg.a; - rg.a = data; - data--; - flags = (data >> 1) & z_flag; - goto loop; - - case 0xAF: // XOR A - rg.a = 0; - flags = z_flag; - goto loop; - -// Stack - - case 0xF1: // POP FA - case 0xC1: // POP BC - case 0xD1: // POP DE - case 0xE1: // POP HL (common) - data = READ( sp ); - r16 [(op >> 4) & 3] = data + 0x100 * READ( sp + 1 ); - sp = (sp + 2) & 0xFFFF; - if ( op != 0xF1 ) - goto loop; - flags = rg.flags & 0xF0; - goto loop; - - case 0xC5: // PUSH BC - data = rp.bc; - goto push; - - case 0xD5: // PUSH DE - data = rp.de; - goto push; - - case 0xE5: // PUSH HL - data = rp.hl; - goto push; - - case 0xF5: // PUSH FA - data = (flags << 8) | rg.a; - goto push; - -// Flow control - - case 0xFF: - if ( pc == idle_addr + 1 ) - goto stop; - case 0xC7: case 0xCF: case 0xD7: case 0xDF: // RST - case 0xE7: case 0xEF: case 0xF7: - data = pc; - pc = (op & 0x38) + rst_base; - goto push; - - case 0xCC: // CZ - pc += 2; - if ( flags & z_flag ) - goto call; - goto loop; - - case 0xD4: // CNC - pc += 2; - if ( !(flags & c_flag) ) - goto call; - goto loop; - - case 0xDC: // CC - pc += 2; - if ( flags & c_flag ) - goto call; - goto loop; - - case 0xD9: // RETI - //interrupts_enabled = 1; - goto ret; - - case 0xC0: // RZ - if ( !(flags & z_flag) ) - goto ret; - goto loop; - - case 0xD0: // RNC - if ( !(flags & c_flag) ) - goto ret; - goto loop; - - case 0xD8: // RC - if ( flags & c_flag ) - goto ret; - goto loop; - - case 0x18: // JR - BRANCH( true ) - - case 0x30: // JR NC - BRANCH( !(flags & c_flag) ) - - case 0x38: // JR C - BRANCH( flags & c_flag ) - - case 0xE9: // JP_HL - pc = rp.hl; - goto loop; - - case 0xC3: // JP (next-most-common) - pc = GET_ADDR(); - goto loop; - - case 0xC2: // JP NZ - pc += 2; - if ( !(flags & z_flag) ) - goto jp_taken; - goto loop; - - case 0xCA: // JP Z (most common) - pc += 2; - if ( !(flags & z_flag) ) - goto loop; - jp_taken: - pc -= 2; - pc = GET_ADDR(); - goto loop; - - case 0xD2: // JP NC - pc += 2; - if ( !(flags & c_flag) ) - goto jp_taken; - goto loop; - - case 0xDA: // JP C - pc += 2; - if ( flags & c_flag ) - goto jp_taken; - goto loop; - -// Flags - - case 0x2F: // CPL - rg.a = ~rg.a; - flags |= n_flag | h_flag; - goto loop; - - case 0x3F: // CCF - flags = (flags ^ c_flag) & ~(n_flag | h_flag); - goto loop; - - case 0x37: // SCF - flags = (flags | c_flag) & ~(n_flag | h_flag); - goto loop; - - case 0xF3: // DI - //interrupts_enabled = 0; - goto loop; - - case 0xFB: // EI - //interrupts_enabled = 1; - goto loop; - -// Special - - case 0xDD: case 0xD3: case 0xDB: case 0xE3: case 0xE4: // ? - case 0xEB: case 0xEC: case 0xF4: case 0xFD: case 0xFC: - case 0x10: // STOP - case 0x27: // DAA (I'll have to implement this eventually...) - case 0xBF: - case 0xED: // Z80 prefix - case 0x76: // HALT - s.remain++; - goto stop; - } - - // If this fails then the case above is missing an opcode - assert( false ); - -stop: - pc--; - - // copy state back - STATIC_CAST(core_regs_t&,r) = rg; - r.pc = pc; - r.sp = sp; - r.flags = flags; - - this->state = &state_; - memcpy( &this->state_, &s, sizeof this->state_ ); - - return s.remain > 0; -} diff --git a/libraries/game-music-emu/gme/Gb_Cpu.h b/libraries/game-music-emu/gme/Gb_Cpu.h deleted file mode 100644 index d3df30cac..000000000 --- a/libraries/game-music-emu/gme/Gb_Cpu.h +++ /dev/null @@ -1,91 +0,0 @@ -// Nintendo Game Boy CPU emulator -// Treats every instruction as taking 4 cycles - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef GB_CPU_H -#define GB_CPU_H - -#include "blargg_common.h" -#include "blargg_endian.h" - -typedef unsigned gb_addr_t; // 16-bit CPU address - -class Gb_Cpu { - enum { clocks_per_instr = 4 }; -public: - // Clear registers and map all pages to unmapped - void reset( void* unmapped = 0 ); - - // Map code memory (memory accessed via the program counter). Start and size - // must be multiple of page_size. - enum { page_size = 0x2000 }; - void map_code( gb_addr_t start, unsigned size, void* code ); - - uint8_t* get_code( gb_addr_t ); - - // Push a byte on the stack - void push_byte( int ); - - // Game Boy Z80 registers. *Not* kept updated during a call to run(). - struct core_regs_t { - #if BLARGG_BIG_ENDIAN - uint8_t b, c, d, e, h, l, flags, a; - #else - uint8_t c, b, e, d, l, h, a, flags; - #endif - }; - - struct registers_t : core_regs_t { - long pc; // more than 16 bits to allow overflow detection - uint16_t sp; - }; - registers_t r; - - // Interrupt enable flag set by EI and cleared by DI - //bool interrupts_enabled; // unused - - // Base address for RST vectors (normally 0) - gb_addr_t rst_base; - - // If CPU executes opcode 0xFF at this address, it treats as illegal instruction - enum { idle_addr = 0xF00D }; - - // Run CPU for at least 'count' cycles and return false, or return true if - // illegal instruction is encountered. - bool run( blargg_long count ); - - // Number of clock cycles remaining for most recent run() call - blargg_long remain() const { return state->remain * clocks_per_instr; } - - // Can read this many bytes past end of a page - enum { cpu_padding = 8 }; - -public: - Gb_Cpu() : rst_base( 0 ) { state = &state_; } - enum { page_shift = 13 }; - enum { page_count = 0x10000 >> page_shift }; -private: - // noncopyable - Gb_Cpu( const Gb_Cpu& ); - Gb_Cpu& operator = ( const Gb_Cpu& ); - - struct state_t { - uint8_t* code_map [page_count + 1]; - blargg_long remain; - }; - state_t* state; // points to state_ or a local copy within run() - state_t state_; - - void set_code_page( int, uint8_t* ); -}; - -inline uint8_t* Gb_Cpu::get_code( gb_addr_t addr ) -{ - return state->code_map [addr >> page_shift] + addr - #if !BLARGG_NONPORTABLE - % (unsigned) page_size - #endif - ; -} - -#endif diff --git a/libraries/game-music-emu/gme/Gb_Oscs.cpp b/libraries/game-music-emu/gme/Gb_Oscs.cpp deleted file mode 100644 index 735653fa9..000000000 --- a/libraries/game-music-emu/gme/Gb_Oscs.cpp +++ /dev/null @@ -1,336 +0,0 @@ -// Gb_Snd_Emu 0.1.5. http://www.slack.net/~ant/ - -#include "Gb_Apu.h" - -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// Gb_Osc - -void Gb_Osc::reset() -{ - delay = 0; - last_amp = 0; - length = 0; - output_select = 3; - output = outputs [output_select]; -} - -void Gb_Osc::clock_length() -{ - if ( (regs [4] & len_enabled_mask) && length ) - length--; -} - -// Gb_Env - -void Gb_Env::clock_envelope() -{ - if ( env_delay && !--env_delay ) - { - env_delay = regs [2] & 7; - int v = volume - 1 + (regs [2] >> 2 & 2); - if ( (unsigned) v < 15 ) - volume = v; - } -} - -bool Gb_Env::write_register( int reg, int data ) -{ - switch ( reg ) - { - case 1: - length = 64 - (regs [1] & 0x3F); - break; - - case 2: - if ( !(data >> 4) ) - enabled = false; - break; - - case 4: - if ( data & trigger ) - { - env_delay = regs [2] & 7; - volume = regs [2] >> 4; - enabled = true; - if ( length == 0 ) - length = 64; - return true; - } - } - return false; -} - -// Gb_Square - -void Gb_Square::reset() -{ - phase = 0; - sweep_freq = 0; - sweep_delay = 0; - Gb_Env::reset(); -} - -void Gb_Square::clock_sweep() -{ - int sweep_period = (regs [0] & period_mask) >> 4; - if ( sweep_period && sweep_delay && !--sweep_delay ) - { - sweep_delay = sweep_period; - regs [3] = sweep_freq & 0xFF; - regs [4] = (regs [4] & ~0x07) | (sweep_freq >> 8 & 0x07); - - int offset = sweep_freq >> (regs [0] & shift_mask); - if ( regs [0] & 0x08 ) - offset = -offset; - sweep_freq += offset; - - if ( sweep_freq < 0 ) - { - sweep_freq = 0; - } - else if ( sweep_freq >= 2048 ) - { - sweep_delay = 0; // don't modify channel frequency any further - sweep_freq = 2048; // silence sound immediately - } - } -} - -void Gb_Square::run( blip_time_t time, blip_time_t end_time, int playing ) -{ - if ( sweep_freq == 2048 ) - playing = false; - - static unsigned char const table [4] = { 1, 2, 4, 6 }; - int const duty = table [regs [1] >> 6]; - int amp = volume & playing; - if ( phase >= duty ) - amp = -amp; - - int frequency = this->frequency(); - if ( unsigned (frequency - 1) > 2040 ) // frequency < 1 || frequency > 2041 - { - // really high frequency results in DC at half volume - amp = volume >> 1; - playing = false; - } - - { - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth->offset( time, delta, output ); - } - } - - time += delay; - if ( !playing ) - time = end_time; - - if ( time < end_time ) - { - int const period = (2048 - frequency) * 4; - Blip_Buffer* const output = this->output; - int phase = this->phase; - int delta = amp * 2; - do - { - phase = (phase + 1) & 7; - if ( phase == 0 || phase == duty ) - { - delta = -delta; - synth->offset_inline( time, delta, output ); - } - time += period; - } - while ( time < end_time ); - - this->phase = phase; - last_amp = delta >> 1; - } - delay = time - end_time; -} - -// Gb_Noise - -void Gb_Noise::run( blip_time_t time, blip_time_t end_time, int playing ) -{ - int amp = volume & playing; - int tap = 13 - (regs [3] & 8); - if ( bits >> tap & 2 ) - amp = -amp; - - { - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth->offset( time, delta, output ); - } - } - - time += delay; - if ( !playing ) - time = end_time; - - if ( time < end_time ) - { - static unsigned char const table [8] = { 8, 16, 32, 48, 64, 80, 96, 112 }; - int period = table [regs [3] & 7] << (regs [3] >> 4); - - // keep parallel resampled time to eliminate time conversion in the loop - Blip_Buffer* const output = this->output; - const blip_resampled_time_t resampled_period = - output->resampled_duration( period ); - blip_resampled_time_t resampled_time = output->resampled_time( time ); - unsigned bits = this->bits; - int delta = amp * 2; - - do - { - unsigned changed = (bits >> tap) + 1; - time += period; - bits <<= 1; - if ( changed & 2 ) - { - delta = -delta; - bits |= 1; - synth->offset_resampled( resampled_time, delta, output ); - } - resampled_time += resampled_period; - } - while ( time < end_time ); - - this->bits = bits; - last_amp = delta >> 1; - } - delay = time - end_time; -} - -// Gb_Wave - -inline void Gb_Wave::write_register( int reg, int data ) -{ - switch ( reg ) - { - case 0: - if ( !(data & 0x80) ) - enabled = false; - break; - - case 1: - length = 256 - regs [1]; - break; - - case 2: - volume = data >> 5 & 3; - break; - - case 4: - if ( data & trigger & regs [0] ) - { - wave_pos = 0; - enabled = true; - if ( length == 0 ) - length = 256; - } - } -} - -void Gb_Wave::run( blip_time_t time, blip_time_t end_time, int playing ) -{ - int volume_shift = (volume - 1) & 7; // volume = 0 causes shift = 7 - int frequency; - { - int amp = (wave [wave_pos] >> volume_shift & playing) * 2; - - frequency = this->frequency(); - if ( unsigned (frequency - 1) > 2044 ) // frequency < 1 || frequency > 2045 - { - amp = 30 >> volume_shift & playing; - playing = false; - } - - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth->offset( time, delta, output ); - } - } - - time += delay; - if ( !playing ) - time = end_time; - - if ( time < end_time ) - { - Blip_Buffer* const output = this->output; - int const period = (2048 - frequency) * 2; - int wave_pos = (this->wave_pos + 1) & (wave_size - 1); - - do - { - int amp = (wave [wave_pos] >> volume_shift) * 2; - wave_pos = (wave_pos + 1) & (wave_size - 1); - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth->offset_inline( time, delta, output ); - } - time += period; - } - while ( time < end_time ); - - this->wave_pos = (wave_pos - 1) & (wave_size - 1); - } - delay = time - end_time; -} - -// Gb_Apu::write_osc - -void Gb_Apu::write_osc( int index, int reg, int data ) -{ - reg -= index * 5; - Gb_Square* sq = &square2; - switch ( index ) - { - case 0: - sq = &square1; - case 1: - if ( sq->write_register( reg, data ) && index == 0 ) - { - square1.sweep_freq = square1.frequency(); - if ( (regs [0] & sq->period_mask) && (regs [0] & sq->shift_mask) ) - { - square1.sweep_delay = 1; // cause sweep to recalculate now - square1.clock_sweep(); - } - } - break; - - case 2: - wave.write_register( reg, data ); - break; - - case 3: - if ( noise.write_register( reg, data ) ) - noise.bits = 0x7FFF; - } -} diff --git a/libraries/game-music-emu/gme/Gb_Oscs.h b/libraries/game-music-emu/gme/Gb_Oscs.h deleted file mode 100644 index 8cb026c3e..000000000 --- a/libraries/game-music-emu/gme/Gb_Oscs.h +++ /dev/null @@ -1,83 +0,0 @@ -// Private oscillators used by Gb_Apu - -// Gb_Snd_Emu 0.1.5 -#ifndef GB_OSCS_H -#define GB_OSCS_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -struct Gb_Osc -{ - enum { trigger = 0x80 }; - enum { len_enabled_mask = 0x40 }; - - Blip_Buffer* outputs [4]; // NULL, right, left, center - Blip_Buffer* output; - int output_select; - uint8_t* regs; // osc's 5 registers - - int delay; - int last_amp; - int volume; - int length; - int enabled; - - void reset(); - void clock_length(); - int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; } -}; - -struct Gb_Env : Gb_Osc -{ - int env_delay; - - void reset(); - void clock_envelope(); - bool write_register( int, int ); -}; - -struct Gb_Square : Gb_Env -{ - enum { period_mask = 0x70 }; - enum { shift_mask = 0x07 }; - - typedef Blip_Synth Synth; - Synth const* synth; - int sweep_delay; - int sweep_freq; - int phase; - - void reset(); - void clock_sweep(); - void run( blip_time_t, blip_time_t, int playing ); -}; - -struct Gb_Noise : Gb_Env -{ - typedef Blip_Synth Synth; - Synth const* synth; - unsigned bits; - - void run( blip_time_t, blip_time_t, int playing ); -}; - -struct Gb_Wave : Gb_Osc -{ - typedef Blip_Synth Synth; - Synth const* synth; - int wave_pos; - enum { wave_size = 32 }; - uint8_t wave [wave_size]; - - void write_register( int, int ); - void run( blip_time_t, blip_time_t, int playing ); -}; - -inline void Gb_Env::reset() -{ - env_delay = 0; - Gb_Osc::reset(); -} - -#endif diff --git a/libraries/game-music-emu/gme/Gbs_Emu.cpp b/libraries/game-music-emu/gme/Gbs_Emu.cpp deleted file mode 100644 index 6c5def339..000000000 --- a/libraries/game-music-emu/gme/Gbs_Emu.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Gbs_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq = - 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() -{ - set_type( gme_gbs_type ); - - static const char* const names [Gb_Apu::osc_count] = { - "Square 1", "Square 2", "Wave", "Noise" - }; - set_voice_names( names ); - - static int const types [Gb_Apu::osc_count] = { - wave_type | 1, wave_type | 2, wave_type | 0, mixed_type | 0 - }; - set_voice_types( types ); - - set_silence_lookahead( 6 ); - set_max_initial_silence( 21 ); - set_gain( 1.2 ); - - set_equalizer( make_equalizer( -1.0, 120 ) ); -} - -Gbs_Emu::~Gbs_Emu() { } - -void Gbs_Emu::unload() -{ - rom.clear(); - Music_Emu::unload(); -} - -// Track info - -static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out ) -{ - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, author ); - GME_COPY_FIELD( h, out, copyright ); -} - -blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const -{ - copy_gbs_fields( header_, out ); - return 0; -} - -static blargg_err_t check_gbs_header( void const* header ) -{ - if ( memcmp( header, "GBS", 3 ) ) - return gme_wrong_file_type; - return 0; -} - -struct Gbs_File : Gme_Info_ -{ - Gbs_Emu::header_t h; - - Gbs_File() { set_type( gme_gbs_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - blargg_err_t err = in.read( &h, Gbs_Emu::header_size ); - if ( err ) - return (err == in.eof_error ? gme_wrong_file_type : err); - - set_track_count( h.track_count ); - return check_gbs_header( &h ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_gbs_fields( h, out ); - return 0; - } -}; - -static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; } -static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; } - -static gme_type_t_ const gme_gbs_type_ = { "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_gbs_type = &gme_gbs_type_; - -// Setup - -blargg_err_t Gbs_Emu::load_( Data_Reader& in ) -{ - assert( offsetof (header_t,copyright [32]) == header_size ); - RETURN_ERR( rom.load( in, header_size, &header_, 0 ) ); - - set_track_count( header_.track_count ); - RETURN_ERR( check_gbs_header( &header_ ) ); - - if ( header_.vers != 1 ) - set_warning( "Unknown file version" ); - - if ( header_.timer_mode & 0x78 ) - set_warning( "Invalid timer mode" ); - - unsigned load_addr = get_le16( header_.load_addr ); - if ( (header_.load_addr [1] | header_.init_addr [1] | header_.play_addr [1]) > 0x7F || - load_addr < 0x400 ) - set_warning( "Invalid load/init/play address" ); - - set_voice_count( Gb_Apu::osc_count ); - - apu.volume( gain() ); - - return setup_buffer( 4194304 ); -} - -void Gbs_Emu::update_eq( blip_eq_t const& eq ) -{ - apu.treble_eq( eq ); -} - -void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - apu.osc_output( i, c, l, r ); -} - -// Emulation - -// see gb_cpu_io.h for read/write functions - -void Gbs_Emu::set_bank( int n ) -{ - blargg_long addr = rom.mask_addr( n * (blargg_long) bank_size ); - if ( addr == 0 && rom.size() > bank_size ) - { - // TODO: what is the correct behavior? Current Game & Watch Gallery - // rip requires that this have no effect or set to bank 1. - //debug_printf( "Selected ROM bank 0\n" ); - return; - //n = 1; - } - cpu::map_code( bank_size, bank_size, rom.at_addr( addr ) ); -} - -void Gbs_Emu::update_timer() -{ - if ( header_.timer_mode & 0x04 ) - { - static byte const rates [4] = { 10, 4, 6, 8 }; - int shift = rates [ram [hi_page + 7] & 3] - (header_.timer_mode >> 7); - play_period = (256L - ram [hi_page + 6]) << shift; - } - else - { - play_period = 70224; // 59.73 Hz - } - if ( tempo() != 1.0 ) - play_period = blip_time_t (play_period / tempo()); -} - -static uint8_t const sound_data [Gb_Apu::register_count] = { - 0x80, 0xBF, 0x00, 0x00, 0xBF, // square 1 - 0x00, 0x3F, 0x00, 0x00, 0xBF, // square 2 - 0x7F, 0xFF, 0x9F, 0x00, 0xBF, // wave - 0x00, 0xFF, 0x00, 0x00, 0xBF, // noise - 0x77, 0xF3, 0xF1, // vin/volume, status, power mode - 0, 0, 0, 0, 0, 0, 0, 0, 0, // unused - 0xAC, 0xDD, 0xDA, 0x48, 0x36, 0x02, 0xCF, 0x16, // waveform data - 0x2C, 0x04, 0xE5, 0x2C, 0xAC, 0xDD, 0xDA, 0x48 -}; - -void Gbs_Emu::cpu_jsr( gb_addr_t addr ) -{ - check( cpu::r.sp == get_le16( header_.stack_ptr ) ); - cpu::r.pc = addr; - cpu_write( --cpu::r.sp, idle_addr >> 8 ); - cpu_write( --cpu::r.sp, idle_addr&0xFF ); -} - -void Gbs_Emu::set_tempo_( double t ) -{ - apu.set_tempo( t ); - update_timer(); -} - -blargg_err_t Gbs_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - memset( ram, 0, 0x4000 ); - memset( ram + 0x4000, 0xFF, 0x1F80 ); - memset( ram + 0x5F80, 0, sizeof ram - 0x5F80 ); - ram [hi_page] = 0; // joypad reads back as 0 - - apu.reset(); - for ( int i = 0; i < (int) sizeof sound_data; i++ ) - apu.write_register( 0, i + apu.start_addr, sound_data [i] ); - - unsigned load_addr = get_le16( header_.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( 0, bank_size, rom.at_addr( 0 ) ); - set_bank( rom.size() > bank_size ); - - ram [hi_page + 6] = header_.timer_modulo; - ram [hi_page + 7] = header_.timer_mode; - update_timer(); - next_play = play_period; - - cpu::r.a = track; - cpu::r.pc = idle_addr; - cpu::r.sp = get_le16( header_.stack_ptr ); - cpu_time = 0; - cpu_jsr( get_le16( header_.init_addr ) ); - - return 0; -} - -blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int ) -{ - cpu_time = 0; - while ( cpu_time < duration ) - { - long count = duration - cpu_time; - cpu_time = duration; - bool result = cpu::run( count ); - cpu_time -= cpu::remain(); - - if ( result ) - { - if ( cpu::r.pc == idle_addr ) - { - if ( next_play > duration ) - { - cpu_time = duration; - break; - } - - if ( cpu_time < next_play ) - cpu_time = next_play; - next_play += play_period; - cpu_jsr( get_le16( header_.play_addr ) ); - GME_FRAME_HOOK( this ); - // TODO: handle timer rates different than 60 Hz - } - else if ( cpu::r.pc > 0xFFFF ) - { - debug_printf( "PC wrapped around\n" ); - cpu::r.pc &= 0xFFFF; - } - else - { - set_warning( "Emulation error (illegal/unsupported instruction)" ); - debug_printf( "Bad opcode $%.2x at $%.4x\n", - (int) *cpu::get_code( cpu::r.pc ), (int) cpu::r.pc ); - cpu::r.pc = (cpu::r.pc + 1) & 0xFFFF; - cpu_time += 6; - } - } - } - - duration = cpu_time; - next_play -= cpu_time; - if ( next_play < 0 ) // could go negative if routine is taking too long to return - next_play = 0; - apu.end_frame( cpu_time ); - - return 0; -} diff --git a/libraries/game-music-emu/gme/Gbs_Emu.h b/libraries/game-music-emu/gme/Gbs_Emu.h deleted file mode 100644 index 580f395c6..000000000 --- a/libraries/game-music-emu/gme/Gbs_Emu.h +++ /dev/null @@ -1,88 +0,0 @@ -// Nintendo Game Boy GBS music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef GBS_EMU_H -#define GBS_EMU_H - -#include "Classic_Emu.h" -#include "Gb_Apu.h" -#include "Gb_Cpu.h" - -class Gbs_Emu : private Gb_Cpu, public Classic_Emu { - typedef Gb_Cpu cpu; -public: - // Equalizer profiles for Game Boy Color speaker and headphones - static equalizer_t const handheld_eq; - static equalizer_t const headphones_eq; - - // GBS file header - enum { header_size = 112 }; - struct header_t - { - char tag [3]; - byte vers; - byte track_count; - byte first_track; - byte load_addr [2]; - byte init_addr [2]; - byte play_addr [2]; - byte stack_ptr [2]; - byte timer_modulo; - byte timer_mode; - char game [32]; - char author [32]; - char copyright [32]; - }; - - // Header for currently loaded file - header_t const& header() const { return header_; } - - static gme_type_t static_type() { return gme_gbs_type; } - -public: - // deprecated - using Music_Emu::load; - blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader - { return load_remaining_( &h, sizeof h, in ); } - -public: - Gbs_Emu(); - ~Gbs_Emu(); -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_( Data_Reader& ); - blargg_err_t start_track_( int ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); - void unload(); -private: - // rom - enum { bank_size = 0x4000 }; - Rom_Data rom; - void set_bank( int ); - - // timer - blip_time_t cpu_time; - blip_time_t play_period; - blip_time_t next_play; - void update_timer(); - - header_t header_; - void cpu_jsr( gb_addr_t ); - -public: private: friend class Gb_Cpu; - blip_time_t clock() const { return cpu_time - cpu::remain(); } - - enum { joypad_addr = 0xFF00 }; - enum { ram_addr = 0xA000 }; - enum { hi_page = 0xFF00 - ram_addr }; - byte ram [0x4000 + 0x2000 + Gb_Cpu::cpu_padding]; - Gb_Apu apu; - - int cpu_read( gb_addr_t ); - void cpu_write( gb_addr_t, int ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Gme_File.cpp b/libraries/game-music-emu/gme/Gme_File.cpp deleted file mode 100644 index a5e4516d6..000000000 --- a/libraries/game-music-emu/gme/Gme_File.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Gme_File.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -const char* const gme_wrong_file_type = "Wrong file type for this emulator"; - -void Gme_File::clear_playlist() -{ - playlist.clear(); - clear_playlist_(); - track_count_ = raw_track_count_; -} - -void Gme_File::unload() -{ - clear_playlist(); // *before* clearing track count - track_count_ = 0; - raw_track_count_ = 0; - file_data.clear(); -} - -Gme_File::Gme_File() -{ - type_ = 0; - user_data_ = 0; - user_cleanup_ = 0; - unload(); // clears fields - blargg_verify_byte_order(); // used by most emulator types, so save them the trouble -} - -Gme_File::~Gme_File() -{ - if ( user_cleanup_ ) - user_cleanup_( user_data_ ); -} - -blargg_err_t Gme_File::load_mem_( byte const* data, long size ) -{ - require( data != file_data.begin() ); // load_mem_() or load_() must be overridden - Mem_File_Reader in( data, size ); - return load_( in ); -} - -blargg_err_t Gme_File::load_( Data_Reader& in ) -{ - RETURN_ERR( file_data.resize( in.remain() ) ); - RETURN_ERR( in.read( file_data.begin(), file_data.size() ) ); - return load_mem_( file_data.begin(), file_data.size() ); -} - -// public load functions call this at beginning -void Gme_File::pre_load() { unload(); } - -void Gme_File::post_load_() { } - -// public load functions call this at end -blargg_err_t Gme_File::post_load( blargg_err_t err ) -{ - if ( !track_count() ) - set_track_count( type()->track_count ); - if ( !err ) - post_load_(); - else - unload(); - - return err; -} - -// Public load functions - -blargg_err_t Gme_File::load_mem( void const* in, long size ) -{ - pre_load(); - return post_load( load_mem_( (byte const*) in, size ) ); -} - -blargg_err_t Gme_File::load( Data_Reader& in ) -{ - pre_load(); - return post_load( load_( in ) ); -} - -blargg_err_t Gme_File::load_file( const char* path ) -{ - pre_load(); - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - return post_load( load_( in ) ); -} - -blargg_err_t Gme_File::load_remaining_( void const* h, long s, Data_Reader& in ) -{ - Remaining_Reader rem( h, s, &in ); - return load( rem ); -} - -// Track info - -void Gme_File::copy_field_( char* out, const char* in, int in_size ) -{ - if ( !in || !*in ) - return; - - // remove spaces/junk from beginning - while ( in_size && unsigned (*in - 1) <= ' ' - 1 ) - { - in++; - in_size--; - } - - // truncate - if ( in_size > max_field_ ) - in_size = max_field_; - - // find terminator - int len = 0; - while ( len < in_size && in [len] ) - len++; - - // remove spaces/junk from end - while ( len && unsigned (in [len - 1]) <= ' ' ) - len--; - - // copy - out [len] = 0; - memcpy( out, in, len ); - - // strip out stupid fields that should have been left blank - if ( !strcmp( out, "?" ) || !strcmp( out, "" ) || !strcmp( out, "< ? >" ) ) - out [0] = 0; -} - -void Gme_File::copy_field_( char* out, const char* in ) -{ - copy_field_( out, in, max_field_ ); -} - -blargg_err_t Gme_File::remap_track_( int* track_io ) const -{ - if ( (unsigned) *track_io >= (unsigned) track_count() ) - return "Invalid track"; - - if ( (unsigned) *track_io < (unsigned) playlist.size() ) - { - M3u_Playlist::entry_t const& e = playlist [*track_io]; - *track_io = 0; - if ( e.track >= 0 ) - { - *track_io = e.track; - if ( !(type_->flags_ & 0x02) ) - *track_io -= e.decimal_track; - } - if ( *track_io >= raw_track_count_ ) - return "Invalid track in m3u playlist"; - } - else - { - check( !playlist.size() ); - } - return 0; -} - -blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const -{ - out->track_count = track_count(); - out->length = -1; - out->loop_length = -1; - out->intro_length = -1; - out->song [0] = 0; - - out->game [0] = 0; - out->author [0] = 0; - out->copyright [0] = 0; - out->comment [0] = 0; - out->dumper [0] = 0; - out->system [0] = 0; - - copy_field_( out->system, type()->system ); - - int remapped = track; - RETURN_ERR( remap_track_( &remapped ) ); - RETURN_ERR( track_info_( out, remapped ) ); - - // override with m3u info - if ( playlist.size() ) - { - M3u_Playlist::info_t const& i = playlist.info(); - copy_field_( out->game , i.title ); - copy_field_( out->author, i.engineer ); - copy_field_( out->author, i.composer ); - copy_field_( out->dumper, i.ripping ); - - M3u_Playlist::entry_t const& e = playlist [track]; - copy_field_( out->song, e.name ); - if ( e.length >= 0 ) out->length = e.length * 1000L; - if ( e.intro >= 0 ) out->intro_length = e.intro * 1000L; - if ( e.loop >= 0 ) out->loop_length = e.loop * 1000L; - } - return 0; -} diff --git a/libraries/game-music-emu/gme/Gme_File.h b/libraries/game-music-emu/gme/Gme_File.h deleted file mode 100644 index 3ec36bc8e..000000000 --- a/libraries/game-music-emu/gme/Gme_File.h +++ /dev/null @@ -1,173 +0,0 @@ -// Common interface to game music file loading and information - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef GME_FILE_H -#define GME_FILE_H - -#include "gme.h" -#include "blargg_common.h" -#include "Data_Reader.h" -#include "M3u_Playlist.h" - -// Error returned if file is wrong type -//extern const char gme_wrong_file_type []; // declared in gme.h - -struct gme_type_t_ -{ - const char* system; /* name of system this music file type is generally for */ - int track_count; /* non-zero for formats with a fixed number of tracks */ - Music_Emu* (*new_emu)(); /* Create new emulator for this type (useful in C++ only) */ - Music_Emu* (*new_info)(); /* Create new info reader for this type */ - - /* internal */ - const char* extension_; - int flags_; -}; - -struct track_info_t -{ - long track_count; - - /* times in milliseconds; -1 if unknown */ - long length; - long intro_length; - long loop_length; - - /* empty string if not available */ - char system [256]; - char game [256]; - char song [256]; - char author [256]; - char copyright [256]; - char comment [256]; - char dumper [256]; -}; -enum { gme_max_field = 255 }; - -struct Gme_File { -public: -// File loading - - // Each loads game music data from a file and returns an error if - // file is wrong type or is seriously corrupt. They also set warning - // string for minor problems. - - // Load from file on disk - blargg_err_t load_file( const char* path ); - - // Load from custom data source (see Data_Reader.h) - blargg_err_t load( Data_Reader& ); - - // Load from file already read into memory. Keeps pointer to data, so you - // must not free it until you're done with the file. - blargg_err_t load_mem( void const* data, long size ); - - // Load an m3u playlist. Must be done after loading main music file. - blargg_err_t load_m3u( const char* path ); - blargg_err_t load_m3u( Data_Reader& in ); - - // Clears any loaded m3u playlist and any internal playlist that the music - // format supports (NSFE for example). - void clear_playlist(); - -// Informational - - // Type of emulator. For example if this returns gme_nsfe_type, this object - // is an NSFE emulator, and you can cast to an Nsfe_Emu* if necessary. - gme_type_t type() const; - - // Most recent warning string, or NULL if none. Clears current warning after - // returning. - const char* warning(); - - // Number of tracks or 0 if no file has been loaded - int track_count() const; - - // Get information for a track (length, name, author, etc.) - // See gme.h for definition of struct track_info_t. - blargg_err_t track_info( track_info_t* out, int track ) const; - -// User data/cleanup - - // Set/get pointer to data you want to associate with this emulator. - // You can use this for whatever you want. - void set_user_data( void* p ) { user_data_ = p; } - void* user_data() const { return user_data_; } - - // Register cleanup function to be called when deleting emulator, or NULL to - // clear it. Passes user_data to cleanup function. - void set_user_cleanup( gme_user_cleanup_t func ) { user_cleanup_ = func; } - -public: - // deprecated - int error_count() const; // use warning() -public: - Gme_File(); - virtual ~Gme_File(); - BLARGG_DISABLE_NOTHROW - typedef uint8_t byte; -protected: - // Services - void set_track_count( int n ) { track_count_ = raw_track_count_ = n; } - void set_warning( const char* s ) { warning_ = s; } - void set_type( gme_type_t t ) { type_ = t; } - blargg_err_t load_remaining_( void const* header, long header_size, Data_Reader& remaining ); - - // Overridable - virtual void unload(); // called before loading file and if loading fails - virtual blargg_err_t load_( Data_Reader& ); // default loads then calls load_mem_() - virtual blargg_err_t load_mem_( byte const* data, long size ); // use data in memory - virtual blargg_err_t track_info_( track_info_t* out, int track ) const = 0; - virtual void pre_load(); - virtual void post_load_(); - virtual void clear_playlist_() { } - -public: - blargg_err_t remap_track_( int* track_io ) const; // need by Music_Emu -private: - // noncopyable - Gme_File( const Gme_File& ); - Gme_File& operator = ( const Gme_File& ); - - gme_type_t type_; - int track_count_; - int raw_track_count_; - const char* warning_; - void* user_data_; - gme_user_cleanup_t user_cleanup_; - M3u_Playlist playlist; - char playlist_warning [64]; - blargg_vector file_data; // only if loaded into memory using default load - - blargg_err_t load_m3u_( blargg_err_t ); - blargg_err_t post_load( blargg_err_t err ); -public: - // track_info field copying - enum { max_field_ = 255 }; - static void copy_field_( char* out, const char* in ); - static void copy_field_( char* out, const char* in, int len ); -}; - -Music_Emu* gme_new_( Music_Emu*, long sample_rate ); - -#define GME_COPY_FIELD( in, out, name ) \ - { Gme_File::copy_field_( out->name, in.name, sizeof in.name ); } - -#ifndef GME_FILE_READER - #define GME_FILE_READER Std_File_Reader -#elif defined (GME_FILE_READER_INCLUDE) - #include GME_FILE_READER_INCLUDE -#endif - -inline gme_type_t Gme_File::type() const { return type_; } -inline int Gme_File::error_count() const { return warning_ != 0; } -inline int Gme_File::track_count() const { return track_count_; } - -inline const char* Gme_File::warning() -{ - const char* s = warning_; - warning_ = 0; - return s; -} - -#endif diff --git a/libraries/game-music-emu/gme/Gym_Emu.cpp b/libraries/game-music-emu/gme/Gym_Emu.cpp deleted file mode 100644 index bb99ff033..000000000 --- a/libraries/game-music-emu/gme/Gym_Emu.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Gym_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -double const min_tempo = 0.25; -double const oversample_factor = 5 / 3.0; -double const fm_gain = 3.0; - -const long base_clock = 53700300; -const long clock_rate = base_clock / 15; - -Gym_Emu::Gym_Emu() -{ - data = 0; - pos = 0; - set_type( gme_gym_type ); - - static const char* const names [] = { - "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" - }; - set_voice_names( names ); - set_silence_lookahead( 1 ); // tracks should already be trimmed -} - -Gym_Emu::~Gym_Emu() { } - -// Track info - -static void get_gym_info( Gym_Emu::header_t const& h, long length, track_info_t* out ) -{ - if ( !memcmp( h.tag, "GYMX", 4 ) ) - { - length = length * 50 / 3; // 1000 / 60 - long loop = get_le32( h.loop_start ); - if ( loop ) - { - out->intro_length = loop * 50 / 3; - out->loop_length = length - out->intro_length; - } - else - { - out->length = length; - out->intro_length = length; // make it clear that track is no longer than length - out->loop_length = 0; - } - - // more stupidity where the field should have been left - if ( strcmp( h.song, "Unknown Song" ) ) - GME_COPY_FIELD( h, out, song ); - - if ( strcmp( h.game, "Unknown Game" ) ) - GME_COPY_FIELD( h, out, game ); - - if ( strcmp( h.copyright, "Unknown Publisher" ) ) - GME_COPY_FIELD( h, out, copyright ); - - if ( strcmp( h.dumper, "Unknown Person" ) ) - GME_COPY_FIELD( h, out, dumper ); - - if ( strcmp( h.comment, "Header added by YMAMP" ) ) - GME_COPY_FIELD( h, out, comment ); - } -} - -blargg_err_t Gym_Emu::track_info_( track_info_t* out, int ) const -{ - get_gym_info( header_, track_length(), out ); - return 0; -} - -static long gym_track_length( byte const* p, byte const* end ) -{ - long time = 0; - while ( p < end ) - { - switch ( *p++ ) - { - case 0: - time++; - break; - - case 1: - case 2: - p += 2; - break; - - case 3: - p += 1; - break; - } - } - return time; -} - -long Gym_Emu::track_length() const { return gym_track_length( data, data_end ); } - -static blargg_err_t check_header( byte const* in, long size, int* data_offset = 0 ) -{ - if ( size < 4 ) - return gme_wrong_file_type; - - if ( memcmp( in, "GYMX", 4 ) == 0 ) - { - if ( size < Gym_Emu::header_size + 1 ) - return gme_wrong_file_type; - - if ( memcmp( ((Gym_Emu::header_t const*) in)->packed, "\0\0\0\0", 4 ) != 0 ) - return "Packed GYM file not supported"; - - if ( data_offset ) - *data_offset = Gym_Emu::header_size; - } - else if ( *in > 3 ) - { - return gme_wrong_file_type; - } - - return 0; -} - -struct Gym_File : Gme_Info_ -{ - byte const* file_begin; - byte const* file_end; - int data_offset; - - Gym_File() { set_type( gme_gym_type ); } - - blargg_err_t load_mem_( byte const* in, long size ) - { - file_begin = in; - file_end = in + size; - data_offset = 0; - return check_header( in, size, &data_offset ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - long length = gym_track_length( &file_begin [data_offset], file_end ); - get_gym_info( *(Gym_Emu::header_t const*) file_begin, length, out ); - return 0; - } -}; - -static Music_Emu* new_gym_emu () { return BLARGG_NEW Gym_Emu ; } -static Music_Emu* new_gym_file() { return BLARGG_NEW Gym_File; } - -static gme_type_t_ const gme_gym_type_ = { "Sega Genesis", 1, &new_gym_emu, &new_gym_file, "GYM", 0 }; -BLARGG_EXPORT extern gme_type_t const gme_gym_type = &gme_gym_type_; - -// Setup - -blargg_err_t Gym_Emu::set_sample_rate_( long sample_rate ) -{ - blip_eq_t eq( -32, 8000, sample_rate ); - apu.treble_eq( eq ); - dac_synth.treble_eq( eq ); - apu.volume( 0.135 * fm_gain * gain() ); - dac_synth.volume( 0.125 / 256 * fm_gain * gain() ); - double factor = Dual_Resampler::setup( oversample_factor, 0.990, fm_gain * gain() ); - fm_sample_rate = sample_rate * factor; - - RETURN_ERR( blip_buf.set_sample_rate( sample_rate, int (1000 / 60.0 / min_tempo) ) ); - blip_buf.clock_rate( clock_rate ); - - RETURN_ERR( fm.set_rate( fm_sample_rate, base_clock / 7.0 ) ); - RETURN_ERR( Dual_Resampler::reset( long (1.0 / 60 / min_tempo * sample_rate) ) ); - - return 0; -} - -void Gym_Emu::set_tempo_( double t ) -{ - if ( t < min_tempo ) - { - set_tempo( min_tempo ); - return; - } - - if ( blip_buf.sample_rate() ) - { - clocks_per_frame = long (clock_rate / 60 / tempo()); - Dual_Resampler::resize( long (sample_rate() / (60.0 * tempo())) ); - } -} - -void Gym_Emu::mute_voices_( int mask ) -{ - Music_Emu::mute_voices_( mask ); - fm.mute_voices( mask ); - dac_muted = (mask & 0x40) != 0; - apu.output( (mask & 0x80) ? 0 : &blip_buf ); -} - -blargg_err_t Gym_Emu::load_mem_( byte const* in, long size ) -{ - assert( offsetof (header_t,packed [4]) == header_size ); - int offset = 0; - RETURN_ERR( check_header( in, size, &offset ) ); - set_voice_count( 8 ); - - data = in + offset; - data_end = in + size; - loop_begin = 0; - - if ( offset ) - header_ = *(header_t const*) in; - else - memset( &header_, 0, sizeof header_ ); - - return 0; -} - -// Emulation - -blargg_err_t Gym_Emu::start_track_( int track ) -{ - RETURN_ERR( Music_Emu::start_track_( track ) ); - - pos = data; - loop_remain = get_le32( header_.loop_start ); - - prev_dac_count = 0; - dac_enabled = false; - dac_amp = -1; - - fm.reset(); - apu.reset(); - blip_buf.clear(); - Dual_Resampler::clear(); - return 0; -} - -void Gym_Emu::run_dac( int dac_count ) -{ - // Guess beginning and end of sample and adjust rate and buffer position accordingly. - - // count dac samples in next frame - int next_dac_count = 0; - const byte* p = this->pos; - int cmd; - while ( (cmd = *p++) != 0 ) - { - int data = *p++; - if ( cmd <= 2 ) - ++p; - if ( cmd == 1 && data == 0x2A ) - next_dac_count++; - } - - // detect beginning and end of sample - int rate_count = dac_count; - int start = 0; - if ( !prev_dac_count && next_dac_count && dac_count < next_dac_count ) - { - rate_count = next_dac_count; - start = next_dac_count - dac_count; - } - else if ( prev_dac_count && !next_dac_count && dac_count < prev_dac_count ) - { - rate_count = prev_dac_count; - } - - // Evenly space samples within buffer section being used - blip_resampled_time_t period = blip_buf.resampled_duration( clocks_per_frame ) / rate_count; - - blip_resampled_time_t time = blip_buf.resampled_time( 0 ) + - period * start + (period >> 1); - - int dac_amp = this->dac_amp; - if ( dac_amp < 0 ) - dac_amp = dac_buf [0]; - - for ( int i = 0; i < dac_count; i++ ) - { - int delta = dac_buf [i] - dac_amp; - dac_amp += delta; - dac_synth.offset_resampled( time, delta, &blip_buf ); - time += period; - } - this->dac_amp = dac_amp; -} - -void Gym_Emu::parse_frame() -{ - int dac_count = 0; - const byte* pos = this->pos; - - if ( loop_remain && !--loop_remain ) - loop_begin = pos; // find loop on first time through sequence - - int cmd; - while ( (cmd = *pos++) != 0 ) - { - int data = *pos++; - if ( cmd == 1 ) - { - int data2 = *pos++; - if ( data != 0x2A ) - { - if ( data == 0x2B ) - dac_enabled = (data2 & 0x80) != 0; - - fm.write0( data, data2 ); - } - else if ( dac_count < (int) sizeof dac_buf ) - { - dac_buf [dac_count] = data2; - dac_count += dac_enabled; - } - } - else if ( cmd == 2 ) - { - fm.write1( data, *pos++ ); - } - else if ( cmd == 3 ) - { - apu.write_data( 0, data ); - } - else - { - // to do: many GYM streams are full of errors, and error count should - // reflect cases where music is really having problems - //log_error(); - --pos; // put data back - } - } - - // loop - if ( pos >= data_end ) - { - check( pos == data_end ); - - if ( loop_begin ) - pos = loop_begin; - else - set_track_ended(); - } - this->pos = pos; - - // dac - if ( dac_count && !dac_muted ) - run_dac( dac_count ); - prev_dac_count = dac_count; -} - -int Gym_Emu::play_frame( blip_time_t blip_time, int sample_count, sample_t* buf ) -{ - if ( !track_ended() ) - parse_frame(); - - apu.end_frame( blip_time ); - - memset( buf, 0, sample_count * sizeof *buf ); - fm.run( sample_count >> 1, buf ); - - return sample_count; -} - -blargg_err_t Gym_Emu::play_( long count, sample_t* out ) -{ - Dual_Resampler::dual_play( count, out, blip_buf ); - return 0; -} diff --git a/libraries/game-music-emu/gme/Gym_Emu.h b/libraries/game-music-emu/gme/Gym_Emu.h deleted file mode 100644 index 290f57f5c..000000000 --- a/libraries/game-music-emu/gme/Gym_Emu.h +++ /dev/null @@ -1,82 +0,0 @@ -// Sega Genesis/Mega Drive GYM music file emulator -// Includes with PCM timing recovery to improve sample quality. - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef GYM_EMU_H -#define GYM_EMU_H - -#include "Dual_Resampler.h" -#include "Ym2612_Emu.h" -#include "Music_Emu.h" -#include "Sms_Apu.h" - -class Gym_Emu : public Music_Emu, private Dual_Resampler { -public: - // GYM file header - enum { header_size = 428 }; - struct header_t - { - char tag [4]; - char song [32]; - char game [32]; - char copyright [32]; - char emulator [32]; - char dumper [32]; - char comment [256]; - byte loop_start [4]; // in 1/60 seconds, 0 if not looped - byte packed [4]; - }; - - // Header for currently loaded file - header_t const& header() const { return header_; } - - static gme_type_t static_type() { return gme_gym_type; } - -public: - // deprecated - using Music_Emu::load; - blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader - { return load_remaining_( &h, sizeof h, in ); } - enum { gym_rate = 60 }; - long track_length() const; // use track_info() - -public: - Gym_Emu(); - ~Gym_Emu(); -protected: - blargg_err_t load_mem_( byte const*, long ); - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t set_sample_rate_( long sample_rate ); - blargg_err_t start_track_( int ); - blargg_err_t play_( long count, sample_t* ); - void mute_voices_( int ); - void set_tempo_( double ); - int play_frame( blip_time_t blip_time, int sample_count, sample_t* buf ); -private: - // sequence data begin, loop begin, current position, end - const byte* data; - const byte* loop_begin; - const byte* pos; - const byte* data_end; - blargg_long loop_remain; // frames remaining until loop beginning has been located - header_t header_; - double fm_sample_rate; - blargg_long clocks_per_frame; - void parse_frame(); - - // dac (pcm) - int dac_amp; - int prev_dac_count; - bool dac_enabled; - bool dac_muted; - void run_dac( int ); - - // sound - Blip_Buffer blip_buf; - Ym2612_Emu fm; - Blip_Synth dac_synth; - Sms_Apu apu; - byte dac_buf [1024]; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Hes_Apu.cpp b/libraries/game-music-emu/gme/Hes_Apu.cpp deleted file mode 100644 index 1df811592..000000000 --- a/libraries/game-music-emu/gme/Hes_Apu.cpp +++ /dev/null @@ -1,315 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Hes_Apu.h" - -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -bool const center_waves = true; // reduces asymmetry and clamping when starting notes - -Hes_Apu::Hes_Apu() -{ - Hes_Osc* osc = &oscs [osc_count]; - do - { - osc--; - osc->outputs [0] = 0; - osc->outputs [1] = 0; - osc->chans [0] = 0; - osc->chans [1] = 0; - osc->chans [2] = 0; - } - while ( osc != oscs ); - - reset(); -} - -void Hes_Apu::reset() -{ - latch = 0; - balance = 0xFF; - - Hes_Osc* osc = &oscs [osc_count]; - do - { - osc--; - memset( osc, 0, offsetof (Hes_Osc,outputs) ); - osc->noise_lfsr = 1; - osc->control = 0x40; - osc->balance = 0xFF; - } - while ( osc != oscs ); -} - -void Hes_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - require( (unsigned) index < osc_count ); - oscs [index].chans [0] = center; - oscs [index].chans [1] = left; - oscs [index].chans [2] = right; - - Hes_Osc* osc = &oscs [osc_count]; - do - { - osc--; - balance_changed( *osc ); - } - while ( osc != oscs ); -} - -void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time ) -{ - Blip_Buffer* const osc_outputs_0 = outputs [0]; // cache often-used values - if ( osc_outputs_0 && control & 0x80 ) - { - int dac = this->dac; - - int const volume_0 = volume [0]; - { - int delta = dac * volume_0 - last_amp [0]; - if ( delta ) - synth_.offset( last_time, delta, osc_outputs_0 ); - osc_outputs_0->set_modified(); - } - - Blip_Buffer* const osc_outputs_1 = outputs [1]; - int const volume_1 = volume [1]; - if ( osc_outputs_1 ) - { - int delta = dac * volume_1 - last_amp [1]; - if ( delta ) - synth_.offset( last_time, delta, osc_outputs_1 ); - osc_outputs_1->set_modified(); - } - - blip_time_t time = last_time + delay; - if ( time < end_time ) - { - if ( noise & 0x80 ) - { - if ( volume_0 | volume_1 ) - { - // noise - int const period = (32 - (noise & 0x1F)) * 64; // TODO: correct? - unsigned noise_lfsr = this->noise_lfsr; - do - { - int new_dac = 0x1F & -(noise_lfsr >> 1 & 1); - // Implemented using "Galios configuration" - // TODO: find correct LFSR algorithm - noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1)); - //noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1)); - int delta = new_dac - dac; - if ( delta ) - { - dac = new_dac; - synth_.offset( time, delta * volume_0, osc_outputs_0 ); - if ( osc_outputs_1 ) - synth_.offset( time, delta * volume_1, osc_outputs_1 ); - } - time += period; - } - while ( time < end_time ); - - this->noise_lfsr = noise_lfsr; - assert( noise_lfsr ); - } - } - else if ( !(control & 0x40) ) - { - // wave - int phase = (this->phase + 1) & 0x1F; // pre-advance for optimal inner loop - int period = this->period * 2; - if ( period >= 14 && (volume_0 | volume_1) ) - { - do - { - int new_dac = wave [phase]; - phase = (phase + 1) & 0x1F; - int delta = new_dac - dac; - if ( delta ) - { - dac = new_dac; - synth_.offset( time, delta * volume_0, osc_outputs_0 ); - if ( osc_outputs_1 ) - synth_.offset( time, delta * volume_1, osc_outputs_1 ); - } - time += period; - } - while ( time < end_time ); - } - else - { - if ( !period ) - { - // TODO: Gekisha Boy assumes that period = 0 silences wave - //period = 0x1000 * 2; - period = 1; - //if ( !(volume_0 | volume_1) ) - // debug_printf( "Used period 0\n" ); - } - - // maintain phase when silent - blargg_long count = (end_time - time + period - 1) / period; - phase += count; // phase will be masked below - time += count * period; - } - this->phase = (phase - 1) & 0x1F; // undo pre-advance - } - } - time -= end_time; - if ( time < 0 ) - time = 0; - delay = time; - - this->dac = dac; - last_amp [0] = dac * volume_0; - last_amp [1] = dac * volume_1; - } - last_time = end_time; -} - -void Hes_Apu::balance_changed( Hes_Osc& osc ) -{ - static short const log_table [32] = { // ~1.5 db per step - #define ENTRY( factor ) short (factor * Hes_Osc::amp_range / 31.0 + 0.5) - ENTRY( 0.000000 ),ENTRY( 0.005524 ),ENTRY( 0.006570 ),ENTRY( 0.007813 ), - ENTRY( 0.009291 ),ENTRY( 0.011049 ),ENTRY( 0.013139 ),ENTRY( 0.015625 ), - ENTRY( 0.018581 ),ENTRY( 0.022097 ),ENTRY( 0.026278 ),ENTRY( 0.031250 ), - ENTRY( 0.037163 ),ENTRY( 0.044194 ),ENTRY( 0.052556 ),ENTRY( 0.062500 ), - ENTRY( 0.074325 ),ENTRY( 0.088388 ),ENTRY( 0.105112 ),ENTRY( 0.125000 ), - ENTRY( 0.148651 ),ENTRY( 0.176777 ),ENTRY( 0.210224 ),ENTRY( 0.250000 ), - ENTRY( 0.297302 ),ENTRY( 0.353553 ),ENTRY( 0.420448 ),ENTRY( 0.500000 ), - ENTRY( 0.594604 ),ENTRY( 0.707107 ),ENTRY( 0.840896 ),ENTRY( 1.000000 ), - #undef ENTRY - }; - - int vol = (osc.control & 0x1F) - 0x1E * 2; - - int left = vol + (osc.balance >> 3 & 0x1E) + (balance >> 3 & 0x1E); - if ( left < 0 ) left = 0; - - int right = vol + (osc.balance << 1 & 0x1E) + (balance << 1 & 0x1E); - if ( right < 0 ) right = 0; - - left = log_table [left ]; - right = log_table [right]; - - // optimizing for the common case of being centered also allows easy - // panning using Effects_Buffer - osc.outputs [0] = osc.chans [0]; // center - osc.outputs [1] = 0; - if ( left != right ) - { - osc.outputs [0] = osc.chans [1]; // left - osc.outputs [1] = osc.chans [2]; // right - } - - if ( center_waves ) - { - osc.last_amp [0] += (left - osc.volume [0]) * 16; - osc.last_amp [1] += (right - osc.volume [1]) * 16; - } - - osc.volume [0] = left; - osc.volume [1] = right; -} - -void Hes_Apu::write_data( blip_time_t time, int addr, int data ) -{ - if ( addr == 0x800 ) - { - latch = data & 7; - } - else if ( addr == 0x801 ) - { - if ( balance != data ) - { - balance = data; - - Hes_Osc* osc = &oscs [osc_count]; - do - { - osc--; - osc->run_until( synth, time ); - balance_changed( *oscs ); - } - while ( osc != oscs ); - } - } - else if ( latch < osc_count ) - { - Hes_Osc& osc = oscs [latch]; - osc.run_until( synth, time ); - switch ( addr ) - { - case 0x802: - osc.period = (osc.period & 0xF00) | data; - break; - - case 0x803: - osc.period = (osc.period & 0x0FF) | ((data & 0x0F) << 8); - break; - - case 0x804: - if ( osc.control & 0x40 & ~data ) - osc.phase = 0; - osc.control = data; - balance_changed( osc ); - break; - - case 0x805: - osc.balance = data; - balance_changed( osc ); - break; - - case 0x806: - data &= 0x1F; - if ( !(osc.control & 0x40) ) - { - osc.wave [osc.phase] = data; - osc.phase = (osc.phase + 1) & 0x1F; - } - else if ( osc.control & 0x80 ) - { - osc.dac = data; - } - break; - - case 0x807: - if ( &osc >= &oscs [4] ) - osc.noise = data; - break; - - case 0x809: - if ( !(data & 0x80) && (data & 0x03) != 0 ) - debug_printf( "HES LFO not supported\n" ); - } - } -} - -void Hes_Apu::end_frame( blip_time_t end_time ) -{ - Hes_Osc* osc = &oscs [osc_count]; - do - { - osc--; - if ( end_time > osc->last_time ) - osc->run_until( synth, end_time ); - assert( osc->last_time >= end_time ); - osc->last_time -= end_time; - } - while ( osc != oscs ); -} diff --git a/libraries/game-music-emu/gme/Hes_Apu.h b/libraries/game-music-emu/gme/Hes_Apu.h deleted file mode 100644 index 1efc0a064..000000000 --- a/libraries/game-music-emu/gme/Hes_Apu.h +++ /dev/null @@ -1,66 +0,0 @@ -// Turbo Grafx 16 (PC Engine) PSG sound chip emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef HES_APU_H -#define HES_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -struct Hes_Osc -{ - unsigned char wave [32]; - short volume [2]; - int last_amp [2]; - int delay; - int period; - unsigned char noise; - unsigned char phase; - unsigned char balance; - unsigned char dac; - blip_time_t last_time; - - Blip_Buffer* outputs [2]; - Blip_Buffer* chans [3]; - unsigned noise_lfsr; - unsigned char control; - - enum { amp_range = 0x8000 }; - typedef Blip_Synth synth_t; - - void run_until( synth_t& synth, blip_time_t ); -}; - -class Hes_Apu { -public: - void treble_eq( blip_eq_t const& ); - void volume( double ); - - enum { osc_count = 6 }; - void osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ); - - void reset(); - - enum { start_addr = 0x0800 }; - enum { end_addr = 0x0809 }; - void write_data( blip_time_t, int addr, int data ); - - void end_frame( blip_time_t ); - -public: - Hes_Apu(); -private: - Hes_Osc oscs [osc_count]; - int latch; - int balance; - Hes_Osc::synth_t synth; - - void balance_changed( Hes_Osc& ); - void recalc_chans(); -}; - -inline void Hes_Apu::volume( double v ) { synth.volume( 1.8 / osc_count / Hes_Osc::amp_range * v ); } - -inline void Hes_Apu::treble_eq( blip_eq_t const& eq ) { synth.treble_eq( eq ); } - -#endif diff --git a/libraries/game-music-emu/gme/Hes_Cpu.cpp b/libraries/game-music-emu/gme/Hes_Cpu.cpp deleted file mode 100644 index 095a1851a..000000000 --- a/libraries/game-music-emu/gme/Hes_Cpu.cpp +++ /dev/null @@ -1,1295 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Hes_Cpu.h" - -#include "blargg_endian.h" - -//#include "hes_cpu_log.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -// TODO: support T flag, including clearing it at appropriate times? - -// all zero-page should really use whatever is at page 1, but that would -// reduce efficiency quite a bit -int const ram_addr = 0x2000; - -#define FLUSH_TIME() (void) (s.time = s_time) -#define CACHE_TIME() (void) (s_time = s.time) - -#include "hes_cpu_io.h" - -#include "blargg_source.h" - -#if BLARGG_NONPORTABLE - #define PAGE_OFFSET( addr ) (addr) -#else - #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) -#endif - -// status flags -int const st_n = 0x80; -int const st_v = 0x40; -int const st_t = 0x20; -int const st_b = 0x10; -int const st_d = 0x08; -int const st_i = 0x04; -int const st_z = 0x02; -int const st_c = 0x01; - -void Hes_Cpu::reset() -{ - check( state == &state_ ); - state = &state_; - - state_.time = 0; - state_.base = 0; - irq_time_ = future_hes_time; - end_time_ = future_hes_time; - - r.status = st_i; - r.sp = 0; - r.pc = 0; - r.a = 0; - r.x = 0; - r.y = 0; - - blargg_verify_byte_order(); -} - -void Hes_Cpu::set_mmr( int reg, int bank ) -{ - assert( (unsigned) reg <= page_count ); // allow page past end to be set - assert( (unsigned) bank < 0x100 ); - mmr [reg] = bank; - uint8_t const* code = CPU_SET_MMR( this, reg, bank ); - state->code_map [reg] = code - PAGE_OFFSET( reg << page_shift ); -} - -#define TIME (s_time + s.base) - -#define READ( addr ) CPU_READ( this, (addr), TIME ) -#define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), TIME );} -#define READ_LOW( addr ) (ram [int (addr)]) -#define WRITE_LOW( addr, data ) (void) (READ_LOW( addr ) = (data)) -#define READ_PROG( addr ) (s.code_map [(addr) >> page_shift] [PAGE_OFFSET( addr )]) - -#define SET_SP( v ) (sp = ((v) + 1) | 0x100) -#define GET_SP() ((sp - 1) & 0xFF) -#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v )) - -bool Hes_Cpu::run( hes_time_t end_time ) -{ - bool illegal_encountered = false; - set_end_time( end_time ); - state_t s = this->state_; - this->state = &s; - // even on x86, using s.time in place of s_time was slower - blargg_long s_time = s.time; - - // registers - uint_fast16_t pc = r.pc; - uint_fast8_t a = r.a; - uint_fast8_t x = r.x; - uint_fast8_t y = r.y; - uint_fast16_t sp; - SET_SP( r.sp ); - - #define IS_NEG (nz & 0x8080) - - #define CALC_STATUS( out ) do {\ - out = status & (st_v | st_d | st_i);\ - out |= ((nz >> 8) | nz) & st_n;\ - out |= c >> 8 & st_c;\ - if ( !(nz & 0xFF) ) out |= st_z;\ - } while ( 0 ) - - #define SET_STATUS( in ) do {\ - status = in & (st_v | st_d | st_i);\ - nz = in << 8;\ - c = nz;\ - nz |= ~in & st_z;\ - } while ( 0 ) - - uint_fast8_t status; - uint_fast16_t c; // carry set if (c & 0x100) != 0 - uint_fast16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 - { - uint_fast8_t temp = r.status; - SET_STATUS( temp ); - } - - goto loop; -branch_not_taken: - s_time -= 2; -loop: - - #ifndef NDEBUG - { - hes_time_t correct = end_time_; - if ( !(status & st_i) && correct > irq_time_ ) - correct = irq_time_; - check( s.base == correct ); - /* - static long count; - if ( count == 1844 ) Debugger(); - if ( s.base != correct ) debug_printf( "%ld\n", count ); - count++; - */ - } - #endif - - check( (unsigned) GET_SP() < 0x100 ); - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - - uint8_t const* instr = s.code_map [pc >> page_shift]; - uint_fast8_t opcode; - - // TODO: eliminate this special case - #if BLARGG_NONPORTABLE - opcode = instr [pc]; - pc++; - instr += pc; - #else - instr += PAGE_OFFSET( pc ); - opcode = *instr++; - pc++; - #endif - - // TODO: each reference lists slightly different timing values, ugh - static uint8_t const clock_table [256] = - {// 0 1 2 3 4 5 6 7 8 9 A B C D E F - 1,7,3, 4,6,4,6,7,3,2,2,2,7,5,7,6,// 0 - 4,7,7, 4,6,4,6,7,2,5,2,2,7,5,7,6,// 1 - 7,7,3, 4,4,4,6,7,4,2,2,2,5,5,7,6,// 2 - 4,7,7, 2,4,4,6,7,2,5,2,2,5,5,7,6,// 3 - 7,7,3, 4,8,4,6,7,3,2,2,2,4,5,7,6,// 4 - 4,7,7, 5,2,4,6,7,2,5,3,2,2,5,7,6,// 5 - 7,7,2, 2,4,4,6,7,4,2,2,2,7,5,7,6,// 6 - 4,7,7,17,4,4,6,7,2,5,4,2,7,5,7,6,// 7 - 4,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,6,// 8 - 4,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,6,// 9 - 2,7,2, 7,4,4,4,7,2,2,2,2,5,5,5,6,// A - 4,7,7, 8,4,4,4,7,2,5,2,2,5,5,5,6,// B - 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,6,// C - 4,7,7,17,2,4,6,7,2,5,3,2,2,5,7,6,// D - 2,7,2,17,4,4,6,7,2,2,2,2,5,5,7,6,// E - 4,7,7,17,2,4,6,7,2,5,4,2,2,5,7,6 // F - }; // 0x00 was 8 - - uint_fast16_t data; - data = clock_table [opcode]; - if ( (s_time += data) >= 0 ) - goto possibly_out_of_time; -almost_out_of_time: - - data = *instr; - - #ifdef HES_CPU_LOG_H - log_cpu( "new", pc - 1, opcode, instr [0], instr [1], instr [2], - instr [3], instr [4], instr [5] ); - //log_opcode( opcode ); - #endif - - switch ( opcode ) - { -possibly_out_of_time: - if ( s_time < (int) data ) - goto almost_out_of_time; - s_time -= data; - goto out_of_time; - -// Macros - -#define GET_MSB() (instr [1]) -#define ADD_PAGE( out ) (pc++, out = data + 0x100 * GET_MSB()); -#define GET_ADDR() GET_LE16( instr ) - -// TODO: is the penalty really always added? the original 6502 was much better -//#define PAGE_CROSS_PENALTY( lsb ) (void) (s_time += (lsb) >> 8) -#define PAGE_CROSS_PENALTY( lsb ) - -// Branch - -// TODO: more efficient way to handle negative branch that wraps PC around -#define BRANCH( cond )\ -{\ - int_fast16_t offset = (int8_t) data;\ - pc++;\ - if ( !(cond) ) goto branch_not_taken;\ - pc = uint16_t (pc + offset);\ - goto loop;\ -} - - case 0xF0: // BEQ - BRANCH( !((uint8_t) nz) ); - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ); - - case 0x10: // BPL - BRANCH( !IS_NEG ); - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - - case 0x30: // BMI - BRANCH( IS_NEG ) - - case 0x50: // BVC - BRANCH( !(status & st_v) ) - - case 0x70: // BVS - BRANCH( status & st_v ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x80: // BRA - branch_taken: - BRANCH( true ); - - case 0xFF: - if ( pc == idle_addr + 1 ) - goto idle_done; - case 0x0F: // BBRn - case 0x1F: - case 0x2F: - case 0x3F: - case 0x4F: - case 0x5F: - case 0x6F: - case 0x7F: - case 0x8F: // BBSn - case 0x9F: - case 0xAF: - case 0xBF: - case 0xCF: - case 0xDF: - case 0xEF: { - uint_fast16_t t = 0x101 * READ_LOW( data ); - t ^= 0xFF; - pc++; - data = GET_MSB(); - BRANCH( t & (1 << (opcode >> 4)) ) - } - - case 0x4C: // JMP abs - pc = GET_ADDR(); - goto loop; - - case 0x7C: // JMP (ind+X) - data += x; - case 0x6C:{// JMP (ind) - data += 0x100 * GET_MSB(); - pc = GET_LE16( &READ_PROG( data ) ); - goto loop; - } - -// Subroutine - - case 0x44: // BSR - WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); - sp = (sp - 2) | 0x100; - WRITE_LOW( sp, pc ); - goto branch_taken; - - case 0x20: { // JSR - uint_fast16_t temp = pc + 1; - pc = GET_ADDR(); - WRITE_LOW( 0x100 | (sp - 1), temp >> 8 ); - sp = (sp - 2) | 0x100; - WRITE_LOW( sp, temp ); - goto loop; - } - - case 0x60: // RTS - pc = 0x100 * READ_LOW( 0x100 | (sp - 0xFF) ); - pc += 1 + READ_LOW( sp ); - sp = (sp - 0xFE) | 0x100; - goto loop; - - case 0x00: // BRK - goto handle_brk; - -// Common - - case 0xBD:{// LDA abs,X - PAGE_CROSS_PENALTY( data + x ); - uint_fast16_t addr = GET_ADDR() + x; - pc += 2; - CPU_READ_FAST( this, addr, TIME, nz ); - a = nz; - goto loop; - } - - case 0x9D:{// STA abs,X - uint_fast16_t addr = GET_ADDR() + x; - pc += 2; - CPU_WRITE_FAST( this, addr, a, TIME ); - goto loop; - } - - case 0x95: // STA zp,x - data = uint8_t (data + x); - case 0x85: // STA zp - pc++; - WRITE_LOW( data, a ); - goto loop; - - case 0xAE:{// LDX abs - uint_fast16_t addr = GET_ADDR(); - pc += 2; - CPU_READ_FAST( this, addr, TIME, nz ); - x = nz; - goto loop; - } - - case 0xA5: // LDA zp - a = nz = READ_LOW( data ); - pc++; - goto loop; - -// Load/store - - { - uint_fast16_t addr; - case 0x91: // STA (ind),Y - addr = 0x100 * READ_LOW( uint8_t (data + 1) ); - addr += READ_LOW( data ) + y; - pc++; - goto sta_ptr; - - case 0x81: // STA (ind,X) - data = uint8_t (data + x); - case 0x92: // STA (ind) - addr = 0x100 * READ_LOW( uint8_t (data + 1) ); - addr += READ_LOW( data ); - pc++; - goto sta_ptr; - - case 0x99: // STA abs,Y - data += y; - case 0x8D: // STA abs - addr = data + 0x100 * GET_MSB(); - pc += 2; - sta_ptr: - CPU_WRITE_FAST( this, addr, a, TIME ); - goto loop; - } - - { - uint_fast16_t addr; - case 0xA1: // LDA (ind,X) - data = uint8_t (data + x); - case 0xB2: // LDA (ind) - addr = 0x100 * READ_LOW( uint8_t (data + 1) ); - addr += READ_LOW( data ); - pc++; - goto a_nz_read_addr; - - case 0xB1:// LDA (ind),Y - addr = READ_LOW( data ) + y; - PAGE_CROSS_PENALTY( addr ); - addr += 0x100 * READ_LOW( (uint8_t) (data + 1) ); - pc++; - goto a_nz_read_addr; - - case 0xB9: // LDA abs,Y - data += y; - PAGE_CROSS_PENALTY( data ); - case 0xAD: // LDA abs - addr = data + 0x100 * GET_MSB(); - pc += 2; - a_nz_read_addr: - CPU_READ_FAST( this, addr, TIME, nz ); - a = nz; - goto loop; - } - - case 0xBE:{// LDX abs,y - PAGE_CROSS_PENALTY( data + y ); - uint_fast16_t addr = GET_ADDR() + y; - pc += 2; - FLUSH_TIME(); - x = nz = READ( addr ); - CACHE_TIME(); - goto loop; - } - - case 0xB5: // LDA zp,x - a = nz = READ_LOW( uint8_t (data + x) ); - pc++; - goto loop; - - case 0xA9: // LDA #imm - pc++; - a = data; - nz = data; - goto loop; - -// Bit operations - - case 0x3C: // BIT abs,x - data += x; - case 0x2C:{// BIT abs - uint_fast16_t addr; - ADD_PAGE( addr ); - FLUSH_TIME(); - nz = READ( addr ); - CACHE_TIME(); - goto bit_common; - } - case 0x34: // BIT zp,x - data = uint8_t (data + x); - case 0x24: // BIT zp - data = READ_LOW( data ); - case 0x89: // BIT imm - nz = data; - bit_common: - pc++; - status &= ~st_v; - status |= nz & st_v; - if ( nz & a ) - goto loop; // Z should be clear, and nz must be non-zero if nz & a is - nz <<= 8; // set Z flag without affecting N flag - goto loop; - - { - uint_fast16_t addr; - - case 0xB3: // TST abs,x - addr = GET_MSB() + x; - goto tst_abs; - - case 0x93: // TST abs - addr = GET_MSB(); - tst_abs: - addr += 0x100 * instr [2]; - pc++; - FLUSH_TIME(); - nz = READ( addr ); - CACHE_TIME(); - goto tst_common; - } - - case 0xA3: // TST zp,x - nz = READ_LOW( uint8_t (GET_MSB() + x) ); - goto tst_common; - - case 0x83: // TST zp - nz = READ_LOW( GET_MSB() ); - tst_common: - pc += 2; - status &= ~st_v; - status |= nz & st_v; - if ( nz & data ) - goto loop; // Z should be clear, and nz must be non-zero if nz & data is - nz <<= 8; // set Z flag without affecting N flag - goto loop; - - { - uint_fast16_t addr; - case 0x0C: // TSB abs - case 0x1C: // TRB abs - addr = GET_ADDR(); - pc++; - goto txb_addr; - - // TODO: everyone lists different behaviors for the status flags, ugh - case 0x04: // TSB zp - case 0x14: // TRB zp - addr = data + ram_addr; - txb_addr: - FLUSH_TIME(); - nz = a | READ( addr ); - if ( opcode & 0x10 ) - nz ^= a; // bits from a will already be set, so this clears them - status &= ~st_v; - status |= nz & st_v; - pc++; - WRITE( addr, nz ); - CACHE_TIME(); - goto loop; - } - - case 0x07: // RMBn - case 0x17: - case 0x27: - case 0x37: - case 0x47: - case 0x57: - case 0x67: - case 0x77: - pc++; - READ_LOW( data ) &= ~(1 << (opcode >> 4)); - goto loop; - - case 0x87: // SMBn - case 0x97: - case 0xA7: - case 0xB7: - case 0xC7: - case 0xD7: - case 0xE7: - case 0xF7: - pc++; - READ_LOW( data ) |= 1 << ((opcode >> 4) - 8); - goto loop; - -// Load/store - - case 0x9E: // STZ abs,x - data += x; - case 0x9C: // STZ abs - ADD_PAGE( data ); - pc++; - FLUSH_TIME(); - WRITE( data, 0 ); - CACHE_TIME(); - goto loop; - - case 0x74: // STZ zp,x - data = uint8_t (data + x); - case 0x64: // STZ zp - pc++; - WRITE_LOW( data, 0 ); - goto loop; - - case 0x94: // STY zp,x - data = uint8_t (data + x); - case 0x84: // STY zp - pc++; - WRITE_LOW( data, y ); - goto loop; - - case 0x96: // STX zp,y - data = uint8_t (data + y); - case 0x86: // STX zp - pc++; - WRITE_LOW( data, x ); - goto loop; - - case 0xB6: // LDX zp,y - data = uint8_t (data + y); - case 0xA6: // LDX zp - data = READ_LOW( data ); - case 0xA2: // LDX #imm - pc++; - x = data; - nz = data; - goto loop; - - case 0xB4: // LDY zp,x - data = uint8_t (data + x); - case 0xA4: // LDY zp - data = READ_LOW( data ); - case 0xA0: // LDY #imm - pc++; - y = data; - nz = data; - goto loop; - - case 0xBC: // LDY abs,X - data += x; - PAGE_CROSS_PENALTY( data ); - case 0xAC:{// LDY abs - uint_fast16_t addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - y = nz = READ( addr ); - CACHE_TIME(); - goto loop; - } - - { - uint_fast8_t temp; - case 0x8C: // STY abs - temp = y; - goto store_abs; - - case 0x8E: // STX abs - temp = x; - store_abs: - uint_fast16_t addr = GET_ADDR(); - pc += 2; - FLUSH_TIME(); - WRITE( addr, temp ); - CACHE_TIME(); - goto loop; - } - -// Compare - - case 0xEC:{// CPX abs - uint_fast16_t addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ( addr ); - CACHE_TIME(); - goto cpx_data; - } - - case 0xE4: // CPX zp - data = READ_LOW( data ); - case 0xE0: // CPX #imm - cpx_data: - nz = x - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0xCC:{// CPY abs - uint_fast16_t addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ( addr ); - CACHE_TIME(); - goto cpy_data; - } - - case 0xC4: // CPY zp - data = READ_LOW( data ); - case 0xC0: // CPY #imm - cpy_data: - nz = y - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - -// Logical - -#define ARITH_ADDR_MODES( op )\ - case op - 0x04: /* (ind,x) */\ - data = uint8_t (data + x);\ - case op + 0x0D: /* (ind) */\ - data = 0x100 * READ_LOW( uint8_t (data + 1) ) + READ_LOW( data );\ - goto ptr##op;\ - case op + 0x0C:{/* (ind),y */\ - uint_fast16_t temp = READ_LOW( data ) + y;\ - PAGE_CROSS_PENALTY( temp );\ - data = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\ - goto ptr##op;\ - }\ - case op + 0x10: /* zp,X */\ - data = uint8_t (data + x);\ - case op + 0x00: /* zp */\ - data = READ_LOW( data );\ - goto imm##op;\ - case op + 0x14: /* abs,Y */\ - data += y;\ - goto ind##op;\ - case op + 0x18: /* abs,X */\ - data += x;\ - ind##op:\ - PAGE_CROSS_PENALTY( data );\ - case op + 0x08: /* abs */\ - ADD_PAGE( data );\ - ptr##op:\ - FLUSH_TIME();\ - data = READ( data );\ - CACHE_TIME();\ - case op + 0x04: /* imm */\ - imm##op: - - ARITH_ADDR_MODES( 0xC5 ) // CMP - nz = a - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - ARITH_ADDR_MODES( 0x25 ) // AND - nz = (a &= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x45 ) // EOR - nz = (a ^= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x05 ) // ORA - nz = (a |= data); - pc++; - goto loop; - -// Add/subtract - - ARITH_ADDR_MODES( 0xE5 ) // SBC - data ^= 0xFF; - goto adc_imm; - - ARITH_ADDR_MODES( 0x65 ) // ADC - adc_imm: { - if ( status & st_d ) - debug_printf( "Decimal mode not supported\n" ); - int_fast16_t carry = c >> 8 & 1; - int_fast16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend - status &= ~st_v; - status |= ov >> 2 & 0x40; - c = nz = a + data + carry; - pc++; - a = (uint8_t) nz; - goto loop; - } - -// Shift/rotate - - case 0x4A: // LSR A - c = 0; - case 0x6A: // ROR A - nz = c >> 1 & 0x80; - c = a << 8; - nz |= a >> 1; - a = nz; - goto loop; - - case 0x0A: // ASL A - nz = a << 1; - c = nz; - a = (uint8_t) nz; - goto loop; - - case 0x2A: { // ROL A - nz = a << 1; - int_fast16_t temp = c >> 8 & 1; - c = nz; - nz |= temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x5E: // LSR abs,X - data += x; - case 0x4E: // LSR abs - c = 0; - case 0x6E: // ROR abs - ror_abs: { - ADD_PAGE( data ); - FLUSH_TIME(); - int temp = READ( data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - goto rotate_common; - } - - case 0x3E: // ROL abs,X - data += x; - goto rol_abs; - - case 0x1E: // ASL abs,X - data += x; - case 0x0E: // ASL abs - c = 0; - case 0x2E: // ROL abs - rol_abs: - ADD_PAGE( data ); - nz = c >> 8 & 1; - FLUSH_TIME(); - nz |= (c = READ( data ) << 1); - rotate_common: - pc++; - WRITE( data, (uint8_t) nz ); - CACHE_TIME(); - goto loop; - - case 0x7E: // ROR abs,X - data += x; - goto ror_abs; - - case 0x76: // ROR zp,x - data = uint8_t (data + x); - goto ror_zp; - - case 0x56: // LSR zp,x - data = uint8_t (data + x); - case 0x46: // LSR zp - c = 0; - case 0x66: // ROR zp - ror_zp: { - int temp = READ_LOW( data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - goto write_nz_zp; - } - - case 0x36: // ROL zp,x - data = uint8_t (data + x); - goto rol_zp; - - case 0x16: // ASL zp,x - data = uint8_t (data + x); - case 0x06: // ASL zp - c = 0; - case 0x26: // ROL zp - rol_zp: - nz = c >> 8 & 1; - nz |= (c = READ_LOW( data ) << 1); - goto write_nz_zp; - -// Increment/decrement - -#define INC_DEC_AXY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; - - case 0x1A: // INA - INC_DEC_AXY( a, +1 ) - - case 0xE8: // INX - INC_DEC_AXY( x, +1 ) - - case 0xC8: // INY - INC_DEC_AXY( y, +1 ) - - case 0x3A: // DEA - INC_DEC_AXY( a, -1 ) - - case 0xCA: // DEX - INC_DEC_AXY( x, -1 ) - - case 0x88: // DEY - INC_DEC_AXY( y, -1 ) - - case 0xF6: // INC zp,x - data = uint8_t (data + x); - case 0xE6: // INC zp - nz = 1; - goto add_nz_zp; - - case 0xD6: // DEC zp,x - data = uint8_t (data + x); - case 0xC6: // DEC zp - nz = (unsigned) -1; - add_nz_zp: - nz += READ_LOW( data ); - write_nz_zp: - pc++; - WRITE_LOW( data, nz ); - goto loop; - - case 0xFE: // INC abs,x - data = x + GET_ADDR(); - goto inc_ptr; - - case 0xEE: // INC abs - data = GET_ADDR(); - inc_ptr: - nz = 1; - goto inc_common; - - case 0xDE: // DEC abs,x - data = x + GET_ADDR(); - goto dec_ptr; - - case 0xCE: // DEC abs - data = GET_ADDR(); - dec_ptr: - nz = (unsigned) -1; - inc_common: - FLUSH_TIME(); - nz += READ( data ); - pc += 2; - WRITE( data, (uint8_t) nz ); - CACHE_TIME(); - goto loop; - -// Transfer - - case 0xA8: // TAY - y = a; - nz = a; - goto loop; - - case 0x98: // TYA - a = y; - nz = y; - goto loop; - - case 0xAA: // TAX - x = a; - nz = a; - goto loop; - - case 0x8A: // TXA - a = x; - nz = x; - goto loop; - - case 0x9A: // TXS - SET_SP( x ); // verified (no flag change) - goto loop; - - case 0xBA: // TSX - x = nz = GET_SP(); - goto loop; - - #define SWAP_REGS( r1, r2 ) {\ - uint_fast8_t t = r1;\ - r1 = r2;\ - r2 = t;\ - goto loop;\ - } - - case 0x02: // SXY - SWAP_REGS( x, y ); - - case 0x22: // SAX - SWAP_REGS( a, x ); - - case 0x42: // SAY - SWAP_REGS( a, y ); - - case 0x62: // CLA - a = 0; - goto loop; - - case 0x82: // CLX - x = 0; - goto loop; - - case 0xC2: // CLY - y = 0; - goto loop; - -// Stack - - case 0x48: // PHA - PUSH( a ); - goto loop; - - case 0xDA: // PHX - PUSH( x ); - goto loop; - - case 0x5A: // PHY - PUSH( y ); - goto loop; - - case 0x40:{// RTI - uint_fast8_t temp = READ_LOW( sp ); - pc = READ_LOW( 0x100 | (sp - 0xFF) ); - pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100; - sp = (sp - 0xFD) | 0x100; - data = status; - SET_STATUS( temp ); - this->r.status = status; // update externally-visible I flag - if ( (data ^ status) & st_i ) - { - hes_time_t new_time = end_time_; - if ( !(status & st_i) && new_time > irq_time_ ) - new_time = irq_time_; - blargg_long delta = s.base - new_time; - s.base = new_time; - s_time += delta; - } - goto loop; - } - - #define POP() READ_LOW( sp ); sp = (sp - 0xFF) | 0x100 - - case 0x68: // PLA - a = nz = POP(); - goto loop; - - case 0xFA: // PLX - x = nz = POP(); - goto loop; - - case 0x7A: // PLY - y = nz = POP(); - goto loop; - - case 0x28:{// PLP - uint_fast8_t temp = POP(); - uint_fast8_t changed = status ^ temp; - SET_STATUS( temp ); - if ( !(changed & st_i) ) - goto loop; // I flag didn't change - if ( status & st_i ) - goto handle_sei; - goto handle_cli; - } - #undef POP - - case 0x08: { // PHP - uint_fast8_t temp; - CALC_STATUS( temp ); - PUSH( temp | st_b ); - goto loop; - } - -// Flags - - case 0x38: // SEC - c = (unsigned) ~0; - goto loop; - - case 0x18: // CLC - c = 0; - goto loop; - - case 0xB8: // CLV - status &= ~st_v; - goto loop; - - case 0xD8: // CLD - status &= ~st_d; - goto loop; - - case 0xF8: // SED - status |= st_d; - goto loop; - - case 0x58: // CLI - if ( !(status & st_i) ) - goto loop; - status &= ~st_i; - handle_cli: { - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - irq_time_; - if ( delta <= 0 ) - { - if ( TIME < irq_time_ ) - goto loop; - goto delayed_cli; - } - s.base = irq_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - if ( delta >= s_time + 1 ) - { - // delayed irq until after next instruction - s.base += s_time + 1; - s_time = -1; - irq_time_ = s.base; // TODO: remove, as only to satisfy debug check in loop - goto loop; - } - delayed_cli: - debug_printf( "Delayed CLI not supported\n" ); // TODO: implement - goto loop; - } - - case 0x78: // SEI - if ( status & st_i ) - goto loop; - status |= st_i; - handle_sei: { - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - end_time_; - s.base = end_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - debug_printf( "Delayed SEI not supported\n" ); // TODO: implement - goto loop; - } - -// Special - - case 0x53:{// TAM - uint_fast8_t const bits = data; // avoid using data across function call - pc++; - for ( int i = 0; i < 8; i++ ) - if ( bits & (1 << i) ) - set_mmr( i, a ); - goto loop; - } - - case 0x43:{// TMA - pc++; - byte const* in = mmr; - do - { - if ( data & 1 ) - a = *in; - in++; - } - while ( (data >>= 1) != 0 ); - goto loop; - } - - case 0x03: // ST0 - case 0x13: // ST1 - case 0x23:{// ST2 - uint_fast16_t addr = opcode >> 4; - if ( addr ) - addr++; - pc++; - FLUSH_TIME(); - CPU_WRITE_VDP( this, addr, data, TIME ); - CACHE_TIME(); - goto loop; - } - - case 0xEA: // NOP - goto loop; - - case 0x54: // CSL - debug_printf( "CSL not supported\n" ); - illegal_encountered = true; - goto loop; - - case 0xD4: // CSH - goto loop; - - case 0xF4: { // SET - //fuint16 operand = GET_MSB(); - debug_printf( "SET not handled\n" ); - //switch ( data ) - //{ - //} - illegal_encountered = true; - goto loop; - } - -// Block transfer - - { - uint_fast16_t in_alt; - int_fast16_t in_inc; - uint_fast16_t out_alt; - int_fast16_t out_inc; - - case 0xE3: // TIA - in_alt = 0; - goto bxfer_alt; - - case 0xF3: // TAI - in_alt = 1; - bxfer_alt: - in_inc = in_alt ^ 1; - out_alt = in_inc; - out_inc = in_alt; - goto bxfer; - - case 0xD3: // TIN - in_inc = 1; - out_inc = 0; - goto bxfer_no_alt; - - case 0xC3: // TDD - in_inc = -1; - out_inc = -1; - goto bxfer_no_alt; - - case 0x73: // TII - in_inc = 1; - out_inc = 1; - bxfer_no_alt: - in_alt = 0; - out_alt = 0; - bxfer: - uint_fast16_t in = GET_LE16( instr + 0 ); - uint_fast16_t out = GET_LE16( instr + 2 ); - int count = GET_LE16( instr + 4 ); - if ( !count ) - count = 0x10000; - pc += 6; - WRITE_LOW( 0x100 | (sp - 1), y ); - WRITE_LOW( 0x100 | (sp - 2), a ); - WRITE_LOW( 0x100 | (sp - 3), x ); - FLUSH_TIME(); - do - { - // TODO: reads from $0800-$1400 in I/O page return 0 and don't access I/O - uint_fast8_t t = READ( in ); - in += in_inc; - in &= 0xFFFF; - s.time += 6; - if ( in_alt ) - in_inc = -in_inc; - WRITE( out, t ); - out += out_inc; - out &= 0xFFFF; - if ( out_alt ) - out_inc = -out_inc; - } - while ( --count ); - CACHE_TIME(); - goto loop; - } - -// Illegal - - default: - debug_printf( "Illegal opcode $%02X at $%04X\n", (int) opcode, (int) pc - 1 ); - illegal_encountered = true; - goto loop; - } - assert( false ); - - int result_; -handle_brk: - pc++; - result_ = 6; - -interrupt: - { - s_time += 7; - - WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); - WRITE_LOW( 0x100 | (sp - 2), pc ); - pc = GET_LE16( &READ_PROG( 0xFFF0 ) + result_ ); - - sp = (sp - 3) | 0x100; - uint_fast8_t temp; - CALC_STATUS( temp ); - if ( result_ == 6 ) - temp |= st_b; - WRITE_LOW( sp, temp ); - - status &= ~st_d; - status |= st_i; - this->r.status = status; // update externally-visible I flag - - blargg_long delta = s.base - end_time_; - s.base = end_time_; - s_time += delta; - goto loop; - } - -idle_done: - s_time = 0; -out_of_time: - pc--; - FLUSH_TIME(); - CPU_DONE( this, TIME, result_ ); - CACHE_TIME(); - if ( result_ > 0 ) - goto interrupt; - if ( s_time < 0 ) - goto loop; - - s.time = s_time; - - r.pc = pc; - r.sp = GET_SP(); - r.a = a; - r.x = x; - r.y = y; - - { - uint_fast8_t temp; - CALC_STATUS( temp ); - r.status = temp; - } - - this->state_ = s; - this->state = &this->state_; - - return illegal_encountered; -} diff --git a/libraries/game-music-emu/gme/Hes_Cpu.h b/libraries/game-music-emu/gme/Hes_Cpu.h deleted file mode 100644 index cec46fa9e..000000000 --- a/libraries/game-music-emu/gme/Hes_Cpu.h +++ /dev/null @@ -1,122 +0,0 @@ -// PC Engine CPU emulator for use with HES music files - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef HES_CPU_H -#define HES_CPU_H - -#include "blargg_common.h" - -typedef blargg_long hes_time_t; // clock cycle count -typedef unsigned hes_addr_t; // 16-bit address -enum { future_hes_time = INT_MAX / 2 + 1 }; - -class Hes_Cpu { -public: - void reset(); - - enum { page_size = 0x2000 }; - enum { page_shift = 13 }; - enum { page_count = 8 }; - void set_mmr( int reg, int bank ); - - uint8_t const* get_code( hes_addr_t ); - - uint8_t ram [page_size]; - - // not kept updated during a call to run() - struct registers_t { - uint16_t pc; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t status; - uint8_t sp; - }; - registers_t r; - - // page mapping registers - uint8_t mmr [page_count + 1]; - - // Set end_time and run CPU from current time. Returns true if any illegal - // instructions were encountered. - bool run( hes_time_t end_time ); - - // Time of beginning of next instruction to be executed - hes_time_t time() const { return state->time + state->base; } - void set_time( hes_time_t t ) { state->time = t - state->base; } - void adjust_time( int delta ) { state->time += delta; } - - hes_time_t irq_time() const { return irq_time_; } - void set_irq_time( hes_time_t ); - - hes_time_t end_time() const { return end_time_; } - void set_end_time( hes_time_t ); - - void end_frame( hes_time_t ); - - // Attempt to execute instruction here results in CPU advancing time to - // lesser of irq_time() and end_time() (or end_time() if IRQs are - // disabled) - enum { idle_addr = 0x1FFF }; - - // Can read this many bytes past end of a page - enum { cpu_padding = 8 }; - -public: - Hes_Cpu() { state = &state_; } - enum { irq_inhibit = 0x04 }; -private: - // noncopyable - Hes_Cpu( const Hes_Cpu& ); - Hes_Cpu& operator = ( const Hes_Cpu& ); - - struct state_t { - uint8_t const* code_map [page_count + 1]; - hes_time_t base; - blargg_long time; - }; - state_t* state; // points to state_ or a local copy within run() - state_t state_; - hes_time_t irq_time_; - hes_time_t end_time_; - - void set_code_page( int, void const* ); - inline int update_end_time( hes_time_t end, hes_time_t irq ); -}; - -inline uint8_t const* Hes_Cpu::get_code( hes_addr_t addr ) -{ - return state->code_map [addr >> page_shift] + addr - #if !BLARGG_NONPORTABLE - % (unsigned) page_size - #endif - ; -} - -inline int Hes_Cpu::update_end_time( hes_time_t t, hes_time_t irq ) -{ - if ( irq < t && !(r.status & irq_inhibit) ) t = irq; - int delta = state->base - t; - state->base = t; - return delta; -} - -inline void Hes_Cpu::set_irq_time( hes_time_t t ) -{ - state->time += update_end_time( end_time_, (irq_time_ = t) ); -} - -inline void Hes_Cpu::set_end_time( hes_time_t t ) -{ - state->time += update_end_time( (end_time_ = t), irq_time_ ); -} - -inline void Hes_Cpu::end_frame( hes_time_t t ) -{ - assert( state == &state_ ); - state_.base -= t; - if ( irq_time_ < future_hes_time ) irq_time_ -= t; - if ( end_time_ < future_hes_time ) end_time_ -= t; -} - -#endif diff --git a/libraries/game-music-emu/gme/Hes_Emu.cpp b/libraries/game-music-emu/gme/Hes_Emu.cpp deleted file mode 100644 index 818691fdc..000000000 --- a/libraries/game-music-emu/gme/Hes_Emu.cpp +++ /dev/null @@ -1,531 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Hes_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -int const timer_mask = 0x04; -int const vdp_mask = 0x02; -int const i_flag_mask = 0x04; -int const unmapped = 0xFF; - -long const period_60hz = 262 * 455L; // scanlines * clocks per scanline - -Hes_Emu::Hes_Emu() -{ - timer.raw_load = 0; - set_type( gme_hes_type ); - - static const char* const names [Hes_Apu::osc_count] = { - "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Multi 1", "Multi 2" - }; - set_voice_names( names ); - - static int const types [Hes_Apu::osc_count] = { - wave_type | 0, wave_type | 1, wave_type | 2, wave_type | 3, - mixed_type | 0, mixed_type | 1 - }; - set_voice_types( types ); - set_silence_lookahead( 6 ); - set_gain( 1.11 ); -} - -Hes_Emu::~Hes_Emu() { } - -void Hes_Emu::unload() -{ - rom.clear(); - Music_Emu::unload(); -} - -// Track info - -static byte const* copy_field( byte const* in, char* out ) -{ - if ( in ) - { - int len = 0x20; - if ( in [0x1F] && !in [0x2F] ) - len = 0x30; // fields are sometimes 16 bytes longer (ugh) - - // since text fields are where any data could be, detect non-text - // and fields with data after zero byte terminator - - int i = 0; - for ( i = 0; i < len && in [i]; i++ ) - if ( ((in [i] + 1) & 0xFF) < ' ' + 1 ) // also treat 0xFF as non-text - return 0; // non-ASCII found - - for ( ; i < len; i++ ) - if ( in [i] ) - return 0; // data after terminator - - Gme_File::copy_field_( out, (char const*) in, len ); - in += len; - } - return in; -} - -static void copy_hes_fields( byte const* in, track_info_t* out ) -{ - if ( *in >= ' ' ) - { - in = copy_field( in, out->game ); - in = copy_field( in, out->author ); - in = copy_field( in, out->copyright ); - } -} - -blargg_err_t Hes_Emu::track_info_( track_info_t* out, int ) const -{ - copy_hes_fields( rom.begin() + 0x20, out ); - return 0; -} - -static blargg_err_t check_hes_header( void const* header ) -{ - if ( memcmp( header, "HESM", 4 ) ) - return gme_wrong_file_type; - return 0; -} - -struct Hes_File : Gme_Info_ -{ - struct header_t { - char header [Hes_Emu::header_size]; - char unused [0x20]; - byte fields [0x30 * 3]; - } h; - - Hes_File() { set_type( gme_hes_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - assert( offsetof (header_t,fields) == Hes_Emu::header_size + 0x20 ); - blargg_err_t err = in.read( &h, sizeof h ); - if ( err ) - return (err == in.eof_error ? gme_wrong_file_type : err); - return check_hes_header( &h ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_hes_fields( h.fields, out ); - return 0; - } -}; - -static Music_Emu* new_hes_emu () { return BLARGG_NEW Hes_Emu ; } -static Music_Emu* new_hes_file() { return BLARGG_NEW Hes_File; } - -static gme_type_t_ const gme_hes_type_ = { "PC Engine", 256, &new_hes_emu, &new_hes_file, "HES", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_hes_type = &gme_hes_type_; - - -// Setup - -blargg_err_t Hes_Emu::load_( Data_Reader& in ) -{ - assert( offsetof (header_t,unused [4]) == header_size ); - RETURN_ERR( rom.load( in, header_size, &header_, unmapped ) ); - - RETURN_ERR( check_hes_header( header_.tag ) ); - - if ( header_.vers != 0 ) - set_warning( "Unknown file version" ); - - if ( memcmp( header_.data_tag, "DATA", 4 ) ) - set_warning( "Data header missing" ); - - if ( memcmp( header_.unused, "\0\0\0\0", 4 ) ) - set_warning( "Unknown header data" ); - - // File spec supports multiple blocks, but I haven't found any, and - // many files have bad sizes in the only block, so it's simpler to - // just try to load the damn data as best as possible. - - long addr = get_le32( header_.addr ); - long size = get_le32( header_.size ); - long const rom_max = 0x100000; - if ( addr & ~(rom_max - 1) ) - { - set_warning( "Invalid address" ); - addr &= rom_max - 1; - } - if ( (unsigned long) (addr + size) > (unsigned long) rom_max ) - set_warning( "Invalid size" ); - - if ( size != rom.file_size() ) - { - if ( size <= rom.file_size() - 4 && !memcmp( rom.begin() + size, "DATA", 4 ) ) - set_warning( "Multiple DATA not supported" ); - else if ( size < rom.file_size() ) - set_warning( "Extra file data" ); - else - set_warning( "Missing file data" ); - } - - rom.set_addr( addr ); - - set_voice_count( apu.osc_count ); - - apu.volume( gain() ); - - return setup_buffer( 7159091 ); -} - -void Hes_Emu::update_eq( blip_eq_t const& eq ) -{ - apu.treble_eq( eq ); -} - -void Hes_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - apu.osc_output( i, center, left, right ); -} - -// Emulation - -void Hes_Emu::recalc_timer_load() -{ - timer.load = timer.raw_load * timer_base + 1; -} - -void Hes_Emu::set_tempo_( double t ) -{ - play_period = hes_time_t (period_60hz / t); - timer_base = int (1024 / t); - recalc_timer_load(); -} - -blargg_err_t Hes_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - memset( ram, 0, sizeof ram ); // some HES music relies on zero fill - memset( sgx, 0, sizeof sgx ); - - apu.reset(); - cpu::reset(); - - for ( unsigned i = 0; i < sizeof header_.banks; i++ ) - set_mmr( i, header_.banks [i] ); - set_mmr( page_count, 0xFF ); // unmapped beyond end of address space - - irq.disables = timer_mask | vdp_mask; - irq.timer = future_hes_time; - irq.vdp = future_hes_time; - - timer.enabled = false; - timer.raw_load= 0x80; - timer.count = timer.load; - timer.fired = false; - timer.last_time = 0; - - vdp.latch = 0; - vdp.control = 0; - vdp.next_vbl = 0; - - ram [0x1FF] = (idle_addr - 1) >> 8; - ram [0x1FE] = (idle_addr - 1) & 0xFF; - r.sp = 0xFD; - r.pc = get_le16( header_.init_addr ); - r.a = track; - - recalc_timer_load(); - last_frame_hook = 0; - - return 0; -} - -// Hardware - -void Hes_Emu::cpu_write_vdp( int addr, int data ) -{ - switch ( addr ) - { - case 0: - vdp.latch = data & 0x1F; - break; - - case 2: - if ( vdp.latch == 5 ) - { - if ( data & 0x04 ) - set_warning( "Scanline interrupt unsupported" ); - run_until( time() ); - vdp.control = data; - irq_changed(); - } - else - { - debug_printf( "VDP not supported: $%02X <- $%02X\n", vdp.latch, data ); - } - break; - - case 3: - debug_printf( "VDP MSB not supported: $%02X <- $%02X\n", vdp.latch, data ); - break; - } -} - -void Hes_Emu::cpu_write_( hes_addr_t addr, int data ) -{ - if ( unsigned (addr - apu.start_addr) <= apu.end_addr - apu.start_addr ) - { - GME_APU_HOOK( this, addr - apu.start_addr, data ); - // avoid going way past end when a long block xfer is writing to I/O space - hes_time_t t = min( time(), end_time() + 8 ); - apu.write_data( t, addr, data ); - return; - } - - hes_time_t time = this->time(); - switch ( addr ) - { - case 0x0000: - case 0x0002: - case 0x0003: - cpu_write_vdp( addr, data ); - return; - - case 0x0C00: { - run_until( time ); - timer.raw_load = (data & 0x7F) + 1; - recalc_timer_load(); - timer.count = timer.load; - break; - } - - case 0x0C01: - data &= 1; - if ( timer.enabled == data ) - return; - run_until( time ); - timer.enabled = data; - if ( data ) - timer.count = timer.load; - break; - - case 0x1402: - run_until( time ); - irq.disables = data; - if ( (data & 0xF8) && (data & 0xF8) != 0xF8 ) // flag questionable values - debug_printf( "Int mask: $%02X\n", data ); - break; - - case 0x1403: - run_until( time ); - if ( timer.enabled ) - timer.count = timer.load; - timer.fired = false; - break; - -#ifndef NDEBUG - case 0x1000: // I/O port - case 0x0402: // palette - case 0x0403: - case 0x0404: - case 0x0405: - return; - - default: - debug_printf( "unmapped write $%04X <- $%02X\n", addr, data ); - return; -#endif - } - - irq_changed(); -} - -int Hes_Emu::cpu_read_( hes_addr_t addr ) -{ - hes_time_t time = this->time(); - addr &= page_size - 1; - switch ( addr ) - { - case 0x0000: - if ( irq.vdp > time ) - return 0; - irq.vdp = future_hes_time; - run_until( time ); - irq_changed(); - return 0x20; - - case 0x0002: - case 0x0003: - debug_printf( "VDP read not supported: %d\n", addr ); - return 0; - - case 0x0C01: - //return timer.enabled; // TODO: remove? - case 0x0C00: - run_until( time ); - debug_printf( "Timer count read\n" ); - return (unsigned) (timer.count - 1) / timer_base; - - case 0x1402: - return irq.disables; - - case 0x1403: - { - int status = 0; - if ( irq.timer <= time ) status |= timer_mask; - if ( irq.vdp <= time ) status |= vdp_mask; - return status; - } - - #ifndef NDEBUG - case 0x1000: // I/O port - case 0x180C: // CD-ROM - case 0x180D: - break; - - default: - debug_printf( "unmapped read $%04X\n", addr ); - #endif - } - - return unmapped; -} - -// see hes_cpu_io.h for core read/write functions - -// Emulation - -void Hes_Emu::run_until( hes_time_t present ) -{ - while ( vdp.next_vbl < present ) - vdp.next_vbl += play_period; - - hes_time_t elapsed = present - timer.last_time; - if ( elapsed > 0 ) - { - if ( timer.enabled ) - { - timer.count -= elapsed; - if ( timer.count <= 0 ) - timer.count += timer.load; - } - timer.last_time = present; - } -} - -void Hes_Emu::irq_changed() -{ - hes_time_t present = time(); - - if ( irq.timer > present ) - { - irq.timer = future_hes_time; - if ( timer.enabled && !timer.fired ) - irq.timer = present + timer.count; - } - - if ( irq.vdp > present ) - { - irq.vdp = future_hes_time; - if ( vdp.control & 0x08 ) - irq.vdp = vdp.next_vbl; - } - - hes_time_t time = future_hes_time; - if ( !(irq.disables & timer_mask) ) time = irq.timer; - if ( !(irq.disables & vdp_mask) ) time = min( time, irq.vdp ); - - set_irq_time( time ); -} - -int Hes_Emu::cpu_done() -{ - check( time() >= end_time() || - (!(r.status & i_flag_mask) && time() >= irq_time()) ); - - if ( !(r.status & i_flag_mask) ) - { - hes_time_t present = time(); - - if ( irq.timer <= present && !(irq.disables & timer_mask) ) - { - timer.fired = true; - irq.timer = future_hes_time; - irq_changed(); // overkill, but not worth writing custom code - #if GME_FRAME_HOOK_DEFINED - { - unsigned const threshold = period_60hz / 30; - unsigned long elapsed = present - last_frame_hook; - if ( elapsed - period_60hz + threshold / 2 < threshold ) - { - last_frame_hook = present; - GME_FRAME_HOOK( this ); - } - } - #endif - return 0x0A; - } - - if ( irq.vdp <= present && !(irq.disables & vdp_mask) ) - { - // work around for bugs with music not acknowledging VDP - //run_until( present ); - //irq.vdp = future_hes_time; - //irq_changed(); - #if GME_FRAME_HOOK_DEFINED - last_frame_hook = present; - GME_FRAME_HOOK( this ); - #endif - return 0x08; - } - } - return 0; -} - -static void adjust_time( blargg_long& time, hes_time_t delta ) -{ - if ( time < future_hes_time ) - { - time -= delta; - if ( time < 0 ) - time = 0; - } -} - -blargg_err_t Hes_Emu::run_clocks( blip_time_t& duration_, int ) -{ - blip_time_t const duration = duration_; // cache - - if ( cpu::run( duration ) ) - set_warning( "Emulation error (illegal instruction)" ); - - check( time() >= duration ); - //check( time() - duration < 20 ); // Txx instruction could cause going way over - - run_until( duration ); - - // end time frame - timer.last_time -= duration; - vdp.next_vbl -= duration; - #if GME_FRAME_HOOK_DEFINED - last_frame_hook -= duration; - #endif - cpu::end_frame( duration ); - ::adjust_time( irq.timer, duration ); - ::adjust_time( irq.vdp, duration ); - apu.end_frame( duration ); - - return 0; -} diff --git a/libraries/game-music-emu/gme/Hes_Emu.h b/libraries/game-music-emu/gme/Hes_Emu.h deleted file mode 100644 index 08c1370d4..000000000 --- a/libraries/game-music-emu/gme/Hes_Emu.h +++ /dev/null @@ -1,94 +0,0 @@ -// TurboGrafx-16/PC Engine HES music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef HES_EMU_H -#define HES_EMU_H - -#include "Classic_Emu.h" -#include "Hes_Apu.h" -#include "Hes_Cpu.h" - -class Hes_Emu : private Hes_Cpu, public Classic_Emu { - typedef Hes_Cpu cpu; -public: - // HES file header - enum { header_size = 0x20 }; - struct header_t - { - byte tag [4]; - byte vers; - byte first_track; - byte init_addr [2]; - byte banks [8]; - byte data_tag [4]; - byte size [4]; - byte addr [4]; - byte unused [4]; - }; - - // Header for currently loaded file - header_t const& header() const { return header_; } - - static gme_type_t static_type() { return gme_hes_type; } - -public: - Hes_Emu(); - ~Hes_Emu(); -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_( Data_Reader& ); - blargg_err_t start_track_( int ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); - void unload(); -public: private: friend class Hes_Cpu; - byte* write_pages [page_count + 1]; // 0 if unmapped or I/O space - - int cpu_read_( hes_addr_t ); - int cpu_read( hes_addr_t ); - void cpu_write_( hes_addr_t, int data ); - void cpu_write( hes_addr_t, int ); - void cpu_write_vdp( int addr, int data ); - byte const* cpu_set_mmr( int page, int bank ); - int cpu_done(); -private: - Rom_Data rom; - header_t header_; - hes_time_t play_period; - hes_time_t last_frame_hook; - int timer_base; - - struct { - hes_time_t last_time; - blargg_long count; - blargg_long load; - int raw_load; - byte enabled; - byte fired; - } timer; - - struct { - hes_time_t next_vbl; - byte latch; - byte control; - } vdp; - - struct { - hes_time_t timer; - hes_time_t vdp; - byte disables; - } irq; - - void recalc_timer_load(); - - // large items - Hes_Apu apu; - byte sgx [3 * page_size + cpu_padding]; - - void irq_changed(); - void run_until( hes_time_t ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Kss_Cpu.cpp b/libraries/game-music-emu/gme/Kss_Cpu.cpp deleted file mode 100644 index f3857680f..000000000 --- a/libraries/game-music-emu/gme/Kss_Cpu.cpp +++ /dev/null @@ -1,1700 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -/* -Last validated with zexall 2006.11.14 2:19 PM -* Doesn't implement the R register or immediate interrupt after EI. -* Address wrap-around isn't completely correct, but is prevented from crashing emulator. -*/ - -#include "Kss_Cpu.h" - -#include "blargg_endian.h" -#include - -//#include "z80_cpu_log.h" - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -#define SYNC_TIME() (void) (s.time = s_time) -#define RELOAD_TIME() (void) (s_time = s.time) - -// Callbacks to emulator - -#define CPU_OUT( cpu, addr, data, time )\ - kss_cpu_out( this, time, addr, data ) - -#define CPU_IN( cpu, addr, time )\ - kss_cpu_in( this, time, addr ) - -#define CPU_WRITE( cpu, addr, data, time )\ - (SYNC_TIME(), kss_cpu_write( this, addr, data )) - -#include "blargg_source.h" - -// flags, named with hex value for clarity -int const S80 = 0x80; -int const Z40 = 0x40; -int const F20 = 0x20; -int const H10 = 0x10; -int const F08 = 0x08; -int const V04 = 0x04; -int const P04 = 0x04; -int const N02 = 0x02; -int const C01 = 0x01; - -#define SZ28P( n ) szpc [n] -#define SZ28PC( n ) szpc [n] -#define SZ28C( n ) (szpc [n] & ~P04) -#define SZ28( n ) SZ28C( n ) - -#define SET_R( n ) (void) (r.r = n) -#define GET_R() (r.r) - -Kss_Cpu::Kss_Cpu() -{ - state = &state_; - - for ( int i = 0x100; --i >= 0; ) - { - int even = 1; - for ( int p = i; p; p >>= 1 ) - even ^= p; - int n = (i & (S80 | F20 | F08)) | ((even & 1) * P04); - szpc [i] = n; - szpc [i + 0x100] = n | C01; - } - szpc [0x000] |= Z40; - szpc [0x100] |= Z40; -} - -inline void Kss_Cpu::set_page( int i, void* write, void const* read ) -{ - blargg_long offset = KSS_CPU_PAGE_OFFSET( i * (blargg_long) page_size ); - state->write [i] = (byte *) write - offset; - state->read [i] = (byte const*) read - offset; -} - -void Kss_Cpu::reset( void* unmapped_write, void const* unmapped_read ) -{ - check( state == &state_ ); - state = &state_; - state_.time = 0; - state_.base = 0; - end_time_ = 0; - - for ( int i = 0; i < page_count + 1; i++ ) - set_page( i, unmapped_write, unmapped_read ); - - memset( &r, 0, sizeof r ); -} - -void Kss_Cpu::map_mem( unsigned addr, blargg_ulong size, void* write, void const* read ) -{ - // address range must begin and end on page boundaries - require( addr % page_size == 0 ); - require( size % page_size == 0 ); - - unsigned first_page = addr / page_size; - for ( unsigned i = size / page_size; i--; ) - { - blargg_long offset = i * (blargg_long) page_size; - set_page( first_page + i, (byte*) write + offset, (byte const*) read + offset ); - } -} - -#define TIME (s_time + s.base) -#define RW_MEM( addr, rw ) (s.rw [(addr) >> page_shift] [KSS_CPU_PAGE_OFFSET( addr )]) -#define READ_PROG( addr ) RW_MEM( addr, read ) -#define READ( addr ) READ_PROG( addr ) -//#define WRITE( addr, data ) (void) (RW_MEM( addr, write ) = data) -#define WRITE( addr, data ) CPU_WRITE( this, addr, data, TIME ) -#define READ_WORD( addr ) GET_LE16( &READ( addr ) ) -#define WRITE_WORD( addr, data ) SET_LE16( &RW_MEM( addr, write ), data ) -#define IN( addr ) CPU_IN( this, addr, TIME ) -#define OUT( addr, data ) CPU_OUT( this, addr, data, TIME ) - -#if BLARGG_BIG_ENDIAN - #define R8( n, offset ) ((r8_ - offset) [n]) -#elif BLARGG_LITTLE_ENDIAN - #define R8( n, offset ) ((r8_ - offset) [(n) ^ 1]) -#else - #error "Byte order of CPU must be known" -#endif - -//#define R16( n, shift, offset ) (r16_ [((n) >> shift) - (offset >> shift)]) - -// help compiler see that it can just adjust stack offset, saving an extra instruction -#define R16( n, shift, offset )\ - (*(uint16_t*) ((char*) r16_ - (offset >> (shift - 1)) + ((n) >> (shift - 1)))) - -#define CASE5( a, b, c, d, e ) case 0x##a:case 0x##b:case 0x##c:case 0x##d:case 0x##e -#define CASE6( a, b, c, d, e, f ) CASE5( a, b, c, d, e ): case 0x##f -#define CASE7( a, b, c, d, e, f, g ) CASE6( a, b, c, d, e, f ): case 0x##g -#define CASE8( a, b, c, d, e, f, g, h ) CASE7( a, b, c, d, e, f, g ): case 0x##h - -// high four bits are $ED time - 8, low four bits are $DD/$FD time - 8 -static byte const ed_dd_timing [0x100] = { -//0 1 2 3 4 5 6 7 8 9 A B C D E F -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x06,0x0C,0x02,0x00,0x00,0x03,0x00,0x00,0x07,0x0C,0x02,0x00,0x00,0x03,0x00, -0x00,0x00,0x00,0x00,0x0F,0x0F,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, -0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, -0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x10, -0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0xA0, -0x4B,0x4B,0x7B,0xCB,0x0B,0x6B,0x00,0x0B,0x40,0x40,0x70,0xC0,0x00,0x60,0x0B,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x00, -0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0B,0x00, -0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00,0xD0,0xD0,0xD0,0xD0,0x00,0x00,0x0B,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x06,0x00,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00, -}; - -bool Kss_Cpu::run( cpu_time_t end_time ) -{ - set_end_time( end_time ); - state_t s = this->state_; - this->state = &s; - bool warning = false; - - union { - regs_t rg; - pairs_t rp; - uint8_t r8_ [8]; // indexed - uint16_t r16_ [4]; - }; - rg = this->r.b; - - cpu_time_t s_time = s.time; - uint_fast32_t pc = r.pc; - uint_fast32_t sp = r.sp; - uint_fast32_t ix = r.ix; // TODO: keep in memory for direct access? - uint_fast32_t iy = r.iy; - int flags = r.b.flags; - - goto loop; -jr_not_taken: - s_time -= 5; - goto loop; -call_not_taken: - s_time -= 7; -jp_not_taken: - pc += 2; -loop: - - check( (unsigned long) pc < 0x10000 ); - check( (unsigned long) sp < 0x10000 ); - check( (unsigned) flags < 0x100 ); - check( (unsigned) ix < 0x10000 ); - check( (unsigned) iy < 0x10000 ); - - uint8_t const* instr = s.read [pc >> page_shift]; -#define GET_ADDR() GET_LE16( instr ) - - uint_fast8_t opcode; - - // TODO: eliminate this special case - #if BLARGG_NONPORTABLE - opcode = instr [pc]; - pc++; - instr += pc; - #else - instr += KSS_CPU_PAGE_OFFSET( pc ); - opcode = *instr++; - pc++; - #endif - - static byte const base_timing [0x100] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F - 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, // 0 - 13,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, // 1 - 12,10,16, 6, 4, 4, 7, 4,12,11,16, 6, 4, 4, 7, 4, // 2 - 12,10,13, 6,11,11,10, 4,12,11,13, 6, 4, 4, 7, 4, // 3 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 4 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 5 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 6 - 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, // 7 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A - 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B - 11,10,10,10,17,11, 7,11,11,10,10, 8,17,17, 7,11, // C - 11,10,10,11,17,11, 7,11,11, 4,10,11,17, 8, 7,11, // D - 11,10,10,19,17,11, 7,11,11, 4,10, 4,17, 8, 7,11, // E - 11,10,10, 4,17,11, 7,11,11, 6,10, 4,17, 8, 7,11, // F - }; - - uint_fast16_t data; - data = base_timing [opcode]; - if ( (s_time += data) >= 0 ) - goto possibly_out_of_time; -almost_out_of_time: - - data = READ_PROG( pc ); - - #ifdef Z80_CPU_LOG_H - //log_opcode( opcode, READ_PROG( pc ) ); - z80_log_regs( rg.a, rp.bc, rp.de, rp.hl, sp, ix, iy ); - z80_cpu_log( "new", pc - 1, opcode, READ_PROG( pc ), - READ_PROG( pc + 1 ), READ_PROG( pc + 2 ) ); - #endif - - switch ( opcode ) - { -possibly_out_of_time: - if ( s_time < (int) data ) - goto almost_out_of_time; - s_time -= data; - goto out_of_time; - -// Common - - case 0x00: // NOP - CASE7( 40, 49, 52, 5B, 64, 6D, 7F ): // LD B,B etc. - goto loop; - - case 0x08:{// EX AF,AF' - int temp = r.alt.b.a; - r.alt.b.a = rg.a; - rg.a = temp; - - temp = r.alt.b.flags; - r.alt.b.flags = flags; - flags = temp; - goto loop; - } - - case 0xD3: // OUT (imm),A - pc++; - OUT( data + rg.a * 0x100, rg.a ); - goto loop; - - case 0x2E: // LD L,imm - pc++; - rg.l = data; - goto loop; - - case 0x3E: // LD A,imm - pc++; - rg.a = data; - goto loop; - - case 0x3A:{// LD A,(addr) - uint_fast16_t addr = GET_ADDR(); - pc += 2; - rg.a = READ( addr ); - goto loop; - } - -// Conditional - -#define ZERO (flags & Z40) -#define CARRY (flags & C01) -#define EVEN (flags & P04) -#define MINUS (flags & S80) - -// JR -// TODO: more efficient way to handle negative branch that wraps PC around -#define JR( cond ) {\ - int offset = (int8_t) data;\ - pc++;\ - if ( !(cond) )\ - goto jr_not_taken;\ - pc = uint16_t (pc + offset);\ - goto loop;\ -} - - case 0x20: JR( !ZERO ) // JR NZ,disp - case 0x28: JR( ZERO ) // JR Z,disp - case 0x30: JR( !CARRY ) // JR NC,disp - case 0x38: JR( CARRY ) // JR C,disp - case 0x18: JR( true ) // JR disp - - case 0x10:{// DJNZ disp - int temp = rg.b - 1; - rg.b = temp; - JR( temp ) - } - -// JP -#define JP( cond ) if ( !(cond) ) goto jp_not_taken; pc = GET_ADDR(); goto loop; - - case 0xC2: JP( !ZERO ) // JP NZ,addr - case 0xCA: JP( ZERO ) // JP Z,addr - case 0xD2: JP( !CARRY ) // JP NC,addr - case 0xDA: JP( CARRY ) // JP C,addr - case 0xE2: JP( !EVEN ) // JP PO,addr - case 0xEA: JP( EVEN ) // JP PE,addr - case 0xF2: JP( !MINUS ) // JP P,addr - case 0xFA: JP( MINUS ) // JP M,addr - - case 0xC3: // JP addr - pc = GET_ADDR(); - goto loop; - - case 0xE9: // JP HL - pc = rp.hl; - goto loop; - -// RET -#define RET( cond ) if ( cond ) goto ret_taken; s_time -= 6; goto loop; - - case 0xC0: RET( !ZERO ) // RET NZ - case 0xC8: RET( ZERO ) // RET Z - case 0xD0: RET( !CARRY ) // RET NC - case 0xD8: RET( CARRY ) // RET C - case 0xE0: RET( !EVEN ) // RET PO - case 0xE8: RET( EVEN ) // RET PE - case 0xF0: RET( !MINUS ) // RET P - case 0xF8: RET( MINUS ) // RET M - - case 0xC9: // RET - ret_taken: - pc = READ_WORD( sp ); - sp = uint16_t (sp + 2); - goto loop; - -// CALL -#define CALL( cond ) if ( cond ) goto call_taken; goto call_not_taken; - - case 0xC4: CALL( !ZERO ) // CALL NZ,addr - case 0xCC: CALL( ZERO ) // CALL Z,addr - case 0xD4: CALL( !CARRY ) // CALL NC,addr - case 0xDC: CALL( CARRY ) // CALL C,addr - case 0xE4: CALL( !EVEN ) // CALL PO,addr - case 0xEC: CALL( EVEN ) // CALL PE,addr - case 0xF4: CALL( !MINUS ) // CALL P,addr - case 0xFC: CALL( MINUS ) // CALL M,addr - - case 0xCD:{// CALL addr - call_taken: - uint_fast16_t addr = pc + 2; - pc = GET_ADDR(); - sp = uint16_t (sp - 2); - WRITE_WORD( sp, addr ); - goto loop; - } - - case 0xFF: // RST - if ( pc > idle_addr ) - goto hit_idle_addr; - CASE7( C7, CF, D7, DF, E7, EF, F7 ): - data = pc; - pc = opcode & 0x38; - goto push_data; - -// PUSH/POP - case 0xF5: // PUSH AF - data = rg.a * 0x100u + flags; - goto push_data; - - case 0xC5: // PUSH BC - case 0xD5: // PUSH DE - case 0xE5: // PUSH HL - data = R16( opcode, 4, 0xC5 ); - push_data: - sp = uint16_t (sp - 2); - WRITE_WORD( sp, data ); - goto loop; - - case 0xF1: // POP AF - flags = READ( sp ); - rg.a = READ( sp + 1 ); - sp = uint16_t (sp + 2); - goto loop; - - case 0xC1: // POP BC - case 0xD1: // POP DE - case 0xE1: // POP HL - R16( opcode, 4, 0xC1 ) = READ_WORD( sp ); - sp = uint16_t (sp + 2); - goto loop; - -// ADC/ADD/SBC/SUB - case 0x96: // SUB (HL) - case 0x86: // ADD (HL) - flags &= ~C01; - case 0x9E: // SBC (HL) - case 0x8E: // ADC (HL) - data = READ( rp.hl ); - goto adc_data; - - case 0xD6: // SUB A,imm - case 0xC6: // ADD imm - flags &= ~C01; - case 0xDE: // SBC A,imm - case 0xCE: // ADC imm - pc++; - goto adc_data; - - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // SUB r - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // ADD r - flags &= ~C01; - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // SBC r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // ADC r - data = R8( opcode & 7, 0 ); - adc_data: { - int result = data + (flags & C01); - data ^= rg.a; - flags = opcode >> 3 & N02; // bit 4 is set in subtract opcodes - if ( flags ) - result = -result; - result += rg.a; - data ^= result; - flags |=(data & H10) | - ((data - -0x80) >> 6 & V04) | - SZ28C( result & 0x1FF ); - rg.a = result; - goto loop; - } - -// CP - case 0xBE: // CP (HL) - data = READ( rp.hl ); - goto cp_data; - - case 0xFE: // CP imm - pc++; - goto cp_data; - - CASE7( B8, B9, BA, BB, BC, BD, BF ): // CP r - data = R8( opcode, 0xB8 ); - cp_data: { - int result = rg.a - data; - flags = N02 | (data & (F20 | F08)) | (result >> 8 & C01); - data ^= rg.a; - flags |=(((result ^ rg.a) & data) >> 5 & V04) | - (((data & H10) ^ result) & (S80 | H10)); - if ( (uint8_t) result ) - goto loop; - flags |= Z40; - goto loop; - } - -// ADD HL,rp - - case 0x39: // ADD HL,SP - data = sp; - goto add_hl_data; - - case 0x09: // ADD HL,BC - case 0x19: // ADD HL,DE - case 0x29: // ADD HL,HL - data = R16( opcode, 4, 0x09 ); - add_hl_data: { - blargg_ulong sum = rp.hl + data; - data ^= rp.hl; - rp.hl = sum; - flags = (flags & (S80 | Z40 | V04)) | - (sum >> 16) | - (sum >> 8 & (F20 | F08)) | - ((data ^ sum) >> 8 & H10); - goto loop; - } - - case 0x27:{// DAA - int a = rg.a; - if ( a > 0x99 ) - flags |= C01; - - int adjust = 0x60 & -(flags & C01); - - if ( flags & H10 || (a & 0x0F) > 9 ) - adjust |= 0x06; - - if ( flags & N02 ) - adjust = -adjust; - a += adjust; - - flags = (flags & (C01 | N02)) | - ((rg.a ^ a) & H10) | - SZ28P( (uint8_t) a ); - rg.a = a; - goto loop; - } - /* - case 0x27:{// DAA - // more optimized, but probably not worth the obscurity - int f = (rg.a + (0xFF - 0x99)) >> 8 | flags; // (a > 0x99 ? C01 : 0) | flags - int adjust = 0x60 & -(f & C01); // f & C01 ? 0x60 : 0 - - if ( (((rg.a + (0x0F - 9)) ^ rg.a) | f) & H10 ) // flags & H10 || (rg.a & 0x0F) > 9 - adjust |= 0x06; - - if ( f & N02 ) - adjust = -adjust; - int a = rg.a + adjust; - - flags = (f & (N02 | C01)) | ((rg.a ^ a) & H10) | SZ28P( (uint8_t) a ); - rg.a = a; - goto loop; - } - */ - -// INC/DEC - case 0x34: // INC (HL) - data = READ( rp.hl ) + 1; - WRITE( rp.hl, data ); - goto inc_set_flags; - - CASE7( 04, 0C, 14, 1C, 24, 2C, 3C ): // INC r - data = ++R8( opcode >> 3, 0 ); - inc_set_flags: - flags = (flags & C01) | - (((data & 0x0F) - 1) & H10) | - SZ28( (uint8_t) data ); - if ( data != 0x80 ) - goto loop; - flags |= V04; - goto loop; - - case 0x35: // DEC (HL) - data = READ( rp.hl ) - 1; - WRITE( rp.hl, data ); - goto dec_set_flags; - - CASE7( 05, 0D, 15, 1D, 25, 2D, 3D ): // DEC r - data = --R8( opcode >> 3, 0 ); - dec_set_flags: - flags = (flags & C01) | N02 | - (((data & 0x0F) + 1) & H10) | - SZ28( (uint8_t) data ); - if ( data != 0x7F ) - goto loop; - flags |= V04; - goto loop; - - case 0x03: // INC BC - case 0x13: // INC DE - case 0x23: // INC HL - R16( opcode, 4, 0x03 )++; - goto loop; - - case 0x33: // INC SP - sp = uint16_t (sp + 1); - goto loop; - - case 0x0B: // DEC BC - case 0x1B: // DEC DE - case 0x2B: // DEC HL - R16( opcode, 4, 0x0B )--; - goto loop; - - case 0x3B: // DEC SP - sp = uint16_t (sp - 1); - goto loop; - -// AND - case 0xA6: // AND (HL) - data = READ( rp.hl ); - goto and_data; - - case 0xE6: // AND imm - pc++; - goto and_data; - - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // AND r - data = R8( opcode, 0xA0 ); - and_data: - rg.a &= data; - flags = SZ28P( rg.a ) | H10; - goto loop; - -// OR - case 0xB6: // OR (HL) - data = READ( rp.hl ); - goto or_data; - - case 0xF6: // OR imm - pc++; - goto or_data; - - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // OR r - data = R8( opcode, 0xB0 ); - or_data: - rg.a |= data; - flags = SZ28P( rg.a ); - goto loop; - -// XOR - case 0xAE: // XOR (HL) - data = READ( rp.hl ); - goto xor_data; - - case 0xEE: // XOR imm - pc++; - goto xor_data; - - CASE7( A8, A9, AA, AB, AC, AD, AF ): // XOR r - data = R8( opcode, 0xA8 ); - xor_data: - rg.a ^= data; - flags = SZ28P( rg.a ); - goto loop; - -// LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (HL),r - WRITE( rp.hl, R8( opcode, 0x70 ) ); - goto loop; - - CASE6( 41, 42, 43, 44, 45, 47 ): // LD B,r - CASE6( 48, 4A, 4B, 4C, 4D, 4F ): // LD C,r - CASE6( 50, 51, 53, 54, 55, 57 ): // LD D,r - CASE6( 58, 59, 5A, 5C, 5D, 5F ): // LD E,r - CASE6( 60, 61, 62, 63, 65, 67 ): // LD H,r - CASE6( 68, 69, 6A, 6B, 6C, 6F ): // LD L,r - CASE6( 78, 79, 7A, 7B, 7C, 7D ): // LD A,r - R8( opcode >> 3 & 7, 0 ) = R8( opcode & 7, 0 ); - goto loop; - - CASE5( 06, 0E, 16, 1E, 26 ): // LD r,imm - R8( opcode >> 3, 0 ) = data; - pc++; - goto loop; - - case 0x36: // LD (HL),imm - pc++; - WRITE( rp.hl, data ); - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(HL) - R8( opcode >> 3, 8 ) = READ( rp.hl ); - goto loop; - - case 0x01: // LD rp,imm - case 0x11: - case 0x21: - R16( opcode, 4, 0x01 ) = GET_ADDR(); - pc += 2; - goto loop; - - case 0x31: // LD sp,imm - sp = GET_ADDR(); - pc += 2; - goto loop; - - case 0x2A:{// LD HL,(addr) - uint_fast16_t addr = GET_ADDR(); - pc += 2; - rp.hl = READ_WORD( addr ); - goto loop; - } - - case 0x32:{// LD (addr),A - uint_fast16_t addr = GET_ADDR(); - pc += 2; - WRITE( addr, rg.a ); - goto loop; - } - - case 0x22:{// LD (addr),HL - uint_fast16_t addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, rp.hl ); - goto loop; - } - - case 0x02: // LD (BC),A - case 0x12: // LD (DE),A - WRITE( R16( opcode, 4, 0x02 ), rg.a ); - goto loop; - - case 0x0A: // LD A,(BC) - case 0x1A: // LD A,(DE) - rg.a = READ( R16( opcode, 4, 0x0A ) ); - goto loop; - - case 0xF9: // LD SP,HL - sp = rp.hl; - goto loop; - -// Rotate - - case 0x07:{// RLCA - uint_fast16_t temp = rg.a; - temp = (temp << 1) | (temp >> 7); - flags = (flags & (S80 | Z40 | P04)) | - (temp & (F20 | F08 | C01)); - rg.a = temp; - goto loop; - } - - case 0x0F:{// RRCA - uint_fast16_t temp = rg.a; - flags = (flags & (S80 | Z40 | P04)) | - (temp & C01); - temp = (temp << 7) | (temp >> 1); - flags |= temp & (F20 | F08); - rg.a = temp; - goto loop; - } - - case 0x17:{// RLA - blargg_ulong temp = (rg.a << 1) | (flags & C01); - flags = (flags & (S80 | Z40 | P04)) | - (temp & (F20 | F08)) | - (temp >> 8); - rg.a = (uint8_t)temp; - goto loop; - } - - case 0x1F:{// RRA - uint_fast16_t temp = (flags << 7) | (rg.a >> 1); - flags = (flags & (S80 | Z40 | P04)) | - (temp & (F20 | F08)) | - (rg.a & C01); - rg.a = temp; - goto loop; - } - -// Misc - case 0x2F:{// CPL - uint_fast16_t temp = ~rg.a; - flags = (flags & (S80 | Z40 | P04 | C01)) | - (temp & (F20 | F08)) | - (H10 | N02); - rg.a = temp; - goto loop; - } - - case 0x3F:{// CCF - flags = ((flags & (S80 | Z40 | P04 | C01)) ^ C01) | - (flags << 4 & H10) | - (rg.a & (F20 | F08)); - goto loop; - } - - case 0x37: // SCF - flags = (flags & (S80 | Z40 | P04)) | C01 | - (rg.a & (F20 | F08)); - goto loop; - - case 0xDB: // IN A,(imm) - pc++; - rg.a = IN( data + rg.a * 0x100 ); - goto loop; - - case 0xE3:{// EX (SP),HL - uint_fast16_t temp = READ_WORD( sp ); - WRITE_WORD( sp, rp.hl ); - rp.hl = temp; - goto loop; - } - - case 0xEB:{// EX DE,HL - uint_fast16_t temp = rp.hl; - rp.hl = rp.de; - rp.de = temp; - goto loop; - } - - case 0xD9:{// EXX DE,HL - uint_fast16_t temp = r.alt.w.bc; - r.alt.w.bc = rp.bc; - rp.bc = temp; - - temp = r.alt.w.de; - r.alt.w.de = rp.de; - rp.de = temp; - - temp = r.alt.w.hl; - r.alt.w.hl = rp.hl; - rp.hl = temp; - goto loop; - } - - case 0xF3: // DI - r.iff1 = 0; - r.iff2 = 0; - goto loop; - - case 0xFB: // EI - r.iff1 = 1; - r.iff2 = 1; - // TODO: delayed effect - goto loop; - - case 0x76: // HALT - goto halt; - -//////////////////////////////////////// CB prefix - { - case 0xCB: - unsigned data2; - data2 = instr [1]; - (void) data2; // TODO is this the same as data in all cases? - pc++; - switch ( data ) - { - - // Rotate left - - #define RLC( read, write ) {\ - uint_fast8_t result = read;\ - result = uint8_t (result << 1) | (result >> 7);\ - flags = SZ28P( result ) | (result & C01);\ - write;\ - goto loop;\ - } - - case 0x06: // RLC (HL) - s_time += 7; - data = rp.hl; - rlc_data_addr: - RLC( READ( data ), WRITE( data, result ) ) - - CASE7( 00, 01, 02, 03, 04, 05, 07 ):{// RLC r - uint8_t& reg = R8( data, 0 ); - RLC( reg, reg = result ) - } - - #define RL( read, write ) {\ - uint_fast16_t result = (read << 1) | (flags & C01);\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x16: // RL (HL) - s_time += 7; - data = rp.hl; - rl_data_addr: - RL( READ( data ), WRITE( data, result ) ) - - CASE7( 10, 11, 12, 13, 14, 15, 17 ):{// RL r - uint8_t& reg = R8( data, 0x10 ); - RL( reg, reg = result ) - } - - #define SLA( read, add, write ) {\ - uint_fast16_t result = (read << 1) | add;\ - flags = SZ28PC( result );\ - write;\ - goto loop;\ - } - - case 0x26: // SLA (HL) - s_time += 7; - data = rp.hl; - sla_data_addr: - SLA( READ( data ), 0, WRITE( data, result ) ) - - CASE7( 20, 21, 22, 23, 24, 25, 27 ):{// SLA r - uint8_t& reg = R8( data, 0x20 ); - SLA( reg, 0, reg = result ) - } - - case 0x36: // SLL (HL) - s_time += 7; - data = rp.hl; - sll_data_addr: - SLA( READ( data ), 1, WRITE( data, result ) ) - - CASE7( 30, 31, 32, 33, 34, 35, 37 ):{// SLL r - uint8_t& reg = R8( data, 0x30 ); - SLA( reg, 1, reg = result ) - } - - // Rotate right - - #define RRC( read, write ) {\ - uint_fast8_t result = read;\ - flags = result & C01;\ - result = uint8_t (result << 7) | (result >> 1);\ - flags |= SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x0E: // RRC (HL) - s_time += 7; - data = rp.hl; - rrc_data_addr: - RRC( READ( data ), WRITE( data, result ) ) - - CASE7( 08, 09, 0A, 0B, 0C, 0D, 0F ):{// RRC r - uint8_t& reg = R8( data, 0x08 ); - RRC( reg, reg = result ) - } - - #define RR( read, write ) {\ - uint_fast8_t result = read;\ - uint_fast8_t temp = result & C01;\ - result = uint8_t (flags << 7) | (result >> 1);\ - flags = SZ28P( result ) | temp;\ - write;\ - goto loop;\ - } - - case 0x1E: // RR (HL) - s_time += 7; - data = rp.hl; - rr_data_addr: - RR( READ( data ), WRITE( data, result ) ) - - CASE7( 18, 19, 1A, 1B, 1C, 1D, 1F ):{// RR r - uint8_t& reg = R8( data, 0x18 ); - RR( reg, reg = result ) - } - - #define SRA( read, write ) {\ - uint_fast8_t result = read;\ - flags = result & C01;\ - result = (result & 0x80) | (result >> 1);\ - flags |= SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x2E: // SRA (HL) - data = rp.hl; - s_time += 7; - sra_data_addr: - SRA( READ( data ), WRITE( data, result ) ) - - CASE7( 28, 29, 2A, 2B, 2C, 2D, 2F ):{// SRA r - uint8_t& reg = R8( data, 0x28 ); - SRA( reg, reg = result ) - } - - #define SRL( read, write ) {\ - uint_fast8_t result = read;\ - flags = result & C01;\ - result >>= 1;\ - flags |= SZ28P( result );\ - write;\ - goto loop;\ - } - - case 0x3E: // SRL (HL) - s_time += 7; - data = rp.hl; - srl_data_addr: - SRL( READ( data ), WRITE( data, result ) ) - - CASE7( 38, 39, 3A, 3B, 3C, 3D, 3F ):{// SRL r - uint8_t& reg = R8( data, 0x38 ); - SRL( reg, reg = result ) - } - - // BIT - { - unsigned temp; - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ): // BIT b,(HL) - s_time += 4; - temp = READ( rp.hl ); - flags &= C01; - goto bit_temp; - CASE7( 40, 41, 42, 43, 44, 45, 47 ): // BIT 0,r - CASE7( 48, 49, 4A, 4B, 4C, 4D, 4F ): // BIT 1,r - CASE7( 50, 51, 52, 53, 54, 55, 57 ): // BIT 2,r - CASE7( 58, 59, 5A, 5B, 5C, 5D, 5F ): // BIT 3,r - CASE7( 60, 61, 62, 63, 64, 65, 67 ): // BIT 4,r - CASE7( 68, 69, 6A, 6B, 6C, 6D, 6F ): // BIT 5,r - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // BIT 6,r - CASE7( 78, 79, 7A, 7B, 7C, 7D, 7F ): // BIT 7,r - temp = R8( data & 7, 0 ); - flags = (flags & C01) | (temp & (F20 | F08)); - bit_temp: - int masked = temp & 1 << (data >> 3 & 7); - flags |=(masked & S80) | H10 | - ((masked - 1) >> 8 & (Z40 | P04)); - goto loop; - } - - // SET/RES - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(HL) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(HL) - s_time += 7; - int temp = READ( rp.hl ); - int bit = 1 << (data >> 3 & 7); - temp |= bit; // SET - if ( !(data & 0x40) ) - temp ^= bit; // RES - WRITE( rp.hl, temp ); - goto loop; - } - - CASE7( C0, C1, C2, C3, C4, C5, C7 ): // SET 0,r - CASE7( C8, C9, CA, CB, CC, CD, CF ): // SET 1,r - CASE7( D0, D1, D2, D3, D4, D5, D7 ): // SET 2,r - CASE7( D8, D9, DA, DB, DC, DD, DF ): // SET 3,r - CASE7( E0, E1, E2, E3, E4, E5, E7 ): // SET 4,r - CASE7( E8, E9, EA, EB, EC, ED, EF ): // SET 5,r - CASE7( F0, F1, F2, F3, F4, F5, F7 ): // SET 6,r - CASE7( F8, F9, FA, FB, FC, FD, FF ): // SET 7,r - R8( data & 7, 0 ) |= 1 << (data >> 3 & 7); - goto loop; - - CASE7( 80, 81, 82, 83, 84, 85, 87 ): // RES 0,r - CASE7( 88, 89, 8A, 8B, 8C, 8D, 8F ): // RES 1,r - CASE7( 90, 91, 92, 93, 94, 95, 97 ): // RES 2,r - CASE7( 98, 99, 9A, 9B, 9C, 9D, 9F ): // RES 3,r - CASE7( A0, A1, A2, A3, A4, A5, A7 ): // RES 4,r - CASE7( A8, A9, AA, AB, AC, AD, AF ): // RES 5,r - CASE7( B0, B1, B2, B3, B4, B5, B7 ): // RES 6,r - CASE7( B8, B9, BA, BB, BC, BD, BF ): // RES 7,r - R8( data & 7, 0 ) &= ~(1 << (data >> 3 & 7)); - goto loop; - } - assert( false ); - } - -#undef GET_ADDR -#define GET_ADDR() GET_LE16( instr + 1 ) - -//////////////////////////////////////// ED prefix - { - case 0xED: - pc++; - s_time += ed_dd_timing [data] >> 4; - switch ( data ) - { - { - blargg_ulong temp; - case 0x72: // SBC HL,SP - case 0x7A: // ADC HL,SP - temp = sp; - if ( 0 ) - case 0x42: // SBC HL,BC - case 0x52: // SBC HL,DE - case 0x62: // SBC HL,HL - case 0x4A: // ADC HL,BC - case 0x5A: // ADC HL,DE - case 0x6A: // ADC HL,HL - temp = R16( data >> 3 & 6, 1, 0 ); - blargg_ulong sum = temp + (flags & C01); - flags = ~data >> 2 & N02; - if ( flags ) - sum = -sum; - sum += rp.hl; - temp ^= rp.hl; - temp ^= sum; - flags |=(sum >> 16 & C01) | - (temp >> 8 & H10) | - (sum >> 8 & (S80 | F20 | F08)) | - ((temp - -0x8000) >> 14 & V04); - rp.hl = sum; - if ( (uint16_t) sum ) - goto loop; - flags |= Z40; - goto loop; - } - - CASE8( 40, 48, 50, 58, 60, 68, 70, 78 ):{// IN r,(C) - int temp = IN( rp.bc ); - R8( data >> 3, 8 ) = temp; - flags = (flags & C01) | SZ28P( temp ); - goto loop; - } - - case 0x71: // OUT (C),0 - rg.flags = 0; - CASE7( 41, 49, 51, 59, 61, 69, 79 ): // OUT (C),r - OUT( rp.bc, R8( data >> 3, 8 ) ); - goto loop; - - { - unsigned temp; - case 0x73: // LD (ADDR),SP - temp = sp; - if ( 0 ) - case 0x43: // LD (ADDR),BC - case 0x53: // LD (ADDR),DE - temp = R16( data, 4, 0x43 ); - uint_fast16_t addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, temp ); - goto loop; - } - - case 0x4B: // LD BC,(ADDR) - case 0x5B:{// LD DE,(ADDR) - uint_fast16_t addr = GET_ADDR(); - pc += 2; - R16( data, 4, 0x4B ) = READ_WORD( addr ); - goto loop; - } - - case 0x7B:{// LD SP,(ADDR) - uint_fast16_t addr = GET_ADDR(); - pc += 2; - sp = READ_WORD( addr ); - goto loop; - } - - case 0x67:{// RRD - uint_fast8_t temp = READ( rp.hl ); - WRITE( rp.hl, (rg.a << 4) | (temp >> 4) ); - temp = (rg.a & 0xF0) | (temp & 0x0F); - flags = (flags & C01) | SZ28P( temp ); - rg.a = temp; - goto loop; - } - - case 0x6F:{// RLD - uint_fast8_t temp = READ( rp.hl ); - WRITE( rp.hl, (temp << 4) | (rg.a & 0x0F) ); - temp = (rg.a & 0xF0) | (temp >> 4); - flags = (flags & C01) | SZ28P( temp ); - rg.a = temp; - goto loop; - } - - CASE8( 44, 4C, 54, 5C, 64, 6C, 74, 7C ): // NEG - opcode = 0x10; // flag to do SBC instead of ADC - flags &= ~C01; - data = rg.a; - rg.a = 0; - goto adc_data; - - { - int inc; - case 0xA9: // CPD - case 0xB9: // CPDR - inc = -1; - if ( 0 ) - case 0xA1: // CPI - case 0xB1: // CPIR - inc = +1; - uint_fast16_t addr = rp.hl; - rp.hl = addr + inc; - int temp = READ( addr ); - - int result = rg.a - temp; - flags = (flags & C01) | N02 | - ((((temp ^ rg.a) & H10) ^ result) & (S80 | H10)); - - if ( !(uint8_t) result ) flags |= Z40; - result -= (flags & H10) >> 4; - flags |= result & F08; - flags |= result << 4 & F20; - if ( !--rp.bc ) - goto loop; - - flags |= V04; - if ( flags & Z40 || data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xA8: // LDD - case 0xB8: // LDDR - inc = -1; - if ( 0 ) - case 0xA0: // LDI - case 0xB0: // LDIR - inc = +1; - uint_fast16_t addr = rp.hl; - rp.hl = addr + inc; - int temp = READ( addr ); - - addr = rp.de; - rp.de = addr + inc; - WRITE( addr, temp ); - - temp += rg.a; - flags = (flags & (S80 | Z40 | C01)) | - (temp & F08) | (temp << 4 & F20); - if ( !--rp.bc ) - goto loop; - - flags |= V04; - if ( data < 0xB0 ) - goto loop; - - pc -= 2; - s_time += 5; - goto loop; - } - - { - int inc; - case 0xAB: // OUTD - case 0xBB: // OTDR - inc = -1; - if ( 0 ) - case 0xA3: // OUTI - case 0xB3: // OTIR - inc = +1; - uint_fast16_t addr = rp.hl; - rp.hl = addr + inc; - int temp = READ( addr ); - - int b = --rg.b; - flags = (temp >> 6 & N02) | SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - OUT( rp.bc, temp ); - goto loop; - } - - { - int inc; - case 0xAA: // IND - case 0xBA: // INDR - inc = -1; - if ( 0 ) - case 0xA2: // INI - case 0xB2: // INIR - inc = +1; - - uint_fast16_t addr = rp.hl; - rp.hl = addr + inc; - - int temp = IN( rp.bc ); - - int b = --rg.b; - flags = (temp >> 6 & N02) | SZ28( b ); - if ( b && data >= 0xB0 ) - { - pc -= 2; - s_time += 5; - } - - WRITE( addr, temp ); - goto loop; - } - - case 0x47: // LD I,A - r.i = rg.a; - goto loop; - - case 0x4F: // LD R,A - SET_R( rg.a ); - debug_printf( "LD R,A not supported\n" ); - warning = true; - goto loop; - - case 0x57: // LD A,I - rg.a = r.i; - goto ld_ai_common; - - case 0x5F: // LD A,R - rg.a = GET_R(); - debug_printf( "LD A,R not supported\n" ); - warning = true; - ld_ai_common: - flags = (flags & C01) | SZ28( rg.a ) | (r.iff2 << 2 & V04); - goto loop; - - CASE8( 45, 4D, 55, 5D, 65, 6D, 75, 7D ): // RETI/RETN - r.iff1 = r.iff2; - goto ret_taken; - - case 0x46: case 0x4E: case 0x66: case 0x6E: // IM 0 - r.im = 0; - goto loop; - - case 0x56: case 0x76: // IM 1 - r.im = 1; - goto loop; - - case 0x5E: case 0x7E: // IM 2 - r.im = 2; - goto loop; - - default: - debug_printf( "Opcode $ED $%02X not supported\n", data ); - warning = true; - goto loop; - } - assert( false ); - } - -//////////////////////////////////////// DD/FD prefix - { - uint_fast16_t ixy; - case 0xDD: - ixy = ix; - goto ix_prefix; - case 0xFD: - ixy = iy; - ix_prefix: - pc++; - unsigned data2 = READ_PROG( pc ); - s_time += ed_dd_timing [data] & 0x0F; - switch ( data ) - { - // TODO: more efficient way of avoid negative address - // TODO: avoid using this as argument to READ() since it is evaluated twice - #define IXY_DISP( ixy, disp ) uint16_t ((ixy) + (disp)) - - #define SET_IXY( in ) if ( opcode == 0xDD ) ix = in; else iy = in; - - // ADD/ADC/SUB/SBC - - case 0x96: // SUB (IXY+disp) - case 0x86: // ADD (IXY+disp) - flags &= ~C01; - case 0x9E: // SBC (IXY+disp) - case 0x8E: // ADC (IXY+disp) - pc++; - opcode = data; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto adc_data; - - case 0x94: // SUB HXY - case 0x84: // ADD HXY - flags &= ~C01; - case 0x9C: // SBC HXY - case 0x8C: // ADC HXY - opcode = data; - data = ixy >> 8; - goto adc_data; - - case 0x95: // SUB LXY - case 0x85: // ADD LXY - flags &= ~C01; - case 0x9D: // SBC LXY - case 0x8D: // ADC LXY - opcode = data; - data = (uint8_t) ixy; - goto adc_data; - - { - unsigned temp; - case 0x39: // ADD IXY,SP - temp = sp; - goto add_ixy_data; - - case 0x29: // ADD IXY,HL - temp = ixy; - goto add_ixy_data; - - case 0x09: // ADD IXY,BC - case 0x19: // ADD IXY,DE - temp = R16( data, 4, 0x09 ); - add_ixy_data: { - blargg_ulong sum = ixy + temp; - temp ^= ixy; - ixy = (uint16_t) sum; - flags = (flags & (S80 | Z40 | V04)) | - (sum >> 16) | - (sum >> 8 & (F20 | F08)) | - ((temp ^ sum) >> 8 & H10); - goto set_ixy; - } - } - - // AND - case 0xA6: // AND (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto and_data; - - case 0xA4: // AND HXY - data = ixy >> 8; - goto and_data; - - case 0xA5: // AND LXY - data = (uint8_t) ixy; - goto and_data; - - // OR - case 0xB6: // OR (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto or_data; - - case 0xB4: // OR HXY - data = ixy >> 8; - goto or_data; - - case 0xB5: // OR LXY - data = (uint8_t) ixy; - goto or_data; - - // XOR - case 0xAE: // XOR (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto xor_data; - - case 0xAC: // XOR HXY - data = ixy >> 8; - goto xor_data; - - case 0xAD: // XOR LXY - data = (uint8_t) ixy; - goto xor_data; - - // CP - case 0xBE: // CP (IXY+disp) - pc++; - data = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto cp_data; - - case 0xBC: // CP HXY - data = ixy >> 8; - goto cp_data; - - case 0xBD: // CP LXY - data = (uint8_t) ixy; - goto cp_data; - - // LD - CASE7( 70, 71, 72, 73, 74, 75, 77 ): // LD (IXY+disp),r - data = R8( data, 0x70 ); - if ( 0 ) - case 0x36: // LD (IXY+disp),imm - pc++, data = READ_PROG( pc ); - pc++; - WRITE( IXY_DISP( ixy, (int8_t) data2 ), data ); - goto loop; - - CASE5( 44, 4C, 54, 5C, 7C ): // LD r,HXY - R8( data >> 3, 8 ) = ixy >> 8; - goto loop; - - case 0x64: // LD HXY,HXY - case 0x6D: // LD LXY,LXY - goto loop; - - CASE5( 45, 4D, 55, 5D, 7D ): // LD r,LXY - R8( data >> 3, 8 ) = ixy; - goto loop; - - CASE7( 46, 4E, 56, 5E, 66, 6E, 7E ): // LD r,(IXY+disp) - pc++; - R8( data >> 3, 8 ) = READ( IXY_DISP( ixy, (int8_t) data2 ) ); - goto loop; - - case 0x26: // LD HXY,imm - pc++; - goto ld_hxy_data; - - case 0x65: // LD HXY,LXY - data2 = (uint8_t) ixy; - goto ld_hxy_data; - - CASE5( 60, 61, 62, 63, 67 ): // LD HXY,r - data2 = R8( data, 0x60 ); - ld_hxy_data: - ixy = (uint8_t) ixy | (data2 << 8); - goto set_ixy; - - case 0x2E: // LD LXY,imm - pc++; - goto ld_lxy_data; - - case 0x6C: // LD LXY,HXY - data2 = ixy >> 8; - goto ld_lxy_data; - - CASE5( 68, 69, 6A, 6B, 6F ): // LD LXY,r - data2 = R8( data, 0x68 ); - ld_lxy_data: - ixy = (ixy & 0xFF00) | data2; - set_ixy: - if ( opcode == 0xDD ) - { - ix = ixy; - goto loop; - } - iy = ixy; - goto loop; - - case 0xF9: // LD SP,IXY - sp = ixy; - goto loop; - - case 0x22:{// LD (ADDR),IXY - uint_fast16_t addr = GET_ADDR(); - pc += 2; - WRITE_WORD( addr, ixy ); - goto loop; - } - - case 0x21: // LD IXY,imm - ixy = GET_ADDR(); - pc += 2; - goto set_ixy; - - case 0x2A:{// LD IXY,(addr) - uint_fast16_t addr = GET_ADDR(); - ixy = READ_WORD( addr ); - pc += 2; - goto set_ixy; - } - - // DD/FD CB prefix - case 0xCB: { - data = IXY_DISP( ixy, (int8_t) data2 ); - pc++; - data2 = READ_PROG( pc ); - pc++; - switch ( data2 ) - { - case 0x06: goto rlc_data_addr; // RLC (IXY) - case 0x16: goto rl_data_addr; // RL (IXY) - case 0x26: goto sla_data_addr; // SLA (IXY) - case 0x36: goto sll_data_addr; // SLL (IXY) - case 0x0E: goto rrc_data_addr; // RRC (IXY) - case 0x1E: goto rr_data_addr; // RR (IXY) - case 0x2E: goto sra_data_addr; // SRA (IXY) - case 0x3E: goto srl_data_addr; // SRL (IXY) - - CASE8( 46, 4E, 56, 5E, 66, 6E, 76, 7E ):{// BIT b,(IXY+disp) - uint_fast8_t temp = READ( data ); - int masked = temp & 1 << (data2 >> 3 & 7); - flags = (flags & C01) | H10 | - (masked & S80) | - ((masked - 1) >> 8 & (Z40 | P04)); - goto loop; - } - - CASE8( 86, 8E, 96, 9E, A6, AE, B6, BE ): // RES b,(IXY+disp) - CASE8( C6, CE, D6, DE, E6, EE, F6, FE ):{// SET b,(IXY+disp) - int temp = READ( data ); - int bit = 1 << (data2 >> 3 & 7); - temp |= bit; // SET - if ( !(data2 & 0x40) ) - temp ^= bit; // RES - WRITE( data, temp ); - goto loop; - } - - default: - debug_printf( "Opcode $%02X $CB $%02X not supported\n", opcode, data2 ); - warning = true; - goto loop; - } - assert( false ); - } - - // INC/DEC - case 0x23: // INC IXY - ixy = uint16_t (ixy + 1); - goto set_ixy; - - case 0x2B: // DEC IXY - ixy = uint16_t (ixy - 1); - goto set_ixy; - - case 0x34: // INC (IXY+disp) - ixy = IXY_DISP( ixy, (int8_t) data2 ); - pc++; - data = READ( ixy ) + 1; - WRITE( ixy, data ); - goto inc_set_flags; - - case 0x35: // DEC (IXY+disp) - ixy = IXY_DISP( ixy, (int8_t) data2 ); - pc++; - data = READ( ixy ) - 1; - WRITE( ixy, data ); - goto dec_set_flags; - - case 0x24: // INC HXY - ixy = uint16_t (ixy + 0x100); - data = ixy >> 8; - goto inc_xy_common; - - case 0x2C: // INC LXY - data = uint8_t (ixy + 1); - ixy = (ixy & 0xFF00) | data; - inc_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto inc_set_flags; - } - iy = ixy; - goto inc_set_flags; - - case 0x25: // DEC HXY - ixy = uint16_t (ixy - 0x100); - data = ixy >> 8; - goto dec_xy_common; - - case 0x2D: // DEC LXY - data = uint8_t (ixy - 1); - ixy = (ixy & 0xFF00) | data; - dec_xy_common: - if ( opcode == 0xDD ) - { - ix = ixy; - goto dec_set_flags; - } - iy = ixy; - goto dec_set_flags; - - // PUSH/POP - case 0xE5: // PUSH IXY - data = ixy; - goto push_data; - - case 0xE1:{// POP IXY - ixy = READ_WORD( sp ); - sp = uint16_t (sp + 2); - goto set_ixy; - } - - // Misc - - case 0xE9: // JP (IXY) - pc = ixy; - goto loop; - - case 0xE3:{// EX (SP),IXY - uint_fast16_t temp = READ_WORD( sp ); - WRITE_WORD( sp, ixy ); - ixy = temp; - goto set_ixy; - } - - default: - debug_printf( "Unnecessary DD/FD prefix encountered\n" ); - warning = true; - pc--; - goto loop; - } - assert( false ); - } - - } - debug_printf( "Unhandled main opcode: $%02X\n", opcode ); - assert( false ); - -hit_idle_addr: - s_time -= 11; - goto out_of_time; -halt: - s_time &= 3; // increment by multiple of 4 -out_of_time: - pc--; - - s.time = s_time; - rg.flags = flags; - r.ix = ix; - r.iy = iy; - r.sp = sp; - r.pc = pc; - this->r.b = rg; - this->state_ = s; - this->state = &this->state_; - - return warning; -} diff --git a/libraries/game-music-emu/gme/Kss_Cpu.h b/libraries/game-music-emu/gme/Kss_Cpu.h deleted file mode 100644 index d31864cd3..000000000 --- a/libraries/game-music-emu/gme/Kss_Cpu.h +++ /dev/null @@ -1,120 +0,0 @@ -// Z80 CPU emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef KSS_CPU_H -#define KSS_CPU_H - -#include "blargg_endian.h" - -typedef blargg_long cpu_time_t; - -// must be defined by caller -void kss_cpu_out( class Kss_Cpu*, cpu_time_t, unsigned addr, int data ); -int kss_cpu_in( class Kss_Cpu*, cpu_time_t, unsigned addr ); -void kss_cpu_write( class Kss_Cpu*, unsigned addr, int data ); - -class Kss_Cpu { -public: - // Clear registers and map all pages to unmapped - void reset( void* unmapped_write, void const* unmapped_read ); - - // Map memory. Start and size must be multiple of page_size. - enum { page_size = 0x2000 }; - void map_mem( unsigned addr, blargg_ulong size, void* write, void const* read ); - - // Map address to page - uint8_t* write( unsigned addr ); - uint8_t const* read( unsigned addr ); - - // Run until specified time is reached. Returns true if suspicious/unsupported - // instruction was encountered at any point during run. - bool run( cpu_time_t end_time ); - - // Time of beginning of next instruction - cpu_time_t time() const { return state->time + state->base; } - - // Alter current time. Not supported during run() call. - void set_time( cpu_time_t t ) { state->time = t - state->base; } - void adjust_time( int delta ) { state->time += delta; } - - #if BLARGG_BIG_ENDIAN - struct regs_t { uint8_t b, c, d, e, h, l, flags, a; }; - #else - struct regs_t { uint8_t c, b, e, d, l, h, a, flags; }; - #endif - BOOST_STATIC_ASSERT( sizeof (regs_t) == 8 ); - - struct pairs_t { uint16_t bc, de, hl, fa; }; - - // Registers are not updated until run() returns - struct registers_t { - uint16_t pc; - uint16_t sp; - uint16_t ix; - uint16_t iy; - union { - regs_t b; // b.b, b.c, b.d, b.e, b.h, b.l, b.flags, b.a - pairs_t w; // w.bc, w.de, w.hl. w.fa - }; - union { - regs_t b; - pairs_t w; - } alt; - uint8_t iff1; - uint8_t iff2; - uint8_t r; - uint8_t i; - uint8_t im; - }; - //registers_t r; (below for efficiency) - - enum { idle_addr = 0xFFFF }; - - // can read this far past end of a page - enum { cpu_padding = 0x100 }; - -public: - Kss_Cpu(); - enum { page_shift = 13 }; - enum { page_count = 0x10000 >> page_shift }; -private: - uint8_t szpc [0x200]; - cpu_time_t end_time_; - struct state_t { - uint8_t const* read [page_count + 1]; - uint8_t * write [page_count + 1]; - cpu_time_t base; - cpu_time_t time; - }; - state_t* state; // points to state_ or a local copy within run() - state_t state_; - void set_end_time( cpu_time_t t ); - void set_page( int i, void* write, void const* read ); -public: - registers_t r; -}; - -#if BLARGG_NONPORTABLE - #define KSS_CPU_PAGE_OFFSET( addr ) (addr) -#else - #define KSS_CPU_PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) -#endif - -inline uint8_t* Kss_Cpu::write( unsigned addr ) -{ - return state->write [addr >> page_shift] + KSS_CPU_PAGE_OFFSET( addr ); -} - -inline uint8_t const* Kss_Cpu::read( unsigned addr ) -{ - return state->read [addr >> page_shift] + KSS_CPU_PAGE_OFFSET( addr ); -} - -inline void Kss_Cpu::set_end_time( cpu_time_t t ) -{ - cpu_time_t delta = state->base - t; - state->base = t; - state->time += delta; -} - -#endif diff --git a/libraries/game-music-emu/gme/Kss_Emu.cpp b/libraries/game-music-emu/gme/Kss_Emu.cpp deleted file mode 100644 index fd4905ce3..000000000 --- a/libraries/game-music-emu/gme/Kss_Emu.cpp +++ /dev/null @@ -1,416 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Kss_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -long const clock_rate = 3579545; -int const osc_count = Ay_Apu::osc_count + Scc_Apu::osc_count; - -Kss_Emu::Kss_Emu() -{ - sn = 0; - set_type( gme_kss_type ); - set_silence_lookahead( 6 ); - static const char* const names [osc_count] = { - "Square 1", "Square 2", "Square 3", - "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Wave 5" - }; - set_voice_names( names ); - - static int const types [osc_count] = { - wave_type | 0, wave_type | 1, wave_type | 2, - wave_type | 3, wave_type | 4, wave_type | 5, wave_type | 6, wave_type | 7 - }; - set_voice_types( types ); - - memset( unmapped_read, 0xFF, sizeof unmapped_read ); -} - -Kss_Emu::~Kss_Emu() { unload(); } - -void Kss_Emu::unload() -{ - delete sn; - sn = 0; - Classic_Emu::unload(); -} - -// Track info - -static void copy_kss_fields( Kss_Emu::header_t const& h, track_info_t* out ) -{ - const char* system = "MSX"; - if ( h.device_flags & 0x02 ) - { - system = "Sega Master System"; - if ( h.device_flags & 0x04 ) - system = "Game Gear"; - } - Gme_File::copy_field_( out->system, system ); -} - -blargg_err_t Kss_Emu::track_info_( track_info_t* out, int ) const -{ - copy_kss_fields( header_, out ); - return 0; -} - -static blargg_err_t check_kss_header( void const* header ) -{ - if ( memcmp( header, "KSCC", 4 ) && memcmp( header, "KSSX", 4 ) ) - return gme_wrong_file_type; - return 0; -} - -struct Kss_File : Gme_Info_ -{ - Kss_Emu::header_t header_; - - Kss_File() { set_type( gme_kss_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - blargg_err_t err = in.read( &header_, Kss_Emu::header_size ); - if ( err ) - return (err == in.eof_error ? gme_wrong_file_type : err); - return check_kss_header( &header_ ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_kss_fields( header_, out ); - return 0; - } -}; - -static Music_Emu* new_kss_emu () { return BLARGG_NEW Kss_Emu ; } -static Music_Emu* new_kss_file() { return BLARGG_NEW Kss_File; } - -static gme_type_t_ const gme_kss_type_ = { "MSX", 256, &new_kss_emu, &new_kss_file, "KSS", 0x03 }; -BLARGG_EXPORT extern gme_type_t const gme_kss_type = &gme_kss_type_; - - -// Setup - -void Kss_Emu::update_gain() -{ - double g = gain() * 1.4; - if ( scc_accessed ) - g *= 1.5; - ay.volume( g ); - scc.volume( g ); - if ( sn ) - sn->volume( g ); -} - -blargg_err_t Kss_Emu::load_( Data_Reader& in ) -{ - memset( &header_, 0, sizeof header_ ); - assert( offsetof (header_t,device_flags) == header_size - 1 ); - assert( offsetof (ext_header_t,msx_audio_vol) == ext_header_size - 1 ); - RETURN_ERR( rom.load( in, header_size, STATIC_CAST(header_t*,&header_), 0 ) ); - - RETURN_ERR( check_kss_header( header_.tag ) ); - - if ( header_.tag [3] == 'C' ) - { - if ( header_.extra_header ) - { - header_.extra_header = 0; - set_warning( "Unknown data in header" ); - } - if ( header_.device_flags & ~0x0F ) - { - header_.device_flags &= 0x0F; - set_warning( "Unknown data in header" ); - } - } - else - { - ext_header_t& ext = header_; - memcpy( &ext, rom.begin(), min( (int) ext_header_size, (int) header_.extra_header ) ); - if ( header_.extra_header > 0x10 ) - set_warning( "Unknown data in header" ); - } - - if ( header_.device_flags & 0x09 ) - set_warning( "FM sound not supported" ); - - scc_enabled = 0xC000; - if ( header_.device_flags & 0x04 ) - scc_enabled = 0; - - if ( header_.device_flags & 0x02 && !sn ) - CHECK_ALLOC( sn = BLARGG_NEW( Sms_Apu ) ); - - set_voice_count( osc_count ); - - return setup_buffer( ::clock_rate ); -} - -void Kss_Emu::update_eq( blip_eq_t const& eq ) -{ - ay.treble_eq( eq ); - scc.treble_eq( eq ); - if ( sn ) - sn->treble_eq( eq ); -} - -void Kss_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - int i2 = i - ay.osc_count; - if ( i2 >= 0 ) - scc.osc_output( i2, center ); - else - ay.osc_output( i, center ); - if ( sn && i < sn->osc_count ) - sn->osc_output( i, center, left, right ); -} - -// Emulation - -void Kss_Emu::set_tempo_( double t ) -{ - blip_time_t period = - (header_.device_flags & 0x40 ? ::clock_rate / 50 : ::clock_rate / 60); - play_period = blip_time_t (period / t); -} - -blargg_err_t Kss_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - memset( ram, 0xC9, 0x4000 ); - memset( ram + 0x4000, 0, sizeof ram - 0x4000 ); - - // copy driver code to lo RAM - static byte const bios [] = { - 0xD3, 0xA0, 0xF5, 0x7B, 0xD3, 0xA1, 0xF1, 0xC9, // $0001: WRTPSG - 0xD3, 0xA0, 0xDB, 0xA2, 0xC9 // $0009: RDPSG - }; - static byte const vectors [] = { - 0xC3, 0x01, 0x00, // $0093: WRTPSG vector - 0xC3, 0x09, 0x00, // $0096: RDPSG vector - }; - memcpy( ram + 0x01, bios, sizeof bios ); - memcpy( ram + 0x93, vectors, sizeof vectors ); - - // copy non-banked data into RAM - unsigned load_addr = get_le16( header_.load_addr ); - long orig_load_size = get_le16( header_.load_size ); - long load_size = min( orig_load_size, rom.file_size() ); - load_size = min( load_size, long (mem_size - load_addr) ); - if ( load_size != orig_load_size ) - set_warning( "Excessive data size" ); - memcpy( ram + load_addr, rom.begin() + header_.extra_header, load_size ); - - rom.set_addr( -load_size - header_.extra_header ); - - // check available bank data - blargg_long const bank_size = this->bank_size(); - int max_banks = (rom.file_size() - load_size + bank_size - 1) / bank_size; - bank_count = header_.bank_mode & 0x7F; - if ( bank_count > max_banks ) - { - bank_count = max_banks; - set_warning( "Bank data missing" ); - } - //debug_printf( "load_size : $%X\n", load_size ); - //debug_printf( "bank_size : $%X\n", bank_size ); - //debug_printf( "bank_count: %d (%d claimed)\n", bank_count, header_.bank_mode & 0x7F ); - - ram [idle_addr] = 0xFF; - cpu::reset( unmapped_write, unmapped_read ); - cpu::map_mem( 0, mem_size, ram, ram ); - - ay.reset(); - scc.reset(); - if ( sn ) - sn->reset(); - r.sp = 0xF380; - ram [--r.sp] = idle_addr >> 8; - ram [--r.sp] = idle_addr & 0xFF; - r.b.a = track; - r.pc = get_le16( header_.init_addr ); - next_play = play_period; - scc_accessed = false; - gain_updated = false; - update_gain(); - ay_latch = 0; - - return 0; -} - -void Kss_Emu::set_bank( int logical, int physical ) -{ - unsigned const bank_size = this->bank_size(); - - unsigned addr = 0x8000; - if ( logical && bank_size == 8 * 1024 ) - addr = 0xA000; - - physical -= header_.first_bank; - if ( (unsigned) physical >= (unsigned) bank_count ) - { - byte* data = ram + addr; - cpu::map_mem( addr, bank_size, data, data ); - } - else - { - long phys = physical * (blargg_long) bank_size; - for ( unsigned offset = 0; offset < bank_size; offset += page_size ) - cpu::map_mem( addr + offset, page_size, - unmapped_write, rom.at_addr( phys + offset ) ); - } -} - -void Kss_Emu::cpu_write( unsigned addr, int data ) -{ - data &= 0xFF; - switch ( addr ) - { - case 0x9000: - set_bank( 0, data ); - return; - - case 0xB000: - set_bank( 1, data ); - return; - } - - int scc_addr = (addr & 0xDFFF) ^ 0x9800; - if ( scc_addr < scc.reg_count ) - { - scc_accessed = true; - scc.write( time(), scc_addr, data ); - return; - } - - debug_printf( "LD ($%04X),$%02X\n", addr, data ); -} - -void kss_cpu_write( Kss_Cpu* cpu, unsigned addr, int data ) -{ - *cpu->write( addr ) = data; - if ( (addr & STATIC_CAST(Kss_Emu&,*cpu).scc_enabled) == 0x8000 ) - STATIC_CAST(Kss_Emu&,*cpu).cpu_write( addr, data ); -} - -void kss_cpu_out( Kss_Cpu* cpu, cpu_time_t time, unsigned addr, int data ) -{ - data &= 0xFF; - Kss_Emu& emu = STATIC_CAST(Kss_Emu&,*cpu); - switch ( addr & 0xFF ) - { - case 0xA0: - emu.ay_latch = data & 0x0F; - return; - - case 0xA1: - GME_APU_HOOK( &emu, emu.ay_latch, data ); - emu.ay.write( time, emu.ay_latch, data ); - return; - - case 0x06: - if ( emu.sn && (emu.header_.device_flags & 0x04) ) - { - emu.sn->write_ggstereo( time, data ); - return; - } - break; - - case 0x7E: - case 0x7F: - if ( emu.sn ) - { - GME_APU_HOOK( &emu, 16, data ); - emu.sn->write_data( time, data ); - return; - } - break; - - case 0xFE: - emu.set_bank( 0, data ); - return; - - #ifndef NDEBUG - case 0xF1: // FM data - if ( data ) - break; // trap non-zero data - case 0xF0: // FM addr - case 0xA8: // PPI - return; - #endif - } - - debug_printf( "OUT $%04X,$%02X\n", addr, data ); -} - -int kss_cpu_in( Kss_Cpu*, cpu_time_t, unsigned addr ) -{ - //Kss_Emu& emu = STATIC_CAST(Kss_Emu&,*cpu); - //switch ( addr & 0xFF ) - //{ - //} - - debug_printf( "IN $%04X\n", addr ); - return 0; -} - -// Emulation - -blargg_err_t Kss_Emu::run_clocks( blip_time_t& duration, int ) -{ - while ( time() < duration ) - { - blip_time_t end = min( duration, next_play ); - cpu::run( min( duration, next_play ) ); - if ( r.pc == idle_addr ) - set_time( end ); - - if ( time() >= next_play ) - { - next_play += play_period; - if ( r.pc == idle_addr ) - { - if ( !gain_updated ) - { - gain_updated = true; - if ( scc_accessed ) - update_gain(); - } - - ram [--r.sp] = idle_addr >> 8; - ram [--r.sp] = idle_addr & 0xFF; - r.pc = get_le16( header_.play_addr ); - GME_FRAME_HOOK( this ); - } - } - } - - duration = time(); - next_play -= duration; - check( next_play >= 0 ); - adjust_time( -duration ); - ay.end_frame( duration ); - scc.end_frame( duration ); - if ( sn ) - sn->end_frame( duration ); - - return 0; -} diff --git a/libraries/game-music-emu/gme/Kss_Emu.h b/libraries/game-music-emu/gme/Kss_Emu.h deleted file mode 100644 index 467b28abd..000000000 --- a/libraries/game-music-emu/gme/Kss_Emu.h +++ /dev/null @@ -1,95 +0,0 @@ -// MSX computer KSS music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef KSS_EMU_H -#define KSS_EMU_H - -#include "Classic_Emu.h" -#include "Kss_Scc_Apu.h" -#include "Kss_Cpu.h" -#include "Sms_Apu.h" -#include "Ay_Apu.h" - -class Kss_Emu : private Kss_Cpu, public Classic_Emu { - typedef Kss_Cpu cpu; -public: - // KSS file header - enum { header_size = 0x10 }; - struct header_t - { - byte tag [4]; - byte load_addr [2]; - byte load_size [2]; - byte init_addr [2]; - byte play_addr [2]; - byte first_bank; - byte bank_mode; - byte extra_header; - byte device_flags; - }; - - enum { ext_header_size = 0x10 }; - struct ext_header_t - { - byte data_size [4]; - byte unused [4]; - byte first_track [2]; - byte last_tack [2]; - byte psg_vol; - byte scc_vol; - byte msx_music_vol; - byte msx_audio_vol; - }; - - struct composite_header_t : header_t, ext_header_t { }; - - // Header for currently loaded file - composite_header_t const& header() const { return header_; } - - static gme_type_t static_type() { return gme_kss_type; } -public: - Kss_Emu(); - ~Kss_Emu(); -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_( Data_Reader& ); - blargg_err_t start_track_( int ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); - void unload(); -private: - Rom_Data rom; - composite_header_t header_; - - bool scc_accessed; - bool gain_updated; - void update_gain(); - - unsigned scc_enabled; // 0 or 0xC000 - int bank_count; - void set_bank( int logical, int physical ); - blargg_long bank_size() const { return (16 * 1024L) >> (header_.bank_mode >> 7 & 1); } - - blip_time_t play_period; - blip_time_t next_play; - int ay_latch; - - friend void kss_cpu_out( class Kss_Cpu*, cpu_time_t, unsigned addr, int data ); - friend int kss_cpu_in( class Kss_Cpu*, cpu_time_t, unsigned addr ); - void cpu_write( unsigned addr, int data ); - friend void kss_cpu_write( class Kss_Cpu*, unsigned addr, int data ); - - // large items - enum { mem_size = 0x10000 }; - byte ram [mem_size + cpu_padding]; - - Ay_Apu ay; - Scc_Apu scc; - Sms_Apu* sn; - byte unmapped_read [0x100]; - byte unmapped_write [page_size]; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Kss_Scc_Apu.cpp b/libraries/game-music-emu/gme/Kss_Scc_Apu.cpp deleted file mode 100644 index bb84b3250..000000000 --- a/libraries/game-music-emu/gme/Kss_Scc_Apu.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Kss_Scc_Apu.h" - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// Tones above this frequency are treated as disabled tone at half volume. -// Power of two is more efficient (avoids division). -unsigned const inaudible_freq = 16384; - -int const wave_size = 0x20; - -void Scc_Apu::run_until( blip_time_t end_time ) -{ - for ( int index = 0; index < osc_count; index++ ) - { - osc_t& osc = oscs [index]; - - Blip_Buffer* const output = osc.output; - if ( !output ) - continue; - output->set_modified(); - - blip_time_t period = (regs [0x80 + index * 2 + 1] & 0x0F) * 0x100 + - regs [0x80 + index * 2] + 1; - int volume = 0; - if ( regs [0x8F] & (1 << index) ) - { - blip_time_t inaudible_period = (blargg_ulong) (output->clock_rate() + - inaudible_freq * 32) / (inaudible_freq * 16); - if ( period > inaudible_period ) - volume = (regs [0x8A + index] & 0x0F) * (amp_range / 256 / 15); - } - - int8_t const* wave = (int8_t*) regs + index * wave_size; - if ( index == osc_count - 1 ) - wave -= wave_size; // last two oscs share wave - { - int amp = wave [osc.phase] * volume; - int delta = amp - osc.last_amp; - if ( delta ) - { - osc.last_amp = amp; - synth.offset( last_time, delta, output ); - } - } - - blip_time_t time = last_time + osc.delay; - if ( time < end_time ) - { - if ( !volume ) - { - // maintain phase - blargg_long count = (end_time - time + period - 1) / period; - osc.phase = (osc.phase + count) & (wave_size - 1); - time += count * period; - } - else - { - - int phase = osc.phase; - int last_wave = wave [phase]; - phase = (phase + 1) & (wave_size - 1); // pre-advance for optimal inner loop - - do - { - int amp = wave [phase]; - phase = (phase + 1) & (wave_size - 1); - int delta = amp - last_wave; - if ( delta ) - { - last_wave = amp; - synth.offset( time, delta * volume, output ); - } - time += period; - } - while ( time < end_time ); - - osc.phase = phase = (phase - 1) & (wave_size - 1); // undo pre-advance - osc.last_amp = wave [phase] * volume; - } - } - osc.delay = time - end_time; - } - last_time = end_time; -} diff --git a/libraries/game-music-emu/gme/Kss_Scc_Apu.h b/libraries/game-music-emu/gme/Kss_Scc_Apu.h deleted file mode 100644 index eda5747fe..000000000 --- a/libraries/game-music-emu/gme/Kss_Scc_Apu.h +++ /dev/null @@ -1,106 +0,0 @@ -// Konami SCC sound chip emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef KSS_SCC_APU_H -#define KSS_SCC_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" -#include - -class Scc_Apu { -public: - // Set buffer to generate all sound into, or disable sound if NULL - void output( Blip_Buffer* ); - - // Reset sound chip - void reset(); - - // Write to register at specified time - enum { reg_count = 0x90 }; - void write( blip_time_t time, int reg, int data ); - - // Run sound to specified time, end current time frame, then start a new - // time frame at time 0. Time frames have no effect on emulation and each - // can be whatever length is convenient. - void end_frame( blip_time_t length ); - -// Additional features - - // Set sound output of specific oscillator to buffer, where index is - // 0 to 4. If buffer is NULL, the specified oscillator is muted. - enum { osc_count = 5 }; - void osc_output( int index, Blip_Buffer* ); - - // Set overall volume (default is 1.0) - void volume( double ); - - // Set treble equalization (see documentation) - void treble_eq( blip_eq_t const& ); - -public: - Scc_Apu(); -private: - enum { amp_range = 0x8000 }; - struct osc_t - { - int delay; - int phase; - int last_amp; - Blip_Buffer* output; - }; - osc_t oscs [osc_count]; - blip_time_t last_time; - unsigned char regs [reg_count]; - Blip_Synth synth; - - void run_until( blip_time_t ); -}; - -inline void Scc_Apu::volume( double v ) { synth.volume( 0.43 / osc_count / amp_range * v ); } - -inline void Scc_Apu::treble_eq( blip_eq_t const& eq ) { synth.treble_eq( eq ); } - -inline void Scc_Apu::osc_output( int index, Blip_Buffer* b ) -{ - assert( (unsigned) index < osc_count ); - oscs [index].output = b; -} - -inline void Scc_Apu::write( blip_time_t time, int addr, int data ) -{ - assert( (unsigned) addr < reg_count ); - run_until( time ); - regs [addr] = data; -} - -inline void Scc_Apu::end_frame( blip_time_t end_time ) -{ - if ( end_time > last_time ) - run_until( end_time ); - last_time -= end_time; - assert( last_time >= 0 ); -} - -inline void Scc_Apu::output( Blip_Buffer* buf ) -{ - for ( int i = 0; i < osc_count; i++ ) - oscs [i].output = buf; -} - -inline Scc_Apu::Scc_Apu() -{ - output( 0 ); -} - -inline void Scc_Apu::reset() -{ - last_time = 0; - - for ( int i = 0; i < osc_count; i++ ) - memset( &oscs [i], 0, offsetof (osc_t,output) ); - - memset( regs, 0, sizeof regs ); -} - -#endif diff --git a/libraries/game-music-emu/gme/M3u_Playlist.cpp b/libraries/game-music-emu/gme/M3u_Playlist.cpp deleted file mode 100644 index e751d4cc8..000000000 --- a/libraries/game-music-emu/gme/M3u_Playlist.cpp +++ /dev/null @@ -1,426 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "M3u_Playlist.h" -#include "Music_Emu.h" - -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// gme functions defined here to avoid linking in m3u code unless it's used - -blargg_err_t Gme_File::load_m3u_( blargg_err_t err ) -{ - require( raw_track_count_ ); // file must be loaded first - - if ( !err ) - { - if ( playlist.size() ) - track_count_ = playlist.size(); - - int line = playlist.first_error(); - if ( line ) - { - // avoid using bloated printf() - char* out = &playlist_warning [sizeof playlist_warning]; - *--out = 0; - do { - *--out = line % 10 + '0'; - } while ( (line /= 10) > 0 ); - - static const char str [] = "Problem in m3u at line "; - out -= sizeof str - 1; - memcpy( out, str, sizeof str - 1 ); - set_warning( out ); - } - } - return err; -} - -blargg_err_t Gme_File::load_m3u( const char* path ) { return load_m3u_( playlist.load( path ) ); } - -blargg_err_t Gme_File::load_m3u( Data_Reader& in ) { return load_m3u_( playlist.load( in ) ); } - -BLARGG_EXPORT gme_err_t gme_load_m3u( Music_Emu* me, const char* path ) { return me->load_m3u( path ); } - -BLARGG_EXPORT gme_err_t gme_load_m3u_data( Music_Emu* me, const void* data, long size ) -{ - Mem_File_Reader in( data, size ); - return me->load_m3u( in ); -} - - - -static char* skip_white( char* in ) -{ - while ( *in == ' ' ) - in++; - return in; -} - -inline unsigned from_dec( unsigned n ) { return n - '0'; } - -static char* parse_filename( char* in, M3u_Playlist::entry_t& entry ) -{ - entry.file = in; - entry.type = ""; - char* out = in; - while ( 1 ) - { - int c = *in; - if ( !c ) break; - in++; - - if ( c == ',' ) // commas in filename - { - char* p = skip_white( in ); - if ( *p == '$' || from_dec( *p ) <= 9 ) - { - in = p; - break; - } - } - - if ( c == ':' && in [0] == ':' && in [1] && in [2] != ',' ) // ::type suffix - { - entry.type = ++in; - while ( (c = *in) != 0 && c != ',' ) - in++; - if ( c == ',' ) - { - *in++ = 0; // terminate type - in = skip_white( in ); - } - break; - } - - if ( c == '\\' ) // \ prefix for special characters - { - c = *in; - if ( !c ) break; - in++; - } - *out++ = (char) c; - } - *out = 0; // terminate string - return in; -} - -static char* next_field( char* in, int* result ) -{ - while ( 1 ) - { - in = skip_white( in ); - - if ( !*in ) - break; - - if ( *in == ',' ) - { - in++; - break; - } - - *result = 1; - in++; - } - return skip_white( in ); -} - -static char* parse_int_( char* in, int* out ) -{ - int n = 0; - while ( 1 ) - { - unsigned d = from_dec( *in ); - if ( d > 9 ) - break; - in++; - n = n * 10 + d; - *out = n; - } - return in; -} - -static char* parse_int( char* in, int* out, int* result ) -{ - return next_field( parse_int_( in, out ), result ); -} - -// Returns 16 or greater if not hex -inline int from_hex_char( int h ) -{ - h -= 0x30; - if ( (unsigned) h > 9 ) - h = ((h - 0x11) & 0xDF) + 10; - return h; -} - -static char* parse_track( char* in, M3u_Playlist::entry_t& entry, int* result ) -{ - if ( *in == '$' ) - { - in++; - int n = 0; - while ( 1 ) - { - int h = from_hex_char( *in ); - if ( h > 15 ) - break; - in++; - n = n * 16 + h; - entry.track = n; - } - } - else - { - in = parse_int_( in, &entry.track ); - if ( entry.track >= 0 ) - entry.decimal_track = 1; - } - return next_field( in, result ); -} - -static char* parse_time_( char* in, int* out ) -{ - *out = -1; - int n = -1; - in = parse_int_( in, &n ); - if ( n >= 0 ) - { - *out = n; - if ( *in == ':' ) - { - n = -1; - in = parse_int_( in + 1, &n ); - if ( n >= 0 ) - *out = *out * 60 + n; - } - } - return in; -} - -static char* parse_time( char* in, int* out, int* result ) -{ - return next_field( parse_time_( in, out ), result ); -} - -static char* parse_name( char* in ) -{ - char* out = in; - while ( 1 ) - { - int c = *in; - if ( !c ) break; - in++; - - if ( c == ',' ) // commas in string - { - char* p = skip_white( in ); - if ( *p == ',' || *p == '-' || from_dec( *p ) <= 9 ) - { - in = p; - break; - } - } - - if ( c == '\\' ) // \ prefix for special characters - { - c = *in; - if ( !c ) break; - in++; - } - *out++ = (char) c; - } - *out = 0; // terminate string - return in; -} - -static int parse_line( char* in, M3u_Playlist::entry_t& entry ) -{ - int result = 0; - - // file - entry.file = in; - entry.type = ""; - in = parse_filename( in, entry ); - - // track - entry.track = -1; - entry.decimal_track = 0; - in = parse_track( in, entry, &result ); - - // name - entry.name = in; - in = parse_name( in ); - - // time - entry.length = -1; - in = parse_time( in, &entry.length, &result ); - - // loop - entry.intro = -1; - entry.loop = -1; - if ( *in == '-' ) - { - entry.loop = entry.length; - in++; - } - else - { - in = parse_time_( in, &entry.loop ); - if ( entry.loop >= 0 ) - { - entry.intro = 0; - if ( *in == '-' ) // trailing '-' means that intro length was specified - { - in++; - entry.intro = entry.loop; - entry.loop = entry.length - entry.intro; - } - } - } - in = next_field( in, &result ); - - // fade - entry.fade = -1; - in = parse_time( in, &entry.fade, &result ); - - // repeat - entry.repeat = -1; - in = parse_int( in, &entry.repeat, &result ); - - return result; -} - -static void parse_comment( char* in, M3u_Playlist::info_t& info, bool first ) -{ - in = skip_white( in + 1 ); - const char* field = in; - while ( *in && *in != ':' ) - in++; - - if ( *in == ':' ) - { - const char* text = skip_white( in + 1 ); - if ( *text ) - { - *in = 0; - if ( !strcmp( "Composer", field ) ) info.composer = text; - else if ( !strcmp( "Engineer", field ) ) info.engineer = text; - else if ( !strcmp( "Ripping" , field ) ) info.ripping = text; - else if ( !strcmp( "Tagging" , field ) ) info.tagging = text; - else - text = 0; - if ( text ) - return; - *in = ':'; - } - } - - if ( first ) - info.title = field; -} - -blargg_err_t M3u_Playlist::parse_() -{ - info_.title = ""; - info_.composer = ""; - info_.engineer = ""; - info_.ripping = ""; - info_.tagging = ""; - - int const CR = 13; - int const LF = 10; - - data.end() [-1] = LF; // terminate input - - first_error_ = 0; - bool first_comment = true; - int line = 0; - int count = 0; - char* in = data.begin(); - while ( in < data.end() ) - { - // find end of line and terminate it - line++; - char* begin = in; - while ( *in != CR && *in != LF ) - { - if ( !*in ) - return "Not an m3u playlist"; - in++; - } - if ( in [0] == CR && in [1] == LF ) // treat CR,LF as a single line - *in++ = 0; - *in++ = 0; - - // parse line - if ( *begin == '#' ) - { - parse_comment( begin, info_, first_comment ); - first_comment = false; - } - else if ( *begin ) - { - if ( (int) entries.size() <= count ) - RETURN_ERR( entries.resize( count * 2 + 64 ) ); - - if ( !parse_line( begin, entries [count] ) ) - count++; - else if ( !first_error_ ) - first_error_ = line; - first_comment = false; - } - } - if ( count <= 0 ) - return "Not an m3u playlist"; - - if ( !(info_.composer [0] | info_.engineer [0] | info_.ripping [0] | info_.tagging [0]) ) - info_.title = ""; - - return entries.resize( count ); -} - -blargg_err_t M3u_Playlist::parse() -{ - blargg_err_t err = parse_(); - if ( err ) - { - entries.clear(); - data.clear(); - } - return err; -} - -blargg_err_t M3u_Playlist::load( Data_Reader& in ) -{ - RETURN_ERR( data.resize( in.remain() + 1 ) ); - RETURN_ERR( in.read( data.begin(), data.size() - 1 ) ); - return parse(); -} - -blargg_err_t M3u_Playlist::load( const char* path ) -{ - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - return load( in ); -} - -blargg_err_t M3u_Playlist::load( void const* in, long size ) -{ - RETURN_ERR( data.resize( size + 1 ) ); - memcpy( data.begin(), in, size ); - return parse(); -} diff --git a/libraries/game-music-emu/gme/M3u_Playlist.h b/libraries/game-music-emu/gme/M3u_Playlist.h deleted file mode 100644 index 6757b7cfb..000000000 --- a/libraries/game-music-emu/gme/M3u_Playlist.h +++ /dev/null @@ -1,67 +0,0 @@ -// M3U playlist file parser, with support for subtrack information - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef M3U_PLAYLIST_H -#define M3U_PLAYLIST_H - -#include "blargg_common.h" -#include "Data_Reader.h" - -class M3u_Playlist { -public: - // Load playlist data - blargg_err_t load( const char* path ); - blargg_err_t load( Data_Reader& in ); - blargg_err_t load( void const* data, long size ); - - // Line number of first parse error, 0 if no error. Any lines with parse - // errors are ignored. - int first_error() const { return first_error_; } - - struct info_t - { - const char* title; - const char* composer; - const char* engineer; - const char* ripping; - const char* tagging; - }; - info_t const& info() const { return info_; } - - struct entry_t - { - const char* file; // filename without stupid ::TYPE suffix - const char* type; // if filename has ::TYPE suffix, this will be "TYPE". "" if none. - const char* name; - bool decimal_track; // true if track was specified in hex - // integers are -1 if not present - int track; // 1-based - int length; // seconds - int intro; - int loop; - int fade; - int repeat; // count - }; - entry_t const& operator [] ( int i ) const { return entries [i]; } - int size() const { return entries.size(); } - - void clear(); - -private: - blargg_vector entries; - blargg_vector data; - int first_error_; - info_t info_; - - blargg_err_t parse(); - blargg_err_t parse_(); -}; - -inline void M3u_Playlist::clear() -{ - first_error_ = 0; - entries.clear(); - data.clear(); -} - -#endif diff --git a/libraries/game-music-emu/gme/Multi_Buffer.cpp b/libraries/game-music-emu/gme/Multi_Buffer.cpp deleted file mode 100644 index 5f000ceeb..000000000 --- a/libraries/game-music-emu/gme/Multi_Buffer.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// Blip_Buffer 0.4.1. http://www.slack.net/~ant/ - -#include "Multi_Buffer.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf ) -{ - length_ = 0; - sample_rate_ = 0; - channels_changed_count_ = 1; -} - -blargg_err_t Multi_Buffer::set_channel_count( int ) { return 0; } - -// Silent_Buffer - -Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse -{ - // TODO: better to use empty Blip_Buffer so caller never has to check for NULL? - chan.left = 0; - chan.center = 0; - chan.right = 0; -} - -// Mono_Buffer - -Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 ) -{ - chan.center = &buf; - chan.left = &buf; - chan.right = &buf; -} - -Mono_Buffer::~Mono_Buffer() { } - -blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec ) -{ - RETURN_ERR( buf.set_sample_rate( rate, msec ) ); - return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() ); -} - -// Stereo_Buffer - -Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 ) -{ - chan.center = &bufs [0]; - chan.left = &bufs [1]; - chan.right = &bufs [2]; -} - -Stereo_Buffer::~Stereo_Buffer() { } - -blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec ) -{ - for ( int i = 0; i < buf_count; i++ ) - RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) ); - return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() ); -} - -void Stereo_Buffer::clock_rate( long rate ) -{ - for ( int i = 0; i < buf_count; i++ ) - bufs [i].clock_rate( rate ); -} - -void Stereo_Buffer::bass_freq( int bass ) -{ - for ( int i = 0; i < buf_count; i++ ) - bufs [i].bass_freq( bass ); -} - -void Stereo_Buffer::clear() -{ - stereo_added = 0; - was_stereo = false; - for ( int i = 0; i < buf_count; i++ ) - bufs [i].clear(); -} - -void Stereo_Buffer::end_frame( blip_time_t clock_count ) -{ - stereo_added = 0; - for ( int i = 0; i < buf_count; i++ ) - { - stereo_added |= bufs [i].clear_modified() << i; - bufs [i].end_frame( clock_count ); - } -} - -long Stereo_Buffer::read_samples( blip_sample_t* out, long count ) -{ - require( !(count & 1) ); // count must be even - count = (unsigned) count / 2; - - long avail = bufs [0].samples_avail(); - if ( count > avail ) - count = avail; - if ( count ) - { - int bufs_used = stereo_added | was_stereo; - //debug_printf( "%X\n", bufs_used ); - if ( bufs_used <= 1 ) - { - mix_mono( out, count ); - bufs [0].remove_samples( count ); - bufs [1].remove_silence( count ); - bufs [2].remove_silence( count ); - } - else if ( bufs_used & 1 ) - { - mix_stereo( out, count ); - bufs [0].remove_samples( count ); - bufs [1].remove_samples( count ); - bufs [2].remove_samples( count ); - } - else - { - mix_stereo_no_center( out, count ); - bufs [0].remove_silence( count ); - bufs [1].remove_samples( count ); - bufs [2].remove_samples( count ); - } - - // to do: this might miss opportunities for optimization - if ( !bufs [0].samples_avail() ) - { - was_stereo = stereo_added; - stereo_added = 0; - } - } - - return count * 2; -} - -void Stereo_Buffer::mix_stereo( blip_sample_t* out_, blargg_long count ) -{ - blip_sample_t* BLIP_RESTRICT out = out_; - int const bass = BLIP_READER_BASS( bufs [1] ); - BLIP_READER_BEGIN( left, bufs [1] ); - BLIP_READER_BEGIN( right, bufs [2] ); - BLIP_READER_BEGIN( center, bufs [0] ); - - for ( ; count; --count ) - { - int c = BLIP_READER_READ( center ); - blargg_long l = c + BLIP_READER_READ( left ); - blargg_long r = c + BLIP_READER_READ( right ); - if ( (int16_t) l != l ) - l = 0x7FFF - (l >> 24); - - BLIP_READER_NEXT( center, bass ); - if ( (int16_t) r != r ) - r = 0x7FFF - (r >> 24); - - BLIP_READER_NEXT( left, bass ); - BLIP_READER_NEXT( right, bass ); - - out [0] = l; - out [1] = r; - out += 2; - } - - BLIP_READER_END( center, bufs [0] ); - BLIP_READER_END( right, bufs [2] ); - BLIP_READER_END( left, bufs [1] ); -} - -void Stereo_Buffer::mix_stereo_no_center( blip_sample_t* out_, blargg_long count ) -{ - blip_sample_t* BLIP_RESTRICT out = out_; - int const bass = BLIP_READER_BASS( bufs [1] ); - BLIP_READER_BEGIN( left, bufs [1] ); - BLIP_READER_BEGIN( right, bufs [2] ); - - for ( ; count; --count ) - { - blargg_long l = BLIP_READER_READ( left ); - if ( (int16_t) l != l ) - l = 0x7FFF - (l >> 24); - - blargg_long r = BLIP_READER_READ( right ); - if ( (int16_t) r != r ) - r = 0x7FFF - (r >> 24); - - BLIP_READER_NEXT( left, bass ); - BLIP_READER_NEXT( right, bass ); - - out [0] = l; - out [1] = r; - out += 2; - } - - BLIP_READER_END( right, bufs [2] ); - BLIP_READER_END( left, bufs [1] ); -} - -void Stereo_Buffer::mix_mono( blip_sample_t* out_, blargg_long count ) -{ - blip_sample_t* BLIP_RESTRICT out = out_; - int const bass = BLIP_READER_BASS( bufs [0] ); - BLIP_READER_BEGIN( center, bufs [0] ); - - for ( ; count; --count ) - { - blargg_long s = BLIP_READER_READ( center ); - if ( (int16_t) s != s ) - s = 0x7FFF - (s >> 24); - - BLIP_READER_NEXT( center, bass ); - out [0] = s; - out [1] = s; - out += 2; - } - - BLIP_READER_END( center, bufs [0] ); -} diff --git a/libraries/game-music-emu/gme/Multi_Buffer.h b/libraries/game-music-emu/gme/Multi_Buffer.h deleted file mode 100644 index 82c8b3ab5..000000000 --- a/libraries/game-music-emu/gme/Multi_Buffer.h +++ /dev/null @@ -1,158 +0,0 @@ -// Multi-channel sound buffer interface, and basic mono and stereo buffers - -// Blip_Buffer 0.4.1 -#ifndef MULTI_BUFFER_H -#define MULTI_BUFFER_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -// Interface to one or more Blip_Buffers mapped to one or more channels -// consisting of left, center, and right buffers. -class Multi_Buffer { -public: - Multi_Buffer( int samples_per_frame ); - virtual ~Multi_Buffer() { } - - // Set the number of channels available - virtual blargg_err_t set_channel_count( int ); - - // Get indexed channel, from 0 to channel count - 1 - struct channel_t { - Blip_Buffer* center; - Blip_Buffer* left; - Blip_Buffer* right; - }; - enum { type_index_mask = 0xFF }; - enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type }; - virtual channel_t channel( int index, int type ) = 0; - - // See Blip_Buffer.h - virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) = 0; - virtual void clock_rate( long ) = 0; - virtual void bass_freq( int ) = 0; - virtual void clear() = 0; - long sample_rate() const; - - // Length of buffer, in milliseconds - int length() const; - - // See Blip_Buffer.h - virtual void end_frame( blip_time_t ) = 0; - - // Number of samples per output frame (1 = mono, 2 = stereo) - int samples_per_frame() const; - - // Count of changes to channel configuration. Incremented whenever - // a change is made to any of the Blip_Buffers for any channel. - unsigned channels_changed_count() { return channels_changed_count_; } - - // See Blip_Buffer.h - virtual long read_samples( blip_sample_t*, long ) = 0; - virtual long samples_avail() const = 0; - -public: - BLARGG_DISABLE_NOTHROW -protected: - void channels_changed() { channels_changed_count_++; } -private: - // noncopyable - Multi_Buffer( const Multi_Buffer& ); - Multi_Buffer& operator = ( const Multi_Buffer& ); - - unsigned channels_changed_count_; - long sample_rate_; - int length_; - int const samples_per_frame_; -}; - -// Uses a single buffer and outputs mono samples. -class Mono_Buffer : public Multi_Buffer { - Blip_Buffer buf; - channel_t chan; -public: - // Buffer used for all channels - Blip_Buffer* center() { return &buf; } - -public: - Mono_Buffer(); - ~Mono_Buffer(); - blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ); - void clock_rate( long rate ) { buf.clock_rate( rate ); } - void bass_freq( int freq ) { buf.bass_freq( freq ); } - void clear() { buf.clear(); } - long samples_avail() const { return buf.samples_avail(); } - long read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); } - channel_t channel( int, int ) { return chan; } - void end_frame( blip_time_t t ) { buf.end_frame( t ); } -}; - -// Uses three buffers (one for center) and outputs stereo sample pairs. -class Stereo_Buffer : public Multi_Buffer { -public: - - // Buffers used for all channels - Blip_Buffer* center() { return &bufs [0]; } - Blip_Buffer* left() { return &bufs [1]; } - Blip_Buffer* right() { return &bufs [2]; } - -public: - Stereo_Buffer(); - ~Stereo_Buffer(); - blargg_err_t set_sample_rate( long, int msec = blip_default_length ); - void clock_rate( long ); - void bass_freq( int ); - void clear(); - channel_t channel( int, int ) { return chan; } - void end_frame( blip_time_t ); - - long samples_avail() const { return bufs [0].samples_avail() * 2; } - long read_samples( blip_sample_t*, long ); - -private: - enum { buf_count = 3 }; - Blip_Buffer bufs [buf_count]; - channel_t chan; - int stereo_added; - int was_stereo; - - void mix_stereo_no_center( blip_sample_t*, blargg_long ); - void mix_stereo( blip_sample_t*, blargg_long ); - void mix_mono( blip_sample_t*, blargg_long ); -}; - -// Silent_Buffer generates no samples, useful where no sound is wanted -class Silent_Buffer : public Multi_Buffer { - channel_t chan; -public: - Silent_Buffer(); - blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ); - void clock_rate( long ) { } - void bass_freq( int ) { } - void clear() { } - channel_t channel( int, int ) { return chan; } - void end_frame( blip_time_t ) { } - long samples_avail() const { return 0; } - long read_samples( blip_sample_t*, long ) { return 0; } -}; - - -inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec ) -{ - sample_rate_ = rate; - length_ = msec; - return 0; -} - -inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec ) -{ - return Multi_Buffer::set_sample_rate( rate, msec ); -} - -inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; } - -inline long Multi_Buffer::sample_rate() const { return sample_rate_; } - -inline int Multi_Buffer::length() const { return length_; } - -#endif diff --git a/libraries/game-music-emu/gme/Music_Emu.cpp b/libraries/game-music-emu/gme/Music_Emu.cpp deleted file mode 100644 index e60e7ca5d..000000000 --- a/libraries/game-music-emu/gme/Music_Emu.cpp +++ /dev/null @@ -1,451 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Music_Emu.h" - -#include "Multi_Buffer.h" -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -int const silence_max = 6; // seconds -int const silence_threshold = 0x10; -long const fade_block_size = 512; -int const fade_shift = 8; // fade ends with gain at 1.0 / (1 << fade_shift) - -Music_Emu::equalizer_t const Music_Emu::tv_eq = - Music_Emu::make_equalizer( -8.0, 180 ); - -void Music_Emu::clear_track_vars() -{ - current_track_ = -1; - out_time = 0; - emu_time = 0; - emu_track_ended_ = true; - track_ended_ = true; - fade_start = INT_MAX / 2 + 1; - fade_step = 1; - silence_time = 0; - silence_count = 0; - buf_remain = 0; - warning(); // clear warning -} - -void Music_Emu::unload() -{ - voice_count_ = 0; - clear_track_vars(); - Gme_File::unload(); -} - -Music_Emu::Music_Emu() -{ - effects_buffer = 0; - multi_channel_ = false; - sample_rate_ = 0; - mute_mask_ = 0; - tempo_ = 1.0; - gain_ = 1.0; - - // defaults - max_initial_silence = 2; - silence_lookahead = 3; - ignore_silence_ = false; - equalizer_.treble = -1.0; - equalizer_.bass = 60; - - emu_autoload_playback_limit_ = true; - - static const char* const names [] = { - "Voice 1", "Voice 2", "Voice 3", "Voice 4", - "Voice 5", "Voice 6", "Voice 7", "Voice 8" - }; - set_voice_names( names ); - Music_Emu::unload(); // non-virtual -} - -Music_Emu::~Music_Emu() { delete effects_buffer; } - -blargg_err_t Music_Emu::set_sample_rate( long rate ) -{ - require( !sample_rate() ); // sample rate can't be changed once set - RETURN_ERR( set_sample_rate_( rate ) ); - RETURN_ERR( buf.resize( buf_size ) ); - sample_rate_ = rate; - return 0; -} - -void Music_Emu::pre_load() -{ - require( sample_rate() ); // set_sample_rate() must be called before loading a file - Gme_File::pre_load(); -} - -void Music_Emu::set_equalizer( equalizer_t const& eq ) -{ - equalizer_ = eq; - set_equalizer_( eq ); -} - -bool Music_Emu::multi_channel() const -{ - return this->multi_channel_; -} - -blargg_err_t Music_Emu::set_multi_channel( bool ) -{ - // by default not supported, derived may override this - return "unsupported for this emulator type"; -} - -blargg_err_t Music_Emu::set_multi_channel_( bool isEnabled ) -{ - // multi channel support must be set at the very beginning - require( !sample_rate() ); - multi_channel_ = isEnabled; - return 0; -} - -void Music_Emu::mute_voice( int index, bool mute ) -{ - require( (unsigned) index < (unsigned) voice_count() ); - int bit = 1 << index; - int mask = mute_mask_ | bit; - if ( !mute ) - mask ^= bit; - mute_voices( mask ); -} - -void Music_Emu::mute_voices( int mask ) -{ - require( sample_rate() ); // sample rate must be set first - mute_mask_ = mask; - mute_voices_( mask ); -} - -void Music_Emu::set_tempo( double t ) -{ - require( sample_rate() ); // sample rate must be set first - double const min = 0.02; - double const max = 4.00; - if ( t < min ) t = min; - if ( t > max ) t = max; - tempo_ = t; - set_tempo_( t ); -} - -void Music_Emu::post_load_() -{ - set_tempo( tempo_ ); - remute_voices(); -} - -blargg_err_t Music_Emu::start_track( int track ) -{ - clear_track_vars(); - - int remapped = track; - RETURN_ERR( remap_track_( &remapped ) ); - current_track_ = track; - RETURN_ERR( start_track_( remapped ) ); - - emu_track_ended_ = false; - track_ended_ = false; - - if ( !ignore_silence_ ) - { - // play until non-silence or end of track - for ( long end = max_initial_silence * out_channels() * sample_rate(); emu_time < end; ) - { - fill_buf(); - if ( buf_remain | (int) emu_track_ended_ ) - break; - } - - emu_time = buf_remain; - out_time = 0; - silence_time = 0; - silence_count = 0; - } - return track_ended() ? warning() : 0; -} - -void Music_Emu::end_track_if_error( blargg_err_t err ) -{ - if ( err ) - { - emu_track_ended_ = true; - set_warning( err ); - } -} - -bool Music_Emu::autoload_playback_limit() const -{ - return emu_autoload_playback_limit_; -} - -void Music_Emu::set_autoload_playback_limit( bool do_autoload_limit ) -{ - emu_autoload_playback_limit_ = do_autoload_limit; -} - -// Tell/Seek - -blargg_long Music_Emu::msec_to_samples( blargg_long msec ) const -{ - blargg_long sec = msec / 1000; - msec -= sec * 1000; - return (sec * sample_rate() + msec * sample_rate() / 1000) * out_channels(); -} - -long Music_Emu::tell_samples() const -{ - return out_time; -} - -long Music_Emu::tell() const -{ - blargg_long rate = sample_rate() * out_channels(); - blargg_long sec = out_time / rate; - return sec * 1000 + (out_time - sec * rate) * 1000 / rate; -} - -blargg_err_t Music_Emu::seek_samples( long time ) -{ - if ( time < out_time ) - RETURN_ERR( start_track( current_track_ ) ); - return skip( time - out_time ); -} - -blargg_err_t Music_Emu::seek( long msec ) -{ - return seek_samples( msec_to_samples( msec ) ); -} - -blargg_err_t Music_Emu::skip( long count ) -{ - require( current_track() >= 0 ); // start_track() must have been called already - out_time += count; - - // remove from silence and buf first - { - long n = min( count, silence_count ); - silence_count -= n; - count -= n; - - n = min( count, buf_remain ); - buf_remain -= n; - count -= n; - } - - if ( count && !emu_track_ended_ ) - { - emu_time += count; - end_track_if_error( skip_( count ) ); - } - - if ( !(silence_count | buf_remain) ) // caught up to emulator, so update track ended - track_ended_ |= emu_track_ended_; - - return 0; -} - -blargg_err_t Music_Emu::skip_( long count ) -{ - // for long skip, mute sound - const long threshold = 30000; - if ( count > threshold ) - { - int saved_mute = mute_mask_; - mute_voices( ~0 ); - - while ( count > threshold / 2 && !emu_track_ended_ ) - { - RETURN_ERR( play_( buf_size, buf.begin() ) ); - count -= buf_size; - } - - mute_voices( saved_mute ); - } - - while ( count && !emu_track_ended_ ) - { - long n = buf_size; - if ( n > count ) - n = count; - count -= n; - RETURN_ERR( play_( n, buf.begin() ) ); - } - return 0; -} - -// Fading - -void Music_Emu::set_fade( long start_msec, long length_msec ) -{ - fade_step = sample_rate() * length_msec / (fade_block_size * fade_shift * 1000 / out_channels()); - fade_start = msec_to_samples( start_msec ); -} - -// unit / pow( 2.0, (double) x / step ) -static int int_log( blargg_long x, int step, int unit ) -{ - int shift = x / step; - int fraction = (x - shift * step) * unit / step; - return ((unit - fraction) + (fraction >> 1)) >> shift; -} - -void Music_Emu::handle_fade( long out_count, sample_t* out ) -{ - for ( int i = 0; i < out_count; i += fade_block_size ) - { - int const shift = 14; - int const unit = 1 << shift; - int gain = int_log( (out_time + i - fade_start) / fade_block_size, - fade_step, unit ); - if ( gain < (unit >> fade_shift) ) - track_ended_ = emu_track_ended_ = true; - - sample_t* io = &out [i]; - for ( int count = min( fade_block_size, out_count - i ); count; --count ) - { - *io = sample_t ((*io * gain) >> shift); - ++io; - } - } -} - -// Silence detection - -void Music_Emu::emu_play( long count, sample_t* out ) -{ - check( current_track_ >= 0 ); - emu_time += count; - if ( current_track_ >= 0 && !emu_track_ended_ ) - end_track_if_error( play_( count, out ) ); - else - memset( out, 0, count * sizeof *out ); -} - -// number of consecutive silent samples at end -static long count_silence( Music_Emu::sample_t* begin, long size ) -{ - Music_Emu::sample_t first = *begin; - *begin = silence_threshold; // sentinel - Music_Emu::sample_t* p = begin + size; - while ( (unsigned) (*--p + silence_threshold / 2) <= (unsigned) silence_threshold ) { } - *begin = first; - return size - (p - begin); -} - -// fill internal buffer and check it for silence -void Music_Emu::fill_buf() -{ - assert( !buf_remain ); - if ( !emu_track_ended_ ) - { - emu_play( buf_size, buf.begin() ); - long silence = count_silence( buf.begin(), buf_size ); - if ( silence < buf_size ) - { - silence_time = emu_time - silence; - buf_remain = buf_size; - return; - } - } - silence_count += buf_size; -} - -blargg_err_t Music_Emu::play( long out_count, sample_t* out ) -{ - if ( track_ended_ ) - { - memset( out, 0, out_count * sizeof *out ); - } - else - { - require( current_track() >= 0 ); - require( out_count % out_channels() == 0 ); - - assert( emu_time >= out_time ); - - // prints nifty graph of how far ahead we are when searching for silence - //debug_printf( "%*s \n", int ((emu_time - out_time) * 7 / sample_rate()), "*" ); - - long pos = 0; - if ( silence_count ) - { - // during a run of silence, run emulator at >=2x speed so it gets ahead - long ahead_time = silence_lookahead * (out_time + out_count - silence_time) + silence_time; - while ( emu_time < ahead_time && !(buf_remain | emu_track_ended_) ) - fill_buf(); - - // fill with silence - pos = min( silence_count, out_count ); - memset( out, 0, pos * sizeof *out ); - silence_count -= pos; - - if ( emu_time - silence_time > silence_max * out_channels() * sample_rate() ) - { - track_ended_ = emu_track_ended_ = true; - silence_count = 0; - buf_remain = 0; - } - } - - if ( buf_remain ) - { - // empty silence buf - long n = min( buf_remain, out_count - pos ); - memcpy( &out [pos], buf.begin() + (buf_size - buf_remain), n * sizeof *out ); - buf_remain -= n; - pos += n; - } - - // generate remaining samples normally - long remain = out_count - pos; - if ( remain ) - { - emu_play( remain, out + pos ); - track_ended_ |= emu_track_ended_; - - if ( !ignore_silence_ || out_time > fade_start ) - { - // check end for a new run of silence - long silence = count_silence( out + pos, remain ); - if ( silence < remain ) - silence_time = emu_time - silence; - - if ( emu_time - silence_time >= buf_size ) - fill_buf(); // cause silence detection on next play() - } - } - - if ( fade_start >= 0 && out_time > fade_start ) - handle_fade( out_count, out ); - } - out_time += out_count; - return 0; -} - -// Gme_Info_ - -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_::post_load_() { Gme_File::post_load_(); } // skip Music_Emu -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_::set_tempo_( double ) { } -blargg_err_t Gme_Info_::start_track_( int ) { return "Use full emulator for playback"; } -blargg_err_t Gme_Info_::play_( long, sample_t* ) { return "Use full emulator for playback"; } diff --git a/libraries/game-music-emu/gme/Music_Emu.h b/libraries/game-music-emu/gme/Music_Emu.h deleted file mode 100644 index 3aafa5ec1..000000000 --- a/libraries/game-music-emu/gme/Music_Emu.h +++ /dev/null @@ -1,252 +0,0 @@ -// Common interface to game music file emulators - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef MUSIC_EMU_H -#define MUSIC_EMU_H - -#include "Gme_File.h" -class Multi_Buffer; - -struct Music_Emu : public Gme_File { -public: -// Basic functionality (see Gme_File.h for file loading/track info functions) - - // Set output sample rate. Must be called only once before loading file. - blargg_err_t set_sample_rate( long sample_rate ); - - // specifies if all 8 voices get rendered to their own stereo channel - // default implementation of Music_Emu always returns not supported error (i.e. no multichannel support by default) - // derived emus must override this if they support multichannel rendering - virtual blargg_err_t set_multi_channel( bool is_enabled ); - - // Start a track, where 0 is the first track. Also clears warning string. - blargg_err_t start_track( int ); - - // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation - // errors set warning string, and major errors also end track. - typedef short sample_t; - blargg_err_t play( long count, sample_t* buf ); - -// Informational - - // Sample rate sound is generated at - long sample_rate() const; - - // Index of current track or -1 if one hasn't been started - int current_track() const; - - // Number of voices used by currently loaded file - int voice_count() const; - - // Names of voices - const char** voice_names() const; - - bool multi_channel() const; - -// Track status/control - - // Number of milliseconds (1000 msec = 1 second) played since beginning of track - long tell() const; - - // Number of samples generated since beginning of track - long tell_samples() const; - - // Seek to new time in track. Seeking backwards or far forward can take a while. - blargg_err_t seek( long msec ); - - // Equivalent to restarting track then skipping n samples - blargg_err_t seek_samples( long n ); - - // Skip n samples - blargg_err_t skip( long n ); - - // True if a track has reached its end - bool track_ended() const; - - // Set start time and length of track fade out. Once fade ends track_ended() returns - // true. Fade time can be changed while track is playing. - void set_fade( long start_msec, long length_msec = 8000 ); - - // Controls whether or not to automatically load and obey track length - // metadata for supported emulators. - // - // @since 0.6.2. - bool autoload_playback_limit() const; - void set_autoload_playback_limit( bool do_autoload_limit ); - - // Disable automatic end-of-track detection and skipping of silence at beginning - void ignore_silence( bool disable = true ); - - // Info for current track - using Gme_File::track_info; - blargg_err_t track_info( track_info_t* out ) const; - -// Sound customization - - // 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. - void set_tempo( double ); - - // Mute/unmute voice i, where voice 0 is first voice - void mute_voice( int index, bool mute = true ); - - // Set muting state of all voices at once using a bit mask, where -1 mutes them all, - // 0 unmutes them all, 0x01 mutes just the first voice, etc. - void mute_voices( int mask ); - - // Change overall output amplitude, where 1.0 results in minimal clamping. - // Must be called before set_sample_rate(). - void set_gain( double ); - - // Request use of custom multichannel buffer. Only supported by "classic" emulators; - // on others this has no effect. Should be called only once *before* set_sample_rate(). - 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) - - // Frequency equalizer parameters (see gme.txt) - // See gme.h for definition of struct gme_equalizer_t. - typedef gme_equalizer_t equalizer_t; - - // Current frequency equalizater parameters - equalizer_t const& equalizer() const; - - // Set frequency equalizer parameters - 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 - static equalizer_t const tv_eq; - -public: - Music_Emu(); - ~Music_Emu(); -protected: - void set_max_initial_silence( int n ) { max_initial_silence = n; } - void set_silence_lookahead( int n ) { silence_lookahead = n; } - void set_voice_count( int n ) { voice_count_ = n; } - void set_voice_names( const char* const* names ); - void set_track_ended() { emu_track_ended_ = true; } - double gain() const { return gain_; } - double tempo() const { return tempo_; } - void remute_voices(); - blargg_err_t set_multi_channel_( bool is_enabled ); - - virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0; - virtual void set_equalizer_( equalizer_t const& ) { } - virtual void enable_accuracy_( bool /* enable */ ) { } - virtual void mute_voices_( int mask ) = 0; - virtual void set_tempo_( double ) = 0; - virtual blargg_err_t start_track_( int ) = 0; // tempo is set before this - virtual blargg_err_t play_( long count, sample_t* out ) = 0; - virtual blargg_err_t skip_( long count ); -protected: - virtual void unload(); - virtual void pre_load(); - virtual void post_load_(); -private: - // general - equalizer_t equalizer_; - int max_initial_silence; - const char** voice_names_; - int voice_count_; - int mute_mask_; - double tempo_; - double gain_; - bool multi_channel_; - - // returns the number of output channels, i.e. usually 2 for stereo, unlesss multi_channel_ == true - int out_channels() const { return this->multi_channel() ? 2*8 : 2; } - - long sample_rate_; - blargg_long msec_to_samples( blargg_long msec ) const; - - // track-specific - int current_track_; - blargg_long out_time; // number of samples played since start of track - blargg_long emu_time; // number of samples emulator has generated since start of track - bool emu_track_ended_; // emulator has reached end of track - bool emu_autoload_playback_limit_; // whether to load and obey track length by default - volatile bool track_ended_; - void clear_track_vars(); - void end_track_if_error( blargg_err_t ); - - // fading - blargg_long fade_start; - int fade_step; - void handle_fade( long count, sample_t* out ); - - // silence detection - int silence_lookahead; // speed to run emulator when looking ahead for silence - bool ignore_silence_; - long silence_time; // number of samples where most recent silence began - long silence_count; // number of samples of silence to play before using buf - long buf_remain; // number of samples left in silence buffer - enum { buf_size = 2048 }; - blargg_vector buf; - void fill_buf(); - void emu_play( long count, sample_t* out ); - - Multi_Buffer* effects_buffer; - friend Music_Emu* gme_internal_new_emu_( gme_type_t, int, bool ); - friend void gme_set_stereo_depth( Music_Emu*, double ); -}; - -// base class for info-only derivations -struct Gme_Info_ : Music_Emu -{ - virtual blargg_err_t set_sample_rate_( long sample_rate ); - virtual void set_equalizer_( equalizer_t const& ); - virtual void enable_accuracy_( bool ); - virtual void mute_voices_( int mask ); - virtual void set_tempo_( double ); - virtual blargg_err_t start_track_( int ); - virtual blargg_err_t play_( long count, sample_t* out ); - virtual void pre_load(); - virtual void post_load_(); -}; - -inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const -{ - return track_info( out, current_track_ ); -} - -inline long Music_Emu::sample_rate() const { return sample_rate_; } -inline const char** Music_Emu::voice_names() const { return voice_names_; } -inline int Music_Emu::voice_count() const { return voice_count_; } -inline int Music_Emu::current_track() const { return current_track_; } -inline bool Music_Emu::track_ended() const { return track_ended_; } -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::remute_voices() { mute_voices( mute_mask_ ); } -inline void Music_Emu::ignore_silence( bool b ) { ignore_silence_ = b; } -inline blargg_err_t Music_Emu::start_track_( int ) { return 0; } - -inline void Music_Emu::set_voice_names( const char* const* names ) -{ - // Intentional removal of const, so users don't have to remember obscure const in middle - voice_names_ = const_cast (names); -} - -inline void Music_Emu::mute_voices_( int ) { } - -inline void Music_Emu::set_gain( double g ) -{ - assert( !sample_rate() ); // you must set gain before setting sample rate - gain_ = g; -} - -#endif diff --git a/libraries/game-music-emu/gme/Nes_Apu.cpp b/libraries/game-music-emu/gme/Nes_Apu.cpp deleted file mode 100644 index 68edb446d..000000000 --- a/libraries/game-music-emu/gme/Nes_Apu.cpp +++ /dev/null @@ -1,391 +0,0 @@ -// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/ - -#include "Nes_Apu.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -int const amp_range = 15; - -Nes_Apu::Nes_Apu() : - square1( &square_synth ), - square2( &square_synth ) -{ - tempo_ = 1.0; - dmc.apu = this; - dmc.prg_reader = NULL; - irq_notifier_ = NULL; - - oscs [0] = &square1; - oscs [1] = &square2; - oscs [2] = ▵ - oscs [3] = &noise; - oscs [4] = &dmc; - - output( NULL ); - volume( 1.0 ); - reset( false ); -} - -void Nes_Apu::treble_eq( const blip_eq_t& eq ) -{ - square_synth.treble_eq( eq ); - triangle.synth.treble_eq( eq ); - noise.synth.treble_eq( eq ); - dmc.synth.treble_eq( eq ); -} - -void Nes_Apu::enable_nonlinear( double v ) -{ - dmc.nonlinear = true; - square_synth.volume( 1.3 * 0.25751258 / 0.742467605 * 0.25 / amp_range * v ); - - const double tnd = 0.48 / 202 * nonlinear_tnd_gain(); - triangle.synth.volume( 3.0 * tnd ); - noise.synth.volume( 2.0 * tnd ); - dmc.synth.volume( tnd ); - - square1 .last_amp = 0; - square2 .last_amp = 0; - triangle.last_amp = 0; - noise .last_amp = 0; - dmc .last_amp = 0; -} - -void Nes_Apu::volume( double v ) -{ - dmc.nonlinear = false; - square_synth.volume( 0.1128 / amp_range * v ); - triangle.synth.volume( 0.12765 / amp_range * v ); - noise.synth.volume( 0.0741 / amp_range * v ); - dmc.synth.volume( 0.42545 / 127 * v ); -} - -void Nes_Apu::output( Blip_Buffer* buffer ) -{ - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, buffer ); -} - -void Nes_Apu::set_tempo( double t ) -{ - tempo_ = t; - frame_period = (dmc.pal_mode ? 8314 : 7458); - if ( t != 1.0 ) - frame_period = (int) (frame_period / t) & ~1; // must be even -} - -void Nes_Apu::reset( bool pal_mode, int initial_dmc_dac ) -{ - dmc.pal_mode = pal_mode; - set_tempo( tempo_ ); - - square1.reset(); - square2.reset(); - triangle.reset(); - noise.reset(); - dmc.reset(); - - last_time = 0; - last_dmc_time = 0; - osc_enables = 0; - irq_flag = false; - earliest_irq_ = no_irq; - frame_delay = 1; - write_register( 0, 0x4017, 0x00 ); - write_register( 0, 0x4015, 0x00 ); - - for ( nes_addr_t addr = start_addr; addr <= 0x4013; addr++ ) - write_register( 0, addr, (addr & 3) ? 0x00 : 0x10 ); - - dmc.dac = initial_dmc_dac; - if ( !dmc.nonlinear ) - triangle.last_amp = 15; - if ( !dmc.nonlinear ) // TODO: remove? - dmc.last_amp = initial_dmc_dac; // prevent output transition -} - -void Nes_Apu::irq_changed() -{ - nes_time_t new_irq = dmc.next_irq; - if ( dmc.irq_flag | irq_flag ) { - new_irq = 0; - } - else if ( new_irq > next_irq ) { - new_irq = next_irq; - } - - if ( new_irq != earliest_irq_ ) { - earliest_irq_ = new_irq; - if ( irq_notifier_ ) - irq_notifier_( irq_data ); - } -} - -// frames - -void Nes_Apu::run_until( nes_time_t end_time ) -{ - require( end_time >= last_dmc_time ); - if ( end_time > next_dmc_read_time() ) - { - nes_time_t start = last_dmc_time; - last_dmc_time = end_time; - dmc.run( start, end_time ); - } -} - -void Nes_Apu::run_until_( nes_time_t end_time ) -{ - require( end_time >= last_time ); - - if ( end_time == last_time ) - return; - - if ( last_dmc_time < end_time ) - { - nes_time_t start = last_dmc_time; - last_dmc_time = end_time; - dmc.run( start, end_time ); - } - - while ( true ) - { - // earlier of next frame time or end time - nes_time_t time = last_time + frame_delay; - if ( time > end_time ) - time = end_time; - frame_delay -= time - last_time; - - // run oscs to present - square1.run( last_time, time ); - square2.run( last_time, time ); - triangle.run( last_time, time ); - noise.run( last_time, time ); - last_time = time; - - if ( time == end_time ) - break; // no more frames to run - - // take frame-specific actions - frame_delay = frame_period; - switch ( frame++ ) - { - case 0: - if ( !(frame_mode & 0xC0) ) { - next_irq = time + frame_period * 4 + 2; - irq_flag = true; - } - // fall through - case 2: - // clock length and sweep on frames 0 and 2 - square1.clock_length( 0x20 ); - square2.clock_length( 0x20 ); - noise.clock_length( 0x20 ); - triangle.clock_length( 0x80 ); // different bit for halt flag on triangle - - square1.clock_sweep( -1 ); - square2.clock_sweep( 0 ); - - // frame 2 is slightly shorter in mode 1 - if ( dmc.pal_mode && frame == 3 ) - frame_delay -= 2; - break; - - case 1: - // frame 1 is slightly shorter in mode 0 - if ( !dmc.pal_mode ) - frame_delay -= 2; - break; - - case 3: - frame = 0; - - // frame 3 is almost twice as long in mode 1 - if ( frame_mode & 0x80 ) - frame_delay += frame_period - (dmc.pal_mode ? 2 : 6); - break; - } - - // clock envelopes and linear counter every frame - triangle.clock_linear_counter(); - square1.clock_envelope(); - square2.clock_envelope(); - noise.clock_envelope(); - } -} - -template -inline void zero_apu_osc( T* osc, nes_time_t time ) -{ - Blip_Buffer* output = osc->output; - int last_amp = osc->last_amp; - osc->last_amp = 0; - if ( output && last_amp ) - osc->synth.offset( time, -last_amp, output ); -} - -void Nes_Apu::end_frame( nes_time_t end_time ) -{ - if ( end_time > last_time ) - run_until_( end_time ); - - if ( dmc.nonlinear ) - { - zero_apu_osc( &square1, last_time ); - zero_apu_osc( &square2, last_time ); - zero_apu_osc( &triangle, last_time ); - zero_apu_osc( &noise, last_time ); - zero_apu_osc( &dmc, last_time ); - } - - // make times relative to new frame - last_time -= end_time; - require( last_time >= 0 ); - - last_dmc_time -= end_time; - require( last_dmc_time >= 0 ); - - if ( next_irq != no_irq ) { - next_irq -= end_time; - check( next_irq >= 0 ); - } - if ( dmc.next_irq != no_irq ) { - dmc.next_irq -= end_time; - check( dmc.next_irq >= 0 ); - } - if ( earliest_irq_ != no_irq ) { - earliest_irq_ -= end_time; - if ( earliest_irq_ < 0 ) - earliest_irq_ = 0; - } -} - -// registers - -static const unsigned char length_table [0x20] = { - 0x0A, 0xFE, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, - 0xA0, 0x08, 0x3C, 0x0A, 0x0E, 0x0C, 0x1A, 0x0E, - 0x0C, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, - 0xC0, 0x18, 0x48, 0x1A, 0x10, 0x1C, 0x20, 0x1E -}; - -void Nes_Apu::write_register( nes_time_t time, nes_addr_t addr, int data ) -{ - require( addr > 0x20 ); // addr must be actual address (i.e. 0x40xx) - require( (unsigned) data <= 0xFF ); - - // Ignore addresses outside range - if ( unsigned (addr - start_addr) > end_addr - start_addr ) - return; - - run_until_( time ); - - if ( addr < 0x4014 ) - { - // Write to channel - int osc_index = (addr - start_addr) >> 2; - Nes_Osc* osc = oscs [osc_index]; - - int reg = addr & 3; - osc->regs [reg] = data; - osc->reg_written [reg] = true; - - if ( osc_index == 4 ) - { - // handle DMC specially - dmc.write_register( reg, data ); - } - else if ( reg == 3 ) - { - // load length counter - if ( (osc_enables >> osc_index) & 1 ) - osc->length_counter = length_table [(data >> 3) & 0x1F]; - - // reset square phase - if ( osc_index < 2 ) - ((Nes_Square*) osc)->phase = Nes_Square::phase_range - 1; - } - } - else if ( addr == 0x4015 ) - { - // Channel enables - for ( int i = osc_count; i--; ) - if ( !((data >> i) & 1) ) - oscs [i]->length_counter = 0; - - bool recalc_irq = dmc.irq_flag; - dmc.irq_flag = false; - - int old_enables = osc_enables; - osc_enables = data; - if ( !(data & 0x10) ) { - dmc.next_irq = no_irq; - recalc_irq = true; - } - else if ( !(old_enables & 0x10) ) { - dmc.start(); // dmc just enabled - } - - if ( recalc_irq ) - irq_changed(); - } - else if ( addr == 0x4017 ) - { - // Frame mode - frame_mode = data; - - bool irq_enabled = !(data & 0x40); - irq_flag &= irq_enabled; - next_irq = no_irq; - - // mode 1 - frame_delay = (frame_delay & 1); - frame = 0; - - if ( !(data & 0x80) ) - { - // mode 0 - frame = 1; - frame_delay += frame_period; - if ( irq_enabled ) - next_irq = time + frame_delay + frame_period * 3 + 1; - } - - irq_changed(); - } -} - -int Nes_Apu::read_status( nes_time_t time ) -{ - run_until_( time - 1 ); - - int result = (dmc.irq_flag << 7) | (irq_flag << 6); - - for ( int i = 0; i < osc_count; i++ ) - if ( oscs [i]->length_counter ) - result |= 1 << i; - - run_until_( time ); - - if ( irq_flag ) - { - result |= 0x40; - irq_flag = false; - irq_changed(); - } - - //debug_printf( "%6d/%d Read $4015->$%02X\n", frame_delay, frame, result ); - - return result; -} diff --git a/libraries/game-music-emu/gme/Nes_Apu.h b/libraries/game-music-emu/gme/Nes_Apu.h deleted file mode 100644 index 5e722248f..000000000 --- a/libraries/game-music-emu/gme/Nes_Apu.h +++ /dev/null @@ -1,179 +0,0 @@ -// NES 2A03 APU sound chip emulator - -// Nes_Snd_Emu 0.1.8 -#ifndef NES_APU_H -#define NES_APU_H - -#include "blargg_common.h" - -typedef blargg_long nes_time_t; // CPU clock cycle count -typedef unsigned nes_addr_t; // 16-bit memory address - -#include "Nes_Oscs.h" - -struct apu_state_t; -class Nes_Buffer; - -class Nes_Apu { -public: - // Set buffer to generate all sound into, or disable sound if NULL - void output( Blip_Buffer* ); - - // Set memory reader callback used by DMC oscillator to fetch samples. - // When callback is invoked, 'user_data' is passed unchanged as the - // first parameter. - void dmc_reader( int (*callback)( void* user_data, nes_addr_t ), void* user_data = NULL ); - - // All time values are the number of CPU clock cycles relative to the - // beginning of the current time frame. Before resetting the CPU clock - // count, call end_frame( last_cpu_time ). - - // Write to register (0x4000-0x4017, except 0x4014 and 0x4016) - enum { start_addr = 0x4000 }; - enum { end_addr = 0x4017 }; - void write_register( nes_time_t, nes_addr_t, int data ); - - // Read from status register at 0x4015 - enum { status_addr = 0x4015 }; - int read_status( nes_time_t ); - - // Run all oscillators up to specified time, end current time frame, then - // start a new time frame at time 0. Time frames have no effect on emulation - // and each can be whatever length is convenient. - void end_frame( nes_time_t ); - -// Additional optional features (can be ignored without any problem) - - // Reset internal frame counter, registers, and all oscillators. - // Use PAL timing if pal_timing is true, otherwise use NTSC timing. - // Set the DMC oscillator's initial DAC value to initial_dmc_dac without - // any audible click. - void reset( bool pal_mode = false, int initial_dmc_dac = 0 ); - - // Adjust frame period - void set_tempo( double ); - - // Save/load exact emulation state - void save_state( apu_state_t* out ) const; - void load_state( apu_state_t const& ); - - // Set overall volume (default is 1.0) - void volume( double ); - - // Set treble equalization (see notes.txt) - void treble_eq( const blip_eq_t& ); - - // Set sound output of specific oscillator to buffer. If buffer is NULL, - // the specified oscillator is muted and emulation accuracy is reduced. - // The oscillators are indexed as follows: 0) Square 1, 1) Square 2, - // 2) Triangle, 3) Noise, 4) DMC. - enum { osc_count = 5 }; - void osc_output( int index, Blip_Buffer* buffer ); - - // Set IRQ time callback that is invoked when the time of earliest IRQ - // may have changed, or NULL to disable. When callback is invoked, - // 'user_data' is passed unchanged as the first parameter. - void irq_notifier( void (*callback)( void* user_data ), void* user_data = NULL ); - - // Get time that APU-generated IRQ will occur if no further register reads - // or writes occur. If IRQ is already pending, returns irq_waiting. If no - // IRQ will occur, returns no_irq. - enum { no_irq = INT_MAX / 2 + 1 }; - enum { irq_waiting = 0 }; - nes_time_t earliest_irq( nes_time_t ) const; - - // Count number of DMC reads that would occur if 'run_until( t )' were executed. - // If last_read is not NULL, set *last_read to the earliest time that - // 'count_dmc_reads( time )' would result in the same result. - int count_dmc_reads( nes_time_t t, nes_time_t* last_read = NULL ) const; - - // Time when next DMC memory read will occur - nes_time_t next_dmc_read_time() const; - - // Run DMC until specified time, so that any DMC memory reads can be - // accounted for (i.e. inserting CPU wait states). - void run_until( nes_time_t ); - -public: - Nes_Apu(); - BLARGG_DISABLE_NOTHROW -private: - friend class Nes_Nonlinearizer; - void enable_nonlinear( double volume ); - static double nonlinear_tnd_gain() { return 0.75; } -private: - friend struct Nes_Dmc; - - // noncopyable - Nes_Apu( const Nes_Apu& ); - Nes_Apu& operator = ( const Nes_Apu& ); - - Nes_Osc* oscs [osc_count]; - Nes_Square square1; - Nes_Square square2; - Nes_Noise noise; - Nes_Triangle triangle; - Nes_Dmc dmc; - - double tempo_; - nes_time_t last_time; // has been run until this time in current frame - nes_time_t last_dmc_time; - nes_time_t earliest_irq_; - nes_time_t next_irq; - int frame_period; - int frame_delay; // cycles until frame counter runs next - int frame; // current frame (0-3) - int osc_enables; - int frame_mode; - bool irq_flag; - void (*irq_notifier_)( void* user_data ); - void* irq_data; - Nes_Square::Synth square_synth; // shared by squares - - void irq_changed(); - void state_restored(); - void run_until_( nes_time_t ); - - // TODO: remove - friend class Nes_Core; -}; - -inline void Nes_Apu::osc_output( int osc, Blip_Buffer* buf ) -{ - assert( (unsigned) osc < osc_count ); - oscs [osc]->output = buf; -} - -inline nes_time_t Nes_Apu::earliest_irq( nes_time_t ) const -{ - return earliest_irq_; -} - -inline void Nes_Apu::dmc_reader( int (*func)( void*, nes_addr_t ), void* user_data ) -{ - dmc.prg_reader_data = user_data; - dmc.prg_reader = func; -} - -inline void Nes_Apu::irq_notifier( void (*func)( void* user_data ), void* user_data ) -{ - irq_notifier_ = func; - irq_data = user_data; -} - -inline int Nes_Apu::count_dmc_reads( nes_time_t time, nes_time_t* last_read ) const -{ - return dmc.count_reads( time, last_read ); -} - -inline nes_time_t Nes_Dmc::next_read_time() const -{ - if ( length_counter == 0 ) - return Nes_Apu::no_irq; // not reading - - return apu->last_dmc_time + delay + long (bits_remain - 1) * period; -} - -inline nes_time_t Nes_Apu::next_dmc_read_time() const { return dmc.next_read_time(); } - -#endif diff --git a/libraries/game-music-emu/gme/Nes_Cpu.cpp b/libraries/game-music-emu/gme/Nes_Cpu.cpp deleted file mode 100644 index 5eb0862a3..000000000 --- a/libraries/game-music-emu/gme/Nes_Cpu.cpp +++ /dev/null @@ -1,1073 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Nes_Cpu.h" - -#include "blargg_endian.h" -#include - -#define BLARGG_CPU_X86 1 - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -#define FLUSH_TIME() (void) (s.time = s_time) -#define CACHE_TIME() (void) (s_time = s.time) - -#include "nes_cpu_io.h" - -#include "blargg_source.h" - -#ifndef CPU_DONE - #define CPU_DONE( cpu, time, result_out ) { result_out = -1; } -#endif - -#ifndef CPU_READ_PPU - #define CPU_READ_PPU( cpu, addr, out, time )\ - {\ - FLUSH_TIME();\ - out = CPU_READ( cpu, addr, time );\ - CACHE_TIME();\ - } -#endif - -#if BLARGG_NONPORTABLE - #define PAGE_OFFSET( addr ) (addr) -#else - #define PAGE_OFFSET( addr ) ((addr) & (page_size - 1)) -#endif - -inline void Nes_Cpu::set_code_page( int i, void const* p ) -{ - state->code_map [i] = (uint8_t const*) p - PAGE_OFFSET( i * page_size ); -} - -int const st_n = 0x80; -int const st_v = 0x40; -int const st_r = 0x20; -int const st_b = 0x10; -int const st_d = 0x08; -int const st_i = 0x04; -int const st_z = 0x02; -int const st_c = 0x01; - -void Nes_Cpu::reset( void const* unmapped_page ) -{ - check( state == &state_ ); - state = &state_; - r.status = st_i; - r.sp = 0xFF; - r.pc = 0; - r.a = 0; - r.x = 0; - r.y = 0; - state_.time = 0; - state_.base = 0; - irq_time_ = future_nes_time; - end_time_ = future_nes_time; - error_count_ = 0; - - assert( page_size == 0x800 ); // assumes this - set_code_page( page_count, unmapped_page ); - map_code( 0x2000, 0xE000, unmapped_page, true ); - map_code( 0x0000, 0x2000, low_mem, true ); - - blargg_verify_byte_order(); -} - -void Nes_Cpu::map_code( nes_addr_t start, unsigned size, void const* data, bool mirror ) -{ - // address range must begin and end on page boundaries - require( start % page_size == 0 ); - require( size % page_size == 0 ); - require( start + size <= 0x10000 ); - - unsigned page = start / page_size; - for ( unsigned n = size / page_size; n; --n ) - { - set_code_page( page++, data ); - if ( !mirror ) - data = (char const*) data + page_size; - } -} - -#define TIME (s_time + s.base) -#define READ_LIKELY_PPU( addr, out ) {CPU_READ_PPU( this, (addr), out, TIME );} -#define READ( addr ) CPU_READ( this, (addr), TIME ) -#define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), TIME );} -#define READ_LOW( addr ) (low_mem [int (addr)]) -#define WRITE_LOW( addr, data ) (void) (READ_LOW( addr ) = (data)) -#define READ_PROG( addr ) (s.code_map [(addr) >> page_bits] [PAGE_OFFSET( addr )]) - -#define SET_SP( v ) (sp = ((v) + 1) | 0x100) -#define GET_SP() ((sp - 1) & 0xFF) -#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v )) - -bool Nes_Cpu::run( nes_time_t end_time ) -{ - set_end_time( end_time ); - state_t s = this->state_; - this->state = &s; - // even on x86, using s.time in place of s_time was slower - int16_t s_time = s.time; - - // registers - uint16_t pc = r.pc; - uint8_t a = r.a; - uint8_t x = r.x; - uint8_t y = r.y; - uint16_t sp; - SET_SP( r.sp ); - - // status flags - #define IS_NEG (nz & 0x8080) - - #define CALC_STATUS( out ) do {\ - out = status & (st_v | st_d | st_i);\ - out |= ((nz >> 8) | nz) & st_n;\ - out |= c >> 8 & st_c;\ - if ( !(nz & 0xFF) ) out |= st_z;\ - } while ( 0 ) - - #define SET_STATUS( in ) do {\ - status = in & (st_v | st_d | st_i);\ - nz = in << 8;\ - c = nz;\ - nz |= ~in & st_z;\ - } while ( 0 ) - - uint8_t status; - uint16_t c; // carry set if (c & 0x100) != 0 - uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 - { - uint8_t temp = r.status; - SET_STATUS( temp ); - } - - goto loop; -dec_clock_loop: - s_time--; -loop: - - check( (unsigned) GET_SP() < 0x100 ); - check( (unsigned) pc < 0x10000 ); - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - check( -32768 <= s_time && s_time < 32767 ); - - uint8_t const* instr = s.code_map [pc >> page_bits]; - uint8_t opcode; - - // TODO: eliminate this special case - #if BLARGG_NONPORTABLE - opcode = instr [pc]; - pc++; - instr += pc; - #else - instr += PAGE_OFFSET( pc ); - opcode = *instr++; - pc++; - #endif - - static uint8_t const clock_table [256] = - {// 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 - 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 - 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 - 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 - 3,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A - 3,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E - 3,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 // F - }; // 0x00 was 7 and 0xF2 was 2 - - uint16_t data; - -#if !BLARGG_CPU_X86 - if ( s_time >= 0 ) - goto out_of_time; - s_time += clock_table [opcode]; - - data = *instr; - - switch ( opcode ) - { -#else - - data = clock_table [opcode]; - if ( (s_time += data) >= 0 ) - goto possibly_out_of_time; -almost_out_of_time: - - data = *instr; - - switch ( opcode ) - { -possibly_out_of_time: - if ( s_time < (int) data ) - goto almost_out_of_time; - s_time -= data; - goto out_of_time; -#endif - -// Macros - -#define GET_MSB() (instr [1]) -#define ADD_PAGE() (pc++, data += 0x100 * GET_MSB()) -#define GET_ADDR() GET_LE16( instr ) - -#define NO_PAGE_CROSSING( lsb ) -#define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8; - -#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; - -#define IND_Y( cross, out ) {\ - uint16_t temp = READ_LOW( data ) + y;\ - out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\ - cross( temp );\ - } - -#define IND_X( out ) {\ - uint16_t temp = data + x;\ - out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\ - } - -#define ARITH_ADDR_MODES( op )\ -case op - 0x04: /* (ind,x) */\ - IND_X( data )\ - goto ptr##op;\ -case op + 0x0C: /* (ind),y */\ - IND_Y( HANDLE_PAGE_CROSSING, data )\ - goto ptr##op;\ -case op + 0x10: /* zp,X */\ - data = uint8_t (data + x);\ -case op + 0x00: /* zp */\ - data = READ_LOW( data );\ - goto imm##op;\ -case op + 0x14: /* abs,Y */\ - data += y;\ - goto ind##op;\ -case op + 0x18: /* abs,X */\ - data += x;\ -ind##op:\ - HANDLE_PAGE_CROSSING( data );\ -case op + 0x08: /* abs */\ - ADD_PAGE();\ -ptr##op:\ - FLUSH_TIME();\ - data = READ( data );\ - CACHE_TIME();\ -case op + 0x04: /* imm */\ -imm##op: - -// TODO: more efficient way to handle negative branch that wraps PC around -#define BRANCH( cond )\ -{\ - int16_t offset = (int8_t) data;\ - uint16_t extra_clock = (++pc & 0xFF) + offset;\ - if ( !(cond) ) goto dec_clock_loop;\ - pc = uint16_t (pc + offset);\ - s_time += extra_clock >> 8 & 1;\ - goto loop;\ -} - -// Often-Used - - case 0xB5: // LDA zp,x - a = nz = READ_LOW( uint8_t (data + x) ); - pc++; - goto loop; - - case 0xA5: // LDA zp - a = nz = READ_LOW( data ); - pc++; - goto loop; - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ); - - case 0x20: { // JSR - uint16_t temp = pc + 1; - pc = GET_ADDR(); - WRITE_LOW( 0x100 | (sp - 1), temp >> 8 ); - sp = (sp - 2) | 0x100; - WRITE_LOW( sp, temp ); - goto loop; - } - - case 0x4C: // JMP abs - pc = GET_ADDR(); - goto loop; - - case 0xE8: // INX - INC_DEC_XY( x, 1 ) - - case 0x10: // BPL - BRANCH( !IS_NEG ) - - ARITH_ADDR_MODES( 0xC5 ) // CMP - nz = a - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x30: // BMI - BRANCH( IS_NEG ) - - case 0xF0: // BEQ - BRANCH( !(uint8_t) nz ); - - case 0x95: // STA zp,x - data = uint8_t (data + x); - case 0x85: // STA zp - pc++; - WRITE_LOW( data, a ); - goto loop; - - case 0xC8: // INY - INC_DEC_XY( y, 1 ) - - case 0xA8: // TAY - y = a; - nz = a; - goto loop; - - case 0x98: // TYA - a = y; - nz = y; - goto loop; - - case 0xAD:{// LDA abs - unsigned addr = GET_ADDR(); - pc += 2; - READ_LIKELY_PPU( addr, nz ); - a = nz; - goto loop; - } - - case 0x60: // RTS - pc = 1 + READ_LOW( sp ); - pc += 0x100 * READ_LOW( 0x100 | (sp - 0xFF) ); - sp = (sp - 0xFE) | 0x100; - goto loop; - - { - uint16_t addr; - - case 0x99: // STA abs,Y - addr = y + GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, a ); - goto loop; - } - goto sta_ptr; - - case 0x8D: // STA abs - addr = GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, a ); - goto loop; - } - goto sta_ptr; - - case 0x9D: // STA abs,X (slightly more common than STA abs) - addr = x + GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, a ); - goto loop; - } - sta_ptr: - FLUSH_TIME(); - WRITE( addr, a ); - CACHE_TIME(); - goto loop; - - case 0x91: // STA (ind),Y - IND_Y( NO_PAGE_CROSSING, addr ) - pc++; - goto sta_ptr; - - case 0x81: // STA (ind,X) - IND_X( addr ) - pc++; - goto sta_ptr; - - } - - case 0xA9: // LDA #imm - pc++; - a = data; - nz = data; - goto loop; - - // common read instructions - { - uint16_t addr; - - case 0xA1: // LDA (ind,X) - IND_X( addr ) - pc++; - goto a_nz_read_addr; - - case 0xB1:// LDA (ind),Y - addr = READ_LOW( data ) + y; - HANDLE_PAGE_CROSSING( addr ); - addr += 0x100 * READ_LOW( (uint8_t) (data + 1) ); - pc++; - a = nz = READ_PROG( addr ); - if ( (addr ^ 0x8000) <= 0x9FFF ) - goto loop; - goto a_nz_read_addr; - - case 0xB9: // LDA abs,Y - HANDLE_PAGE_CROSSING( data + y ); - addr = GET_ADDR() + y; - pc += 2; - a = nz = READ_PROG( addr ); - if ( (addr ^ 0x8000) <= 0x9FFF ) - goto loop; - goto a_nz_read_addr; - - case 0xBD: // LDA abs,X - HANDLE_PAGE_CROSSING( data + x ); - addr = GET_ADDR() + x; - pc += 2; - a = nz = READ_PROG( addr ); - if ( (addr ^ 0x8000) <= 0x9FFF ) - goto loop; - a_nz_read_addr: - FLUSH_TIME(); - a = nz = READ( addr ); - CACHE_TIME(); - goto loop; - - } - -// Branch - - case 0x50: // BVC - BRANCH( !(status & st_v) ) - - case 0x70: // BVS - BRANCH( status & st_v ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - -// Load/store - - case 0x94: // STY zp,x - data = uint8_t (data + x); - case 0x84: // STY zp - pc++; - WRITE_LOW( data, y ); - goto loop; - - case 0x96: // STX zp,y - data = uint8_t (data + y); - case 0x86: // STX zp - pc++; - WRITE_LOW( data, x ); - goto loop; - - case 0xB6: // LDX zp,y - data = uint8_t (data + y); - case 0xA6: // LDX zp - data = READ_LOW( data ); - case 0xA2: // LDX #imm - pc++; - x = data; - nz = data; - goto loop; - - case 0xB4: // LDY zp,x - data = uint8_t (data + x); - case 0xA4: // LDY zp - data = READ_LOW( data ); - case 0xA0: // LDY #imm - pc++; - y = data; - nz = data; - goto loop; - - case 0xBC: // LDY abs,X - data += x; - HANDLE_PAGE_CROSSING( data ); - case 0xAC:{// LDY abs - unsigned addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - y = nz = READ( addr ); - CACHE_TIME(); - goto loop; - } - - case 0xBE: // LDX abs,y - data += y; - HANDLE_PAGE_CROSSING( data ); - case 0xAE:{// LDX abs - unsigned addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - x = nz = READ( addr ); - CACHE_TIME(); - goto loop; - } - - { - uint8_t temp; - case 0x8C: // STY abs - temp = y; - goto store_abs; - - case 0x8E: // STX abs - temp = x; - store_abs: - unsigned addr = GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, temp ); - goto loop; - } - FLUSH_TIME(); - WRITE( addr, temp ); - CACHE_TIME(); - goto loop; - } - -// Compare - - case 0xEC:{// CPX abs - unsigned addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ( addr ); - CACHE_TIME(); - goto cpx_data; - } - - case 0xE4: // CPX zp - data = READ_LOW( data ); - case 0xE0: // CPX #imm - cpx_data: - nz = x - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0xCC:{// CPY abs - unsigned addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ( addr ); - CACHE_TIME(); - goto cpy_data; - } - - case 0xC4: // CPY zp - data = READ_LOW( data ); - case 0xC0: // CPY #imm - cpy_data: - nz = y - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - -// Logical - - ARITH_ADDR_MODES( 0x25 ) // AND - nz = (a &= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x45 ) // EOR - nz = (a ^= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x05 ) // ORA - nz = (a |= data); - pc++; - goto loop; - - case 0x2C:{// BIT abs - unsigned addr = GET_ADDR(); - pc += 2; - status &= ~st_v; - READ_LIKELY_PPU( addr, nz ); - status |= nz & st_v; - if ( a & nz ) - goto loop; - nz <<= 8; // result must be zero, even if N bit is set - goto loop; - } - - case 0x24: // BIT zp - nz = READ_LOW( data ); - pc++; - status &= ~st_v; - status |= nz & st_v; - if ( a & nz ) - goto loop; - nz <<= 8; // result must be zero, even if N bit is set - goto loop; - -// Add/subtract - - ARITH_ADDR_MODES( 0xE5 ) // SBC - case 0xEB: // unofficial equivalent - data ^= 0xFF; - goto adc_imm; - - ARITH_ADDR_MODES( 0x65 ) // ADC - adc_imm: { - int16_t carry = c >> 8 & 1; - int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend - status &= ~st_v; - status |= ov >> 2 & 0x40; - c = nz = a + data + carry; - pc++; - a = (uint8_t) nz; - goto loop; - } - -// Shift/rotate - - case 0x4A: // LSR A - c = 0; - case 0x6A: // ROR A - nz = c >> 1 & 0x80; - c = a << 8; - nz |= a >> 1; - a = nz; - goto loop; - - case 0x0A: // ASL A - nz = a << 1; - c = nz; - a = (uint8_t) nz; - goto loop; - - case 0x2A: { // ROL A - nz = a << 1; - int16_t temp = c >> 8 & 1; - c = nz; - nz |= temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x5E: // LSR abs,X - data += x; - case 0x4E: // LSR abs - c = 0; - case 0x6E: // ROR abs - ror_abs: { - ADD_PAGE(); - FLUSH_TIME(); - int temp = READ( data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - goto rotate_common; - } - - case 0x3E: // ROL abs,X - data += x; - goto rol_abs; - - case 0x1E: // ASL abs,X - data += x; - case 0x0E: // ASL abs - c = 0; - case 0x2E: // ROL abs - rol_abs: - ADD_PAGE(); - nz = c >> 8 & 1; - FLUSH_TIME(); - nz |= (c = READ( data ) << 1); - rotate_common: - pc++; - WRITE( data, (uint8_t) nz ); - CACHE_TIME(); - goto loop; - - case 0x7E: // ROR abs,X - data += x; - goto ror_abs; - - case 0x76: // ROR zp,x - data = uint8_t (data + x); - goto ror_zp; - - case 0x56: // LSR zp,x - data = uint8_t (data + x); - case 0x46: // LSR zp - c = 0; - case 0x66: // ROR zp - ror_zp: { - int temp = READ_LOW( data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - goto write_nz_zp; - } - - case 0x36: // ROL zp,x - data = uint8_t (data + x); - goto rol_zp; - - case 0x16: // ASL zp,x - data = uint8_t (data + x); - case 0x06: // ASL zp - c = 0; - case 0x26: // ROL zp - rol_zp: - nz = c >> 8 & 1; - nz |= (c = READ_LOW( data ) << 1); - goto write_nz_zp; - -// Increment/decrement - - case 0xCA: // DEX - INC_DEC_XY( x, -1 ) - - case 0x88: // DEY - INC_DEC_XY( y, -1 ) - - case 0xF6: // INC zp,x - data = uint8_t (data + x); - case 0xE6: // INC zp - nz = 1; - goto add_nz_zp; - - case 0xD6: // DEC zp,x - data = uint8_t (data + x); - case 0xC6: // DEC zp - nz = (uint16_t) -1; - add_nz_zp: - nz += READ_LOW( data ); - write_nz_zp: - pc++; - WRITE_LOW( data, nz ); - goto loop; - - case 0xFE: // INC abs,x - data = x + GET_ADDR(); - goto inc_ptr; - - case 0xEE: // INC abs - data = GET_ADDR(); - inc_ptr: - nz = 1; - goto inc_common; - - case 0xDE: // DEC abs,x - data = x + GET_ADDR(); - goto dec_ptr; - - case 0xCE: // DEC abs - data = GET_ADDR(); - dec_ptr: - nz = (uint16_t) -1; - inc_common: - FLUSH_TIME(); - nz += READ( data ); - pc += 2; - WRITE( data, (uint8_t) nz ); - CACHE_TIME(); - goto loop; - -// Transfer - - case 0xAA: // TAX - x = a; - nz = a; - goto loop; - - case 0x8A: // TXA - a = x; - nz = x; - goto loop; - - case 0x9A: // TXS - SET_SP( x ); // verified (no flag change) - goto loop; - - case 0xBA: // TSX - x = nz = GET_SP(); - goto loop; - -// Stack - - case 0x48: // PHA - PUSH( a ); // verified - goto loop; - - case 0x68: // PLA - a = nz = READ_LOW( sp ); - sp = (sp - 0xFF) | 0x100; - goto loop; - - case 0x40:{// RTI - uint8_t temp = READ_LOW( sp ); - pc = READ_LOW( 0x100 | (sp - 0xFF) ); - pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100; - sp = (sp - 0xFD) | 0x100; - data = status; - SET_STATUS( temp ); - if ( !((data ^ status) & st_i) ) goto loop; // I flag didn't change - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - irq_time_; - if ( delta <= 0 ) goto loop; - if ( status & st_i ) goto loop; - s_time += delta; - s.base = irq_time_; - goto loop; - } - - case 0x28:{// PLP - uint8_t temp = READ_LOW( sp ); - sp = (sp - 0xFF) | 0x100; - uint8_t changed = status ^ temp; - SET_STATUS( temp ); - if ( !(changed & st_i) ) - goto loop; // I flag didn't change - if ( status & st_i ) - goto handle_sei; - goto handle_cli; - } - - case 0x08: { // PHP - uint8_t temp; - CALC_STATUS( temp ); - PUSH( temp | (st_b | st_r) ); - goto loop; - } - - case 0x6C:{// JMP (ind) - data = GET_ADDR(); - check( unsigned (data - 0x2000) >= 0x4000 ); // ensure it's outside I/O space - uint8_t const* page = s.code_map [data >> page_bits]; - pc = page [PAGE_OFFSET( data )]; - data = (data & 0xFF00) | ((data + 1) & 0xFF); - pc |= page [PAGE_OFFSET( data )] << 8; - goto loop; - } - - case 0x00: // BRK - goto handle_brk; - -// Flags - - case 0x38: // SEC - c = (uint16_t) ~0; - goto loop; - - case 0x18: // CLC - c = 0; - goto loop; - - case 0xB8: // CLV - status &= ~st_v; - goto loop; - - case 0xD8: // CLD - status &= ~st_d; - goto loop; - - case 0xF8: // SED - status |= st_d; - goto loop; - - case 0x58: // CLI - if ( !(status & st_i) ) - goto loop; - status &= ~st_i; - handle_cli: { - //debug_printf( "CLI at %d\n", TIME ); - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - irq_time_; - if ( delta <= 0 ) - { - if ( TIME < irq_time_ ) - goto loop; - goto delayed_cli; - } - s.base = irq_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - if ( delta >= s_time + 1 ) - { - s.base += s_time + 1; - s_time = -1; - goto loop; - } - - // TODO: implement - delayed_cli: - debug_printf( "Delayed CLI not emulated\n" ); - goto loop; - } - - case 0x78: // SEI - if ( status & st_i ) - goto loop; - status |= st_i; - handle_sei: { - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - end_time_; - s.base = end_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - debug_printf( "Delayed SEI not emulated\n" ); - goto loop; - } - -// Unofficial - - // SKW - Skip word - case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: - HANDLE_PAGE_CROSSING( data + x ); - case 0x0C: - pc++; - // SKB - Skip byte - case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: - case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: - pc++; - goto loop; - - // NOP - case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: - goto loop; - - case bad_opcode: // HLT - pc--; - case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: - case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: - goto stop; - -// Unimplemented - - case 0xFF: // force 256-entry jump table for optimization purposes - c |= 1; - default: - check( (unsigned) opcode <= 0xFF ); - // skip over proper number of bytes - static unsigned char const illop_lens [8] = { - 0x40, 0x40, 0x40, 0x80, 0x40, 0x40, 0x80, 0xA0 - }; - uint8_t opcode = instr [-1]; - int16_t len = illop_lens [opcode >> 2 & 7] >> (opcode << 1 & 6) & 3; - if ( opcode == 0x9C ) - len = 2; - pc += len; - error_count_++; - - if ( (opcode >> 4) == 0x0B ) - { - if ( opcode == 0xB3 ) - data = READ_LOW( data ); - if ( opcode != 0xB7 ) - HANDLE_PAGE_CROSSING( data + y ); - } - goto loop; - } - assert( false ); - - int result_; -handle_brk: - pc++; - result_ = 4; - -interrupt: - { - s_time += 7; - - WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); - WRITE_LOW( 0x100 | (sp - 2), pc ); - pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ ); - - sp = (sp - 3) | 0x100; - uint8_t temp; - CALC_STATUS( temp ); - temp |= st_r; - if ( result_ ) - temp |= st_b; // TODO: incorrectly sets B flag for IRQ - WRITE_LOW( sp, temp ); - - this->r.status = status |= st_i; - blargg_long delta = s.base - end_time_; - if ( delta >= 0 ) goto loop; - s_time += delta; - s.base = end_time_; - goto loop; - } - -out_of_time: - pc--; - FLUSH_TIME(); - CPU_DONE( this, TIME, result_ ); - CACHE_TIME(); - if ( result_ >= 0 ) - goto interrupt; - if ( s_time < 0 ) - goto loop; - -stop: - - s.time = s_time; - - r.pc = pc; - r.sp = GET_SP(); - r.a = a; - r.x = x; - r.y = y; - - { - uint8_t temp; - CALC_STATUS( temp ); - r.status = temp; - } - - this->state_ = s; - this->state = &this->state_; - - return s_time < 0; -} - diff --git a/libraries/game-music-emu/gme/Nes_Cpu.h b/libraries/game-music-emu/gme/Nes_Cpu.h deleted file mode 100644 index 878b5ba5c..000000000 --- a/libraries/game-music-emu/gme/Nes_Cpu.h +++ /dev/null @@ -1,112 +0,0 @@ -// NES 6502 CPU emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef NES_CPU_H -#define NES_CPU_H - -#include "blargg_common.h" - -typedef blargg_long nes_time_t; // clock cycle count -typedef unsigned nes_addr_t; // 16-bit address -enum { future_nes_time = INT_MAX / 2 + 1 }; - -class Nes_Cpu { -public: - // Clear registers, map low memory and its three mirrors to address 0, - // and mirror unmapped_page in remaining memory - void reset( void const* unmapped_page = 0 ); - - // Map code memory (memory accessed via the program counter). Start and size - // must be multiple of page_size. If mirror is true, repeats code page - // throughout address range. - enum { page_size = 0x800 }; - void map_code( nes_addr_t start, unsigned size, void const* code, bool mirror = false ); - - // Access emulated memory as CPU does - uint8_t const* get_code( nes_addr_t ); - - // 2KB of RAM at address 0 - uint8_t low_mem [0x800]; - - // NES 6502 registers. Not kept updated during a call to run(). - struct registers_t { - uint16_t pc; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t status; - uint8_t sp; - }; - registers_t r; - - // Set end_time and run CPU from current time. Returns true if execution - // stopped due to encountering bad_opcode. - bool run( nes_time_t end_time ); - - // Time of beginning of next instruction to be executed - nes_time_t time() const { return state->time + state->base; } - void set_time( nes_time_t t ) { state->time = t - state->base; } - void adjust_time( int delta ) { state->time += delta; } - - nes_time_t irq_time() const { return irq_time_; } - void set_irq_time( nes_time_t ); - - nes_time_t end_time() const { return end_time_; } - void set_end_time( nes_time_t ); - - // Number of undefined instructions encountered and skipped - void clear_error_count() { error_count_ = 0; } - unsigned long error_count() const { return error_count_; } - - // CPU invokes bad opcode handler if it encounters this - enum { bad_opcode = 0xF2 }; - -public: - Nes_Cpu() { state = &state_; } - enum { page_bits = 11 }; - enum { page_count = 0x10000 >> page_bits }; - enum { irq_inhibit = 0x04 }; -private: - struct state_t { - uint8_t const* code_map [page_count + 1]; - nes_time_t base; - int time; - }; - state_t* state; // points to state_ or a local copy within run() - state_t state_; - nes_time_t irq_time_; - nes_time_t end_time_; - unsigned long error_count_; - - void set_code_page( int, void const* ); - inline int update_end_time( nes_time_t end, nes_time_t irq ); -}; - -inline uint8_t const* Nes_Cpu::get_code( nes_addr_t addr ) -{ - return state->code_map [addr >> page_bits] + addr - #if !BLARGG_NONPORTABLE - % (unsigned) page_size - #endif - ; -} - -inline int Nes_Cpu::update_end_time( nes_time_t t, nes_time_t irq ) -{ - if ( irq < t && !(r.status & irq_inhibit) ) t = irq; - int delta = state->base - t; - state->base = t; - return delta; -} - -inline void Nes_Cpu::set_irq_time( nes_time_t t ) -{ - state->time += update_end_time( end_time_, (irq_time_ = t) ); -} - -inline void Nes_Cpu::set_end_time( nes_time_t t ) -{ - state->time += update_end_time( (end_time_ = t), irq_time_ ); -} - -#endif diff --git a/libraries/game-music-emu/gme/Nes_Fme7_Apu.cpp b/libraries/game-music-emu/gme/Nes_Fme7_Apu.cpp deleted file mode 100644 index 93973e409..000000000 --- a/libraries/game-music-emu/gme/Nes_Fme7_Apu.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Nes_Fme7_Apu.h" - -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 Nes_Fme7_Apu::reset() -{ - last_time = 0; - - for ( int i = 0; i < osc_count; i++ ) - oscs [i].last_amp = 0; - - fme7_apu_state_t* state = this; - memset( state, 0, sizeof *state ); -} - -unsigned char const Nes_Fme7_Apu::amp_table [16] = -{ - #define ENTRY( n ) (unsigned char) (n * amp_range + 0.5) - ENTRY(0.0000), ENTRY(0.0078), ENTRY(0.0110), ENTRY(0.0156), - ENTRY(0.0221), ENTRY(0.0312), ENTRY(0.0441), ENTRY(0.0624), - ENTRY(0.0883), ENTRY(0.1249), ENTRY(0.1766), ENTRY(0.2498), - ENTRY(0.3534), ENTRY(0.4998), ENTRY(0.7070), ENTRY(1.0000) - #undef ENTRY -}; - -void Nes_Fme7_Apu::run_until( blip_time_t end_time ) -{ - require( end_time >= last_time ); - - for ( int index = 0; index < osc_count; index++ ) - { - int mode = regs [7] >> index; - int vol_mode = regs [010 + index]; - int volume = amp_table [vol_mode & 0x0F]; - - Blip_Buffer* const osc_output = oscs [index].output; - if ( !osc_output ) - continue; - osc_output->set_modified(); - - // check for unsupported mode - #ifndef NDEBUG - if ( (mode & 011) <= 001 && vol_mode & 0x1F ) - debug_printf( "FME7 used unimplemented sound mode: %02X, vol_mode: %02X\n", - mode, vol_mode & 0x1F ); - #endif - - if ( (mode & 001) | (vol_mode & 0x10) ) - volume = 0; // noise and envelope aren't supported - - // period - int const period_factor = 16; - unsigned period = (regs [index * 2 + 1] & 0x0F) * 0x100 * period_factor + - regs [index * 2] * period_factor; - if ( period < 50 ) // around 22 kHz - { - volume = 0; - if ( !period ) // on my AY-3-8910A, period doesn't have extra one added - period = period_factor; - } - - // current amplitude - int amp = volume; - if ( !phases [index] ) - amp = 0; - { - int delta = amp - oscs [index].last_amp; - if ( delta ) - { - oscs [index].last_amp = amp; - synth.offset( last_time, delta, osc_output ); - } - } - - blip_time_t time = last_time + delays [index]; - if ( time < end_time ) - { - int delta = amp * 2 - volume; - if ( volume ) - { - do - { - delta = -delta; - synth.offset_inline( time, delta, osc_output ); - time += period; - } - while ( time < end_time ); - - oscs [index].last_amp = (delta + volume) >> 1; - phases [index] = (delta > 0); - } - else - { - // maintain phase when silent - int count = (end_time - time + period - 1) / period; - phases [index] ^= count & 1; - time += (blargg_long) count * period; - } - } - - delays [index] = time - end_time; - } - - last_time = end_time; -} - diff --git a/libraries/game-music-emu/gme/Nes_Fme7_Apu.h b/libraries/game-music-emu/gme/Nes_Fme7_Apu.h deleted file mode 100644 index b79ed6f5e..000000000 --- a/libraries/game-music-emu/gme/Nes_Fme7_Apu.h +++ /dev/null @@ -1,131 +0,0 @@ -// Sunsoft FME-7 sound emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef NES_FME7_APU_H -#define NES_FME7_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -struct fme7_apu_state_t -{ - enum { reg_count = 14 }; - uint8_t regs [reg_count]; - uint8_t phases [3]; // 0 or 1 - uint8_t latch; - uint16_t delays [3]; // a, b, c -}; - -class Nes_Fme7_Apu : private fme7_apu_state_t { -public: - // See Nes_Apu.h for reference - void reset(); - void volume( double ); - void treble_eq( blip_eq_t const& ); - void output( Blip_Buffer* ); - enum { osc_count = 3 }; - void osc_output( int index, Blip_Buffer* ); - void end_frame( blip_time_t ); - void save_state( fme7_apu_state_t* ) const; - void load_state( fme7_apu_state_t const& ); - - // Mask and addresses of registers - enum { addr_mask = 0xE000 }; - enum { data_addr = 0xE000 }; - enum { latch_addr = 0xC000 }; - - // (addr & addr_mask) == latch_addr - void write_latch( int ); - - // (addr & addr_mask) == data_addr - void write_data( blip_time_t, int data ); - -public: - Nes_Fme7_Apu(); - BLARGG_DISABLE_NOTHROW -private: - // noncopyable - Nes_Fme7_Apu( const Nes_Fme7_Apu& ); - Nes_Fme7_Apu& operator = ( const Nes_Fme7_Apu& ); - - static unsigned char const amp_table [16]; - - struct { - Blip_Buffer* output; - int last_amp; - } oscs [osc_count]; - blip_time_t last_time; - - enum { amp_range = 192 }; // can be any value; this gives best error/quality tradeoff - Blip_Synth synth; - - void run_until( blip_time_t ); -}; - -inline void Nes_Fme7_Apu::volume( double v ) -{ - synth.volume( 0.38 / amp_range * v ); // to do: fine-tune -} - -inline void Nes_Fme7_Apu::treble_eq( blip_eq_t const& eq ) -{ - synth.treble_eq( eq ); -} - -inline void Nes_Fme7_Apu::osc_output( int i, Blip_Buffer* buf ) -{ - assert( (unsigned) i < osc_count ); - oscs [i].output = buf; -} - -inline void Nes_Fme7_Apu::output( Blip_Buffer* buf ) -{ - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, buf ); -} - -inline Nes_Fme7_Apu::Nes_Fme7_Apu() -{ - output( NULL ); - volume( 1.0 ); - reset(); -} - -inline void Nes_Fme7_Apu::write_latch( int data ) { latch = data; } - -inline void Nes_Fme7_Apu::write_data( blip_time_t time, int data ) -{ - if ( (unsigned) latch >= reg_count ) - { - #ifdef debug_printf - debug_printf( "FME7 write to %02X (past end of sound registers)\n", (int) latch ); - #endif - return; - } - - run_until( time ); - regs [latch] = data; -} - -inline void Nes_Fme7_Apu::end_frame( blip_time_t time ) -{ - if ( time > last_time ) - run_until( time ); - - assert( last_time >= time ); - last_time -= time; -} - -inline void Nes_Fme7_Apu::save_state( fme7_apu_state_t* out ) const -{ - *out = *this; -} - -inline void Nes_Fme7_Apu::load_state( fme7_apu_state_t const& in ) -{ - reset(); - fme7_apu_state_t* state = this; - *state = in; -} - -#endif diff --git a/libraries/game-music-emu/gme/Nes_Namco_Apu.cpp b/libraries/game-music-emu/gme/Nes_Namco_Apu.cpp deleted file mode 100644 index 3e5fc1491..000000000 --- a/libraries/game-music-emu/gme/Nes_Namco_Apu.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/ - -#include "Nes_Namco_Apu.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -Nes_Namco_Apu::Nes_Namco_Apu() -{ - output( NULL ); - volume( 1.0 ); - reset(); -} - -void Nes_Namco_Apu::reset() -{ - last_time = 0; - addr_reg = 0; - - int i; - for ( i = 0; i < reg_count; i++ ) - reg [i] = 0; - - for ( i = 0; i < osc_count; i++ ) - { - Namco_Osc& osc = oscs [i]; - osc.delay = 0; - osc.last_amp = 0; - osc.wave_pos = 0; - } -} - -void Nes_Namco_Apu::output( Blip_Buffer* buf ) -{ - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, buf ); -} - -/* -void Nes_Namco_Apu::reflect_state( Tagged_Data& data ) -{ - reflect_int16( data, BLARGG_4CHAR('A','D','D','R'), &addr_reg ); - - static const char hex [17] = "0123456789ABCDEF"; - int i; - for ( i = 0; i < reg_count; i++ ) - reflect_int16( data, 'RG\0\0' + hex [i >> 4] * 0x100 + hex [i & 15], ® [i] ); - - for ( i = 0; i < osc_count; i++ ) - { - reflect_int32( data, BLARGG_4CHAR('D','L','Y','0') + i, &oscs [i].delay ); - reflect_int16( data, BLARGG_4CHAR('P','O','S','0') + i, &oscs [i].wave_pos ); - } -} -*/ - -void Nes_Namco_Apu::end_frame( blip_time_t time ) -{ - if ( time > last_time ) - run_until( time ); - - assert( last_time >= time ); - last_time -= time; -} - -void Nes_Namco_Apu::run_until( blip_time_t nes_end_time ) -{ - int active_oscs = (reg [0x7F] >> 4 & 7) + 1; - for ( int i = osc_count - active_oscs; i < osc_count; i++ ) - { - Namco_Osc& osc = oscs [i]; - Blip_Buffer* output = osc.output; - if ( !output ) - continue; - output->set_modified(); - - blip_resampled_time_t time = - output->resampled_time( last_time ) + osc.delay; - blip_resampled_time_t end_time = output->resampled_time( nes_end_time ); - osc.delay = 0; - if ( time < end_time ) - { - const uint8_t* osc_reg = ® [i * 8 + 0x40]; - if ( !(osc_reg [4] & 0xE0) ) - continue; - - int volume = osc_reg [7] & 15; - if ( !volume ) - continue; - - blargg_long freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100L + osc_reg [0]; - if ( freq < 64 * active_oscs ) - continue; // prevent low frequencies from excessively delaying freq changes - blip_resampled_time_t period = - output->resampled_duration( 983040 ) / freq * active_oscs; - - int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4; - if ( !wave_size ) - continue; - - int last_amp = osc.last_amp; - int wave_pos = osc.wave_pos; - - do - { - // read wave sample - int addr = wave_pos + osc_reg [6]; - int sample = reg [addr >> 1] >> (addr << 2 & 4); - wave_pos++; - sample = (sample & 15) * volume; - - // output impulse if amplitude changed - int delta = sample - last_amp; - if ( delta ) - { - last_amp = sample; - synth.offset_resampled( time, delta, output ); - } - - // next sample - time += period; - if ( wave_pos >= wave_size ) - wave_pos = 0; - } - while ( time < end_time ); - - osc.wave_pos = wave_pos; - osc.last_amp = last_amp; - } - osc.delay = time - end_time; - } - - last_time = nes_end_time; -} - diff --git a/libraries/game-music-emu/gme/Nes_Namco_Apu.h b/libraries/game-music-emu/gme/Nes_Namco_Apu.h deleted file mode 100644 index 876d85e0a..000000000 --- a/libraries/game-music-emu/gme/Nes_Namco_Apu.h +++ /dev/null @@ -1,102 +0,0 @@ -// Namco 106 sound chip emulator - -// Nes_Snd_Emu 0.1.8 -#ifndef NES_NAMCO_APU_H -#define NES_NAMCO_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -struct namco_state_t; - -class Nes_Namco_Apu { -public: - // See Nes_Apu.h for reference. - void volume( double ); - void treble_eq( const blip_eq_t& ); - void output( Blip_Buffer* ); - enum { osc_count = 8 }; - void osc_output( int index, Blip_Buffer* ); - void reset(); - void end_frame( blip_time_t ); - - // Read/write data register is at 0x4800 - enum { data_reg_addr = 0x4800 }; - void write_data( blip_time_t, int ); - int read_data(); - - // Write-only address register is at 0xF800 - enum { addr_reg_addr = 0xF800 }; - void write_addr( int ); - - // to do: implement save/restore - void save_state( namco_state_t* out ) const; - void load_state( namco_state_t const& ); - -public: - Nes_Namco_Apu(); - BLARGG_DISABLE_NOTHROW -private: - // noncopyable - Nes_Namco_Apu( const Nes_Namco_Apu& ); - Nes_Namco_Apu& operator = ( const Nes_Namco_Apu& ); - - struct Namco_Osc { - blargg_long delay; - Blip_Buffer* output; - short last_amp; - short wave_pos; - }; - - Namco_Osc oscs [osc_count]; - - blip_time_t last_time; - int addr_reg; - - enum { reg_count = 0x80 }; - uint8_t reg [reg_count]; - Blip_Synth synth; - - uint8_t& access(); - void run_until( blip_time_t ); -}; -/* -struct namco_state_t -{ - uint8_t regs [0x80]; - uint8_t addr; - uint8_t unused; - uint8_t positions [8]; - uint32_t delays [8]; -}; -*/ - -inline uint8_t& Nes_Namco_Apu::access() -{ - int addr = addr_reg & 0x7F; - if ( addr_reg & 0x80 ) - addr_reg = (addr + 1) | 0x80; - return reg [addr]; -} - -inline void Nes_Namco_Apu::volume( double v ) { synth.volume( 0.10 / osc_count * v ); } - -inline void Nes_Namco_Apu::treble_eq( const blip_eq_t& eq ) { synth.treble_eq( eq ); } - -inline void Nes_Namco_Apu::write_addr( int v ) { addr_reg = v; } - -inline int Nes_Namco_Apu::read_data() { return access(); } - -inline void Nes_Namco_Apu::osc_output( int i, Blip_Buffer* buf ) -{ - assert( (unsigned) i < osc_count ); - oscs [i].output = buf; -} - -inline void Nes_Namco_Apu::write_data( blip_time_t time, int data ) -{ - run_until( time ); - access() = data; -} - -#endif diff --git a/libraries/game-music-emu/gme/Nes_Oscs.cpp b/libraries/game-music-emu/gme/Nes_Oscs.cpp deleted file mode 100644 index 1ad3f59c0..000000000 --- a/libraries/game-music-emu/gme/Nes_Oscs.cpp +++ /dev/null @@ -1,551 +0,0 @@ -// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/ - -#include "Nes_Apu.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// Nes_Osc - -void Nes_Osc::clock_length( int halt_mask ) -{ - if ( length_counter && !(regs [0] & halt_mask) ) - length_counter--; -} - -void Nes_Envelope::clock_envelope() -{ - int period = regs [0] & 15; - if ( reg_written [3] ) { - reg_written [3] = false; - env_delay = period; - envelope = 15; - } - else if ( --env_delay < 0 ) { - env_delay = period; - if ( envelope | (regs [0] & 0x20) ) - envelope = (envelope - 1) & 15; - } -} - -int Nes_Envelope::volume() const -{ - return length_counter == 0 ? 0 : (regs [0] & 0x10) ? (regs [0] & 15) : envelope; -} - -// Nes_Square - -void Nes_Square::clock_sweep( int negative_adjust ) -{ - int sweep = regs [1]; - - if ( --sweep_delay < 0 ) - { - reg_written [1] = true; - - int period = this->period(); - int shift = sweep & shift_mask; - if ( shift && (sweep & 0x80) && period >= 8 ) - { - int offset = period >> shift; - - if ( sweep & negate_flag ) - offset = negative_adjust - offset; - - if ( period + offset < 0x800 ) - { - period += offset; - // rewrite period - regs [2] = period & 0xFF; - regs [3] = (regs [3] & ~7) | ((period >> 8) & 7); - } - } - } - - if ( reg_written [1] ) { - reg_written [1] = false; - sweep_delay = (sweep >> 4) & 7; - } -} - -// TODO: clean up -inline nes_time_t Nes_Square::maintain_phase( nes_time_t time, nes_time_t end_time, - nes_time_t timer_period ) -{ - nes_time_t remain = end_time - time; - if ( remain > 0 ) - { - int count = (remain + timer_period - 1) / timer_period; - phase = (phase + count) & (phase_range - 1); - time += (blargg_long) count * timer_period; - } - return time; -} - -void Nes_Square::run( nes_time_t time, nes_time_t end_time ) -{ - const int period = this->period(); - const int timer_period = (period + 1) * 2; - - if ( !output ) - { - delay = maintain_phase( time + delay, end_time, timer_period ) - end_time; - return; - } - - output->set_modified(); - - int offset = period >> (regs [1] & shift_mask); - if ( regs [1] & negate_flag ) - offset = 0; - - const int volume = this->volume(); - if ( volume == 0 || period < 8 || (period + offset) >= 0x800 ) - { - if ( last_amp ) { - synth.offset( time, -last_amp, output ); - last_amp = 0; - } - - time += delay; - time = maintain_phase( time, end_time, timer_period ); - } - else - { - // handle duty select - int duty_select = (regs [0] >> 6) & 3; - int duty = 1 << duty_select; // 1, 2, 4, 2 - int amp = 0; - if ( duty_select == 3 ) { - duty = 2; // negated 25% - amp = volume; - } - if ( phase < duty ) - amp ^= volume; - - { - int delta = update_amp( amp ); - if ( delta ) - synth.offset( time, delta, output ); - } - - time += delay; - if ( time < end_time ) - { - Blip_Buffer* const output = this->output; - const Synth& synth = this->synth; - int delta = amp * 2 - volume; - int phase = this->phase; - - do { - phase = (phase + 1) & (phase_range - 1); - if ( phase == 0 || phase == duty ) { - delta = -delta; - synth.offset_inline( time, delta, output ); - } - time += timer_period; - } - while ( time < end_time ); - - last_amp = (delta + volume) >> 1; - this->phase = phase; - } - } - - delay = time - end_time; -} - -// Nes_Triangle - -void Nes_Triangle::clock_linear_counter() -{ - if ( reg_written [3] ) - linear_counter = regs [0] & 0x7F; - else if ( linear_counter ) - linear_counter--; - - if ( !(regs [0] & 0x80) ) - reg_written [3] = false; -} - -inline int Nes_Triangle::calc_amp() const -{ - int amp = phase_range - phase; - if ( amp < 0 ) - amp = phase - (phase_range + 1); - return amp; -} - -// TODO: clean up -inline nes_time_t Nes_Triangle::maintain_phase( nes_time_t time, nes_time_t end_time, - nes_time_t timer_period ) -{ - nes_time_t remain = end_time - time; - if ( remain > 0 ) - { - int count = (remain + timer_period - 1) / timer_period; - phase = ((unsigned) phase + 1 - count) & (phase_range * 2 - 1); - phase++; - time += (blargg_long) count * timer_period; - } - return time; -} - -void Nes_Triangle::run( nes_time_t time, nes_time_t end_time ) -{ - const int timer_period = period() + 1; - if ( !output ) - { - time += delay; - delay = 0; - if ( length_counter && linear_counter && timer_period >= 3 ) - delay = maintain_phase( time, end_time, timer_period ) - end_time; - return; - } - - output->set_modified(); - - // to do: track phase when period < 3 - // to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks. - - int delta = update_amp( calc_amp() ); - if ( delta ) - synth.offset( time, delta, output ); - - time += delay; - if ( length_counter == 0 || linear_counter == 0 || timer_period < 3 ) - { - time = end_time; - } - else if ( time < end_time ) - { - Blip_Buffer* const output = this->output; - - int phase = this->phase; - int volume = 1; - if ( phase > phase_range ) { - phase -= phase_range; - volume = -volume; - } - - do { - if ( --phase == 0 ) { - phase = phase_range; - volume = -volume; - } - else { - synth.offset_inline( time, volume, output ); - } - - time += timer_period; - } - while ( time < end_time ); - - if ( volume < 0 ) - phase += phase_range; - this->phase = phase; - last_amp = calc_amp(); - } - delay = time - end_time; -} - -// Nes_Dmc - -void Nes_Dmc::reset() -{ - address = 0; - dac = 0; - buf = 0; - bits_remain = 1; - bits = 0; - buf_full = false; - silence = true; - next_irq = Nes_Apu::no_irq; - irq_flag = false; - irq_enabled = false; - - Nes_Osc::reset(); - period = 0x1AC; -} - -void Nes_Dmc::recalc_irq() -{ - nes_time_t irq = Nes_Apu::no_irq; - if ( irq_enabled && length_counter ) - irq = apu->last_dmc_time + delay + - ((length_counter - 1) * 8 + bits_remain - 1) * nes_time_t (period) + 1; - if ( irq != next_irq ) { - next_irq = irq; - apu->irq_changed(); - } -} - -int Nes_Dmc::count_reads( nes_time_t time, nes_time_t* last_read ) const -{ - if ( last_read ) - *last_read = time; - - if ( length_counter == 0 ) - return 0; // not reading - - nes_time_t first_read = next_read_time(); - nes_time_t avail = time - first_read; - if ( avail <= 0 ) - return 0; - - int count = (avail - 1) / (period * 8) + 1; - if ( !(regs [0] & loop_flag) && count > length_counter ) - count = length_counter; - - if ( last_read ) - { - *last_read = first_read + (count - 1) * (period * 8) + 1; - check( *last_read <= time ); - check( count == count_reads( *last_read, NULL ) ); - check( count - 1 == count_reads( *last_read - 1, NULL ) ); - } - - return count; -} - -static short const dmc_period_table [2] [16] = { - {428, 380, 340, 320, 286, 254, 226, 214, // NTSC - 190, 160, 142, 128, 106, 84, 72, 54}, - - {398, 354, 316, 298, 276, 236, 210, 198, // PAL - 176, 148, 132, 118, 98, 78, 66, 50} -}; - -inline void Nes_Dmc::reload_sample() -{ - address = 0x4000 + regs [2] * 0x40; - length_counter = regs [3] * 0x10 + 1; -} - -static byte const dac_table [128] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14, - 15,15,16,17,18,19,20,20,21,22,23,24,24,25,26,27, - 27,28,29,30,31,31,32,33,33,34,35,36,36,37,38,38, - 39,40,41,41,42,43,43,44,45,45,46,47,47,48,48,49, - 50,50,51,52,52,53,53,54,55,55,56,56,57,58,58,59, - 59,60,60,61,61,62,63,63,64,64,65,65,66,66,67,67, - 68,68,69,70,70,71,71,72,72,73,73,74,74,75,75,75, - 76,76,77,77,78,78,79,79,80,80,81,81,82,82,82,83, -}; - -void Nes_Dmc::write_register( int addr, int data ) -{ - if ( addr == 0 ) - { - period = dmc_period_table [pal_mode] [data & 15]; - irq_enabled = (data & 0xC0) == 0x80; // enabled only if loop disabled - irq_flag &= irq_enabled; - recalc_irq(); - } - else if ( addr == 1 ) - { - int old_dac = dac; - dac = data & 0x7F; - - // adjust last_amp so that "pop" amplitude will be properly non-linear - // with respect to change in dac - int faked_nonlinear = dac - (dac_table [dac] - dac_table [old_dac]); - if ( !nonlinear ) - last_amp = faked_nonlinear; - } -} - -void Nes_Dmc::start() -{ - reload_sample(); - fill_buffer(); - recalc_irq(); -} - -void Nes_Dmc::fill_buffer() -{ - if ( !buf_full && length_counter ) - { - require( prg_reader ); // prg_reader must be set - buf = prg_reader( prg_reader_data, 0x8000u + address ); - address = (address + 1) & 0x7FFF; - buf_full = true; - if ( --length_counter == 0 ) - { - if ( regs [0] & loop_flag ) { - reload_sample(); - } - else { - apu->osc_enables &= ~0x10; - irq_flag = irq_enabled; - next_irq = Nes_Apu::no_irq; - apu->irq_changed(); - } - } - } -} - -void Nes_Dmc::run( nes_time_t time, nes_time_t end_time ) -{ - int delta = update_amp( dac ); - if ( !output ) - { - silence = true; - } - else - { - output->set_modified(); - if ( delta ) - synth.offset( time, delta, output ); - } - - time += delay; - if ( time < end_time ) - { - int bits_remain = this->bits_remain; - if ( silence && !buf_full ) - { - int count = (end_time - time + period - 1) / period; - bits_remain = (bits_remain - 1 + 8 - (count % 8)) % 8 + 1; - time += count * period; - } - else - { - Blip_Buffer* const output = this->output; - const int period = this->period; - int bits = this->bits; - int dac = this->dac; - - do - { - if ( !silence ) - { - int step = (bits & 1) * 4 - 2; - bits >>= 1; - if ( unsigned (dac + step) <= 0x7F ) { - dac += step; - synth.offset_inline( time, step, output ); - } - } - - time += period; - - if ( --bits_remain == 0 ) - { - bits_remain = 8; - if ( !buf_full ) { - silence = true; - } - else { - silence = false; - bits = buf; - buf_full = false; - if ( !output ) - silence = true; - fill_buffer(); - } - } - } - while ( time < end_time ); - - this->dac = dac; - this->last_amp = dac; - this->bits = bits; - } - this->bits_remain = bits_remain; - } - delay = time - end_time; -} - -// Nes_Noise - -static short const noise_period_table [16] = { - 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0, - 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4 -}; - -void Nes_Noise::run( nes_time_t time, nes_time_t end_time ) -{ - int period = noise_period_table [regs [2] & 15]; - - if ( !output ) - { - // TODO: clean up - time += delay; - delay = time + (end_time - time + period - 1) / period * period - end_time; - return; - } - - output->set_modified(); - - const int volume = this->volume(); - int amp = (noise & 1) ? volume : 0; - { - int delta = update_amp( amp ); - if ( delta ) - synth.offset( time, delta, output ); - } - - time += delay; - if ( time < end_time ) - { - const int mode_flag = 0x80; - - if ( !volume ) - { - // round to next multiple of period - time += (end_time - time + period - 1) / period * period; - - // approximate noise cycling while muted, by shuffling up noise register - // to do: precise muted noise cycling? - if ( !(regs [2] & mode_flag) ) { - int feedback = (noise << 13) ^ (noise << 14); - noise = (feedback & 0x4000) | (noise >> 1); - } - } - else - { - Blip_Buffer* const output = this->output; - - // using resampled time avoids conversion in synth.offset() - blip_resampled_time_t rperiod = output->resampled_duration( period ); - blip_resampled_time_t rtime = output->resampled_time( time ); - - int noise = this->noise; - int delta = amp * 2 - volume; - const int tap = (regs [2] & mode_flag ? 8 : 13); - - do { - int feedback = (noise << tap) ^ (noise << 14); - time += period; - - if ( (noise + 1) & 2 ) { - // bits 0 and 1 of noise differ - delta = -delta; - synth.offset_resampled( rtime, delta, output ); - } - - rtime += rperiod; - noise = (feedback & 0x4000) | (noise >> 1); - } - while ( time < end_time ); - - last_amp = (delta + volume) >> 1; - this->noise = noise; - } - } - - delay = time - end_time; -} - diff --git a/libraries/game-music-emu/gme/Nes_Oscs.h b/libraries/game-music-emu/gme/Nes_Oscs.h deleted file mode 100644 index b675bfb47..000000000 --- a/libraries/game-music-emu/gme/Nes_Oscs.h +++ /dev/null @@ -1,147 +0,0 @@ -// Private oscillators used by Nes_Apu - -// Nes_Snd_Emu 0.1.8 -#ifndef NES_OSCS_H -#define NES_OSCS_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -class Nes_Apu; - -struct Nes_Osc -{ - unsigned char regs [4]; - bool reg_written [4]; - Blip_Buffer* output; - int length_counter;// length counter (0 if unused by oscillator) - int delay; // delay until next (potential) transition - int last_amp; // last amplitude oscillator was outputting - - void clock_length( int halt_mask ); - int period() const { - return (regs [3] & 7) * 0x100 + (regs [2] & 0xFF); - } - void reset() { - delay = 0; - last_amp = 0; - } - int update_amp( int amp ) { - int delta = amp - last_amp; - last_amp = amp; - return delta; - } -}; - -struct Nes_Envelope : Nes_Osc -{ - int envelope; - int env_delay; - - void clock_envelope(); - int volume() const; - void reset() { - envelope = 0; - env_delay = 0; - Nes_Osc::reset(); - } -}; - -// Nes_Square -struct Nes_Square : Nes_Envelope -{ - enum { negate_flag = 0x08 }; - enum { shift_mask = 0x07 }; - enum { phase_range = 8 }; - int phase; - int sweep_delay; - - typedef Blip_Synth Synth; - Synth const& synth; // shared between squares - - Nes_Square( Synth const* s ) : synth( *s ) { } - - void clock_sweep( int adjust ); - void run( nes_time_t, nes_time_t ); - void reset() { - sweep_delay = 0; - Nes_Envelope::reset(); - } - nes_time_t maintain_phase( nes_time_t time, nes_time_t end_time, - nes_time_t timer_period ); -}; - -// Nes_Triangle -struct Nes_Triangle : Nes_Osc -{ - enum { phase_range = 16 }; - int phase; - int linear_counter; - Blip_Synth synth; - - int calc_amp() const; - void run( nes_time_t, nes_time_t ); - void clock_linear_counter(); - void reset() { - linear_counter = 0; - phase = 1; - Nes_Osc::reset(); - } - nes_time_t maintain_phase( nes_time_t time, nes_time_t end_time, - nes_time_t timer_period ); -}; - -// Nes_Noise -struct Nes_Noise : Nes_Envelope -{ - int noise; - Blip_Synth synth; - - void run( nes_time_t, nes_time_t ); - void reset() { - noise = 1 << 14; - Nes_Envelope::reset(); - } -}; - -// Nes_Dmc -struct Nes_Dmc : Nes_Osc -{ - int address; // address of next byte to read - int period; - //int length_counter; // bytes remaining to play (already defined in Nes_Osc) - int buf; - int bits_remain; - int bits; - bool buf_full; - bool silence; - - enum { loop_flag = 0x40 }; - - int dac; - - nes_time_t next_irq; - bool irq_enabled; - bool irq_flag; - bool pal_mode; - bool nonlinear; - - int (*prg_reader)( void*, nes_addr_t ); // needs to be initialized to prg read function - void* prg_reader_data; - - Nes_Apu* apu; - - Blip_Synth synth; - - void start(); - void write_register( int, int ); - void run( nes_time_t, nes_time_t ); - void recalc_irq(); - void fill_buffer(); - void reload_sample(); - void reset(); - int count_reads( nes_time_t, nes_time_t* ) const; - nes_time_t next_read_time() const; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Nes_Vrc6_Apu.cpp b/libraries/game-music-emu/gme/Nes_Vrc6_Apu.cpp deleted file mode 100644 index d178407c3..000000000 --- a/libraries/game-music-emu/gme/Nes_Vrc6_Apu.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/ - -#include "Nes_Vrc6_Apu.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -Nes_Vrc6_Apu::Nes_Vrc6_Apu() -{ - output( NULL ); - volume( 1.0 ); - reset(); -} - -void Nes_Vrc6_Apu::reset() -{ - last_time = 0; - for ( int i = 0; i < osc_count; i++ ) - { - Vrc6_Osc& osc = oscs [i]; - for ( int j = 0; j < reg_count; j++ ) - osc.regs [j] = 0; - osc.delay = 0; - osc.last_amp = 0; - osc.phase = 1; - osc.amp = 0; - } -} - -void Nes_Vrc6_Apu::output( Blip_Buffer* buf ) -{ - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, buf ); -} - -void Nes_Vrc6_Apu::run_until( blip_time_t time ) -{ - require( time >= last_time ); - run_square( oscs [0], time ); - run_square( oscs [1], time ); - run_saw( time ); - last_time = time; -} - -void Nes_Vrc6_Apu::write_osc( blip_time_t time, int osc_index, int reg, int data ) -{ - require( (unsigned) osc_index < osc_count ); - require( (unsigned) reg < reg_count ); - - run_until( time ); - oscs [osc_index].regs [reg] = data; -} - -void Nes_Vrc6_Apu::end_frame( blip_time_t time ) -{ - if ( time > last_time ) - run_until( time ); - - assert( last_time >= time ); - last_time -= time; -} - -void Nes_Vrc6_Apu::save_state( vrc6_apu_state_t* out ) const -{ - assert( sizeof (vrc6_apu_state_t) == 20 ); - out->saw_amp = oscs [2].amp; - for ( int i = 0; i < osc_count; i++ ) - { - Vrc6_Osc const& osc = oscs [i]; - for ( int r = 0; r < reg_count; r++ ) - out->regs [i] [r] = osc.regs [r]; - - out->delays [i] = osc.delay; - out->phases [i] = osc.phase; - } -} - -void Nes_Vrc6_Apu::load_state( vrc6_apu_state_t const& in ) -{ - reset(); - oscs [2].amp = in.saw_amp; - for ( int i = 0; i < osc_count; i++ ) - { - Vrc6_Osc& osc = oscs [i]; - for ( int r = 0; r < reg_count; r++ ) - osc.regs [r] = in.regs [i] [r]; - - osc.delay = in.delays [i]; - osc.phase = in.phases [i]; - } - if ( !oscs [2].phase ) - oscs [2].phase = 1; -} - -void Nes_Vrc6_Apu::run_square( Vrc6_Osc& osc, blip_time_t end_time ) -{ - Blip_Buffer* output = osc.output; - if ( !output ) - return; - output->set_modified(); - - int volume = osc.regs [0] & 15; - if ( !(osc.regs [2] & 0x80) ) - volume = 0; - - int gate = osc.regs [0] & 0x80; - int duty = ((osc.regs [0] >> 4) & 7) + 1; - int delta = ((gate || osc.phase < duty) ? volume : 0) - osc.last_amp; - blip_time_t time = last_time; - if ( delta ) - { - osc.last_amp += delta; - square_synth.offset( time, delta, output ); - } - - time += osc.delay; - osc.delay = 0; - int period = osc.period(); - if ( volume && !gate && period > 4 ) - { - if ( time < end_time ) - { - int phase = osc.phase; - - do - { - phase++; - if ( phase == 16 ) - { - phase = 0; - osc.last_amp = volume; - square_synth.offset( time, volume, output ); - } - if ( phase == duty ) - { - osc.last_amp = 0; - square_synth.offset( time, -volume, output ); - } - time += period; - } - while ( time < end_time ); - - osc.phase = phase; - } - osc.delay = time - end_time; - } -} - -void Nes_Vrc6_Apu::run_saw( blip_time_t end_time ) -{ - Vrc6_Osc& osc = oscs [2]; - Blip_Buffer* output = osc.output; - if ( !output ) - return; - output->set_modified(); - - int amp = osc.amp; - int amp_step = osc.regs [0] & 0x3F; - blip_time_t time = last_time; - int last_amp = osc.last_amp; - if ( !(osc.regs [2] & 0x80) || !(amp_step | amp) ) - { - osc.delay = 0; - int delta = (amp >> 3) - last_amp; - last_amp = amp >> 3; - saw_synth.offset( time, delta, output ); - } - else - { - time += osc.delay; - if ( time < end_time ) - { - int period = osc.period() * 2; - int phase = osc.phase; - - do - { - if ( --phase == 0 ) - { - phase = 7; - amp = 0; - } - - int delta = (amp >> 3) - last_amp; - if ( delta ) - { - last_amp = amp >> 3; - saw_synth.offset( time, delta, output ); - } - - time += period; - amp = (amp + amp_step) & 0xFF; - } - while ( time < end_time ); - - osc.phase = phase; - osc.amp = amp; - } - - osc.delay = time - end_time; - } - - osc.last_amp = last_amp; -} - diff --git a/libraries/game-music-emu/gme/Nes_Vrc6_Apu.h b/libraries/game-music-emu/gme/Nes_Vrc6_Apu.h deleted file mode 100644 index 23a6519fc..000000000 --- a/libraries/game-music-emu/gme/Nes_Vrc6_Apu.h +++ /dev/null @@ -1,95 +0,0 @@ -// Konami VRC6 sound chip emulator - -// Nes_Snd_Emu 0.1.8 -#ifndef NES_VRC6_APU_H -#define NES_VRC6_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -struct vrc6_apu_state_t; - -class Nes_Vrc6_Apu { -public: - // See Nes_Apu.h for reference - void reset(); - void volume( double ); - void treble_eq( blip_eq_t const& ); - void output( Blip_Buffer* ); - enum { osc_count = 3 }; - void osc_output( int index, Blip_Buffer* ); - void end_frame( blip_time_t ); - void save_state( vrc6_apu_state_t* ) const; - void load_state( vrc6_apu_state_t const& ); - - // Oscillator 0 write-only registers are at $9000-$9002 - // Oscillator 1 write-only registers are at $A000-$A002 - // Oscillator 2 write-only registers are at $B000-$B002 - enum { reg_count = 3 }; - enum { base_addr = 0x9000 }; - enum { addr_step = 0x1000 }; - void write_osc( blip_time_t, int osc, int reg, int data ); - -public: - Nes_Vrc6_Apu(); - BLARGG_DISABLE_NOTHROW -private: - // noncopyable - Nes_Vrc6_Apu( const Nes_Vrc6_Apu& ); - Nes_Vrc6_Apu& operator = ( const Nes_Vrc6_Apu& ); - - struct Vrc6_Osc - { - uint8_t regs [3]; - Blip_Buffer* output; - int delay; - int last_amp; - int phase; - int amp; // only used by saw - - int period() const - { - return (regs [2] & 0x0F) * 0x100L + regs [1] + 1; - } - }; - - Vrc6_Osc oscs [osc_count]; - blip_time_t last_time; - - Blip_Synth saw_synth; - Blip_Synth square_synth; - - void run_until( blip_time_t ); - void run_square( Vrc6_Osc& osc, blip_time_t ); - void run_saw( blip_time_t ); -}; - -struct vrc6_apu_state_t -{ - uint8_t regs [3] [3]; - uint8_t saw_amp; - uint16_t delays [3]; - uint8_t phases [3]; - uint8_t unused; -}; - -inline void Nes_Vrc6_Apu::osc_output( int i, Blip_Buffer* buf ) -{ - assert( (unsigned) i < osc_count ); - oscs [i].output = buf; -} - -inline void Nes_Vrc6_Apu::volume( double v ) -{ - double const factor = 0.0967 * 2; - saw_synth.volume( factor / 31 * v ); - square_synth.volume( factor * 0.5 / 15 * v ); -} - -inline void Nes_Vrc6_Apu::treble_eq( blip_eq_t const& eq ) -{ - saw_synth.treble_eq( eq ); - square_synth.treble_eq( eq ); -} - -#endif diff --git a/libraries/game-music-emu/gme/Nsf_Emu.cpp b/libraries/game-music-emu/gme/Nsf_Emu.cpp deleted file mode 100644 index 74d76850e..000000000 --- a/libraries/game-music-emu/gme/Nsf_Emu.cpp +++ /dev/null @@ -1,561 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Nsf_Emu.h" - -#include "blargg_endian.h" -#include -#include - -#if !NSF_EMU_APU_ONLY - #include "Nes_Namco_Apu.h" - #include "Nes_Vrc6_Apu.h" - #include "Nes_Fme7_Apu.h" -#endif - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -int const vrc6_flag = 0x01; -int const namco_flag = 0x10; -int const fme7_flag = 0x20; - -long const clock_divisor = 12; - -Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq = - 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 ) -{ - return *((Nsf_Emu*) emu)->cpu::get_code( addr ); -} - -Nsf_Emu::Nsf_Emu() -{ - vrc6 = 0; - namco = 0; - fme7 = 0; - - set_type( gme_nsf_type ); - set_silence_lookahead( 6 ); - apu.dmc_reader( pcm_read, this ); - Music_Emu::set_equalizer( nes_eq ); - set_gain( 1.4 ); - memset( unmapped_code, Nes_Cpu::bad_opcode, sizeof unmapped_code ); -} - -Nsf_Emu::~Nsf_Emu() { unload(); } - -void Nsf_Emu::unload() -{ - #if !NSF_EMU_APU_ONLY - { - delete vrc6; - vrc6 = 0; - - delete namco; - namco = 0; - - delete fme7; - fme7 = 0; - } - #endif - - rom.clear(); - Music_Emu::unload(); -} - -// Track info - -static void copy_nsf_fields( Nsf_Emu::header_t const& h, track_info_t* out ) -{ - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, author ); - GME_COPY_FIELD( h, out, copyright ); - if ( h.chip_flags ) - Gme_File::copy_field_( out->system, "Famicom" ); -} - -blargg_err_t Nsf_Emu::track_info_( track_info_t* out, int ) const -{ - copy_nsf_fields( header_, out ); - return 0; -} - -static blargg_err_t check_nsf_header( void const* header ) -{ - if ( memcmp( header, "NESM\x1A", 5 ) ) - return gme_wrong_file_type; - return 0; -} - -struct Nsf_File : Gme_Info_ -{ - Nsf_Emu::header_t h; - - Nsf_File() { set_type( gme_nsf_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - blargg_err_t err = in.read( &h, Nsf_Emu::header_size ); - if ( err ) - return (err == in.eof_error ? gme_wrong_file_type : err); - - if ( h.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag) ) - set_warning( "Uses unsupported audio expansion hardware" ); - - set_track_count( h.track_count ); - return check_nsf_header( &h ); - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_nsf_fields( h, out ); - return 0; - } -}; - -static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; } -static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; } - -static gme_type_t_ const gme_nsf_type_ = { "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_nsf_type = &gme_nsf_type_; - - -// Setup - -void Nsf_Emu::set_tempo_( double t ) -{ - unsigned playback_rate = get_le16( header_.ntsc_speed ); - unsigned standard_rate = 0x411A; - clock_rate_ = 1789772.72727; - play_period = 262 * 341L * 4 - 2; // two fewer PPU clocks every four frames - - if ( pal_only ) - { - play_period = 33247 * clock_divisor; - clock_rate_ = 1662607.125; - standard_rate = 0x4E20; - playback_rate = get_le16( header_.pal_speed ); - } - - if ( !playback_rate ) - playback_rate = standard_rate; - - if ( playback_rate != standard_rate || t != 1.0 ) - play_period = long (playback_rate * clock_rate_ / (1000000.0 / clock_divisor * t)); - - apu.set_tempo( t ); -} - -blargg_err_t Nsf_Emu::init_sound() -{ - if ( header_.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag) ) - set_warning( "Uses unsupported audio expansion hardware" ); - - { - #define APU_NAMES "Square 1", "Square 2", "Triangle", "Noise", "DMC" - - int const count = Nes_Apu::osc_count; - static const char* const apu_names [count] = { APU_NAMES }; - set_voice_count( count ); - set_voice_names( apu_names ); - - } - - static int const types [] = { - wave_type | 1, wave_type | 2, wave_type | 0, - noise_type | 0, mixed_type | 1, - wave_type | 3, wave_type | 4, wave_type | 5, - wave_type | 6, wave_type | 7, wave_type | 8, wave_type | 9, - wave_type |10, wave_type |11, wave_type |12, wave_type |13 - }; - set_voice_types( types ); // common to all sound chip configurations - - double adjusted_gain = gain(); - - #if NSF_EMU_APU_ONLY - { - if ( header_.chip_flags ) - set_warning( "Uses unsupported audio expansion hardware" ); - } - #else - { - if ( header_.chip_flags & (namco_flag | vrc6_flag | fme7_flag) ) - set_voice_count( Nes_Apu::osc_count + 3 ); - - if ( header_.chip_flags & namco_flag ) - { - namco = BLARGG_NEW Nes_Namco_Apu; - CHECK_ALLOC( namco ); - adjusted_gain *= 0.75; - - int const count = Nes_Apu::osc_count + Nes_Namco_Apu::osc_count; - static const char* const names [count] = { - APU_NAMES, - "Wave 1", "Wave 2", "Wave 3", "Wave 4", - "Wave 5", "Wave 6", "Wave 7", "Wave 8" - }; - set_voice_count( count ); - set_voice_names( names ); - } - - if ( header_.chip_flags & vrc6_flag ) - { - vrc6 = BLARGG_NEW Nes_Vrc6_Apu; - CHECK_ALLOC( vrc6 ); - adjusted_gain *= 0.75; - - { - int const count = Nes_Apu::osc_count + Nes_Vrc6_Apu::osc_count; - static const char* const names [count] = { - APU_NAMES, - "Saw Wave", "Square 3", "Square 4" - }; - set_voice_count( count ); - set_voice_names( names ); - } - - if ( header_.chip_flags & namco_flag ) - { - int const count = Nes_Apu::osc_count + Nes_Vrc6_Apu::osc_count + - Nes_Namco_Apu::osc_count; - static const char* const names [count] = { - APU_NAMES, - "Saw Wave", "Square 3", "Square 4", - "Wave 1", "Wave 2", "Wave 3", "Wave 4", - "Wave 5", "Wave 6", "Wave 7", "Wave 8" - }; - set_voice_count( count ); - set_voice_names( names ); - } - } - - if ( header_.chip_flags & fme7_flag ) - { - fme7 = BLARGG_NEW Nes_Fme7_Apu; - CHECK_ALLOC( fme7 ); - adjusted_gain *= 0.75; - - int const count = Nes_Apu::osc_count + Nes_Fme7_Apu::osc_count; - static const char* const names [count] = { - APU_NAMES, - "Square 3", "Square 4", "Square 5" - }; - set_voice_count( count ); - set_voice_names( names ); - } - - if ( namco ) namco->volume( adjusted_gain ); - if ( vrc6 ) vrc6 ->volume( adjusted_gain ); - if ( fme7 ) fme7 ->volume( adjusted_gain ); - } - #endif - - apu.volume( adjusted_gain ); - - return 0; -} - -blargg_err_t Nsf_Emu::load_( Data_Reader& in ) -{ - assert( offsetof (header_t,unused [4]) == header_size ); - RETURN_ERR( rom.load( in, header_size, &header_, 0 ) ); - - set_track_count( header_.track_count ); - RETURN_ERR( check_nsf_header( &header_ ) ); - - if ( header_.vers != 1 ) - set_warning( "Unknown file version" ); - - // sound and memory - blargg_err_t err = init_sound(); - if ( err ) - return err; - - // set up data - nes_addr_t load_addr = get_le16( header_.load_addr ); - init_addr = get_le16( header_.init_addr ); - play_addr = get_le16( header_.play_addr ); - if ( !load_addr ) load_addr = rom_begin; - if ( !init_addr ) init_addr = rom_begin; - if ( !play_addr ) play_addr = rom_begin; - if ( load_addr < rom_begin || init_addr < rom_begin ) - { - const char* w = warning(); - if ( !w ) - w = "Corrupt file (invalid load/init/play address)"; - return w; - } - - rom.set_addr( load_addr % bank_size ); - int total_banks = rom.size() / bank_size; - - // bank switching - int first_bank = (load_addr - rom_begin) / bank_size; - for ( int i = 0; i < bank_count; i++ ) - { - unsigned bank = i - first_bank; - if ( bank >= (unsigned) total_banks ) - bank = 0; - initial_banks [i] = bank; - - if ( header_.banks [i] ) - { - // bank-switched - memcpy( initial_banks, header_.banks, sizeof initial_banks ); - break; - } - } - - pal_only = (header_.speed_flags & 3) == 1; - - #if !NSF_EMU_EXTRA_FLAGS - header_.speed_flags = 0; - #endif - - set_tempo( tempo() ); - - return setup_buffer( (long) (clock_rate_ + 0.5) ); -} - -void Nsf_Emu::update_eq( blip_eq_t const& eq ) -{ - apu.treble_eq( eq ); - - #if !NSF_EMU_APU_ONLY - { - if ( namco ) namco->treble_eq( eq ); - if ( vrc6 ) vrc6 ->treble_eq( eq ); - if ( fme7 ) fme7 ->treble_eq( eq ); - } - #endif -} - -void Nsf_Emu::set_voice( int i, Blip_Buffer* buf, Blip_Buffer*, Blip_Buffer* ) -{ - if ( i < Nes_Apu::osc_count ) - { - apu.osc_output( i, buf ); - return; - } - i -= Nes_Apu::osc_count; - - #if !NSF_EMU_APU_ONLY - { - if ( fme7 && i < Nes_Fme7_Apu::osc_count ) - { - fme7->osc_output( i, buf ); - return; - } - - if ( vrc6 ) - { - if ( i < Nes_Vrc6_Apu::osc_count ) - { - // put saw first - if ( --i < 0 ) - i = 2; - vrc6->osc_output( i, buf ); - return; - } - i -= Nes_Vrc6_Apu::osc_count; - } - - if ( namco && i < Nes_Namco_Apu::osc_count ) - { - namco->osc_output( i, buf ); - return; - } - } - #endif -} - -// Emulation - -// see nes_cpu_io.h for read/write functions - -void Nsf_Emu::cpu_write_misc( nes_addr_t addr, int data ) -{ - #if !NSF_EMU_APU_ONLY - { - if ( namco ) - { - switch ( addr ) - { - case Nes_Namco_Apu::data_reg_addr: - namco->write_data( time(), data ); - return; - - case Nes_Namco_Apu::addr_reg_addr: - namco->write_addr( data ); - return; - } - } - - if ( addr >= Nes_Fme7_Apu::latch_addr && fme7 ) - { - switch ( addr & Nes_Fme7_Apu::addr_mask ) - { - case Nes_Fme7_Apu::latch_addr: - fme7->write_latch( data ); - return; - - case Nes_Fme7_Apu::data_addr: - fme7->write_data( time(), data ); - return; - } - } - - if ( vrc6 ) - { - unsigned reg = addr & (Nes_Vrc6_Apu::addr_step - 1); - unsigned osc = unsigned (addr - Nes_Vrc6_Apu::base_addr) / Nes_Vrc6_Apu::addr_step; - if ( osc < Nes_Vrc6_Apu::osc_count && reg < Nes_Vrc6_Apu::reg_count ) - { - vrc6->write_osc( time(), osc, reg, data ); - return; - } - } - } - #endif - - // unmapped write - - #ifndef NDEBUG - { - // some games write to $8000 and $8001 repeatedly - if ( addr == 0x8000 || addr == 0x8001 ) return; - - // probably namco sound mistakenly turned on in mck - if ( addr == 0x4800 || addr == 0xF800 ) return; - - // memory mapper? - if ( addr == 0xFFF8 ) return; - - debug_printf( "write_unmapped( 0x%04X, 0x%02X )\n", (unsigned) addr, (unsigned) data ); - } - #endif -} - -blargg_err_t Nsf_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - memset( low_mem, 0, sizeof low_mem ); - memset( sram, 0, sizeof sram ); - - cpu::reset( unmapped_code ); // also maps low_mem - cpu::map_code( sram_addr, sizeof sram, sram ); - for ( int i = 0; i < bank_count; ++i ) - cpu_write( bank_select_addr + i, initial_banks [i] ); - - apu.reset( pal_only, (header_.speed_flags & 0x20) ? 0x3F : 0 ); - apu.write_register( 0, 0x4015, 0x0F ); - apu.write_register( 0, 0x4017, (header_.speed_flags & 0x10) ? 0x80 : 0 ); - #if !NSF_EMU_APU_ONLY - { - if ( namco ) namco->reset(); - if ( vrc6 ) vrc6 ->reset(); - if ( fme7 ) fme7 ->reset(); - } - #endif - - play_ready = 4; - play_extra = 0; - next_play = play_period / clock_divisor; - - saved_state.pc = badop_addr; - low_mem [0x1FF] = (badop_addr - 1) >> 8; - low_mem [0x1FE] = (badop_addr - 1) & 0xFF; - r.sp = 0xFD; - r.pc = init_addr; - r.a = track; - r.x = pal_only; - - return 0; -} - -blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int ) -{ - set_time( 0 ); - while ( time() < duration ) - { - nes_time_t end = min( (blip_time_t) next_play, duration ); - end = min( end, time() + 32767 ); // allows CPU to use 16-bit time delta - if ( cpu::run( end ) ) - { - if ( r.pc != badop_addr ) - { - set_warning( "Emulation error (illegal instruction)" ); - r.pc++; - } - else - { - play_ready = 1; - if ( saved_state.pc != badop_addr ) - { - cpu::r = saved_state; - saved_state.pc = badop_addr; - } - else - { - set_time( end ); - } - } - } - - if ( time() >= next_play ) - { - nes_time_t period = (play_period + play_extra) / clock_divisor; - play_extra = play_period - period * clock_divisor; - next_play += period; - if ( play_ready && !--play_ready ) - { - check( saved_state.pc == badop_addr ); - if ( r.pc != badop_addr ) - saved_state = cpu::r; - - r.pc = play_addr; - low_mem [0x100 + r.sp--] = (badop_addr - 1) >> 8; - low_mem [0x100 + r.sp--] = (badop_addr - 1) & 0xFF; - GME_FRAME_HOOK( this ); - } - } - } - - if ( cpu::error_count() ) - { - cpu::clear_error_count(); - set_warning( "Emulation error (illegal instruction)" ); - } - - duration = time(); - next_play -= duration; - check( next_play >= 0 ); - if ( next_play < 0 ) - next_play = 0; - - apu.end_frame( duration ); - - #if !NSF_EMU_APU_ONLY - { - if ( namco ) namco->end_frame( duration ); - if ( vrc6 ) vrc6 ->end_frame( duration ); - if ( fme7 ) fme7 ->end_frame( duration ); - } - #endif - - return 0; -} diff --git a/libraries/game-music-emu/gme/Nsf_Emu.h b/libraries/game-music-emu/gme/Nsf_Emu.h deleted file mode 100644 index e538b1b30..000000000 --- a/libraries/game-music-emu/gme/Nsf_Emu.h +++ /dev/null @@ -1,106 +0,0 @@ -// Nintendo NES/Famicom NSF music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef NSF_EMU_H -#define NSF_EMU_H - -#include "Classic_Emu.h" -#include "Nes_Apu.h" -#include "Nes_Cpu.h" - -class Nsf_Emu : private Nes_Cpu, public Classic_Emu { - typedef Nes_Cpu cpu; -public: - // Equalizer profiles for US NES and Japanese Famicom - static equalizer_t const nes_eq; - static equalizer_t const famicom_eq; - - // NSF file header - enum { header_size = 0x80 }; - struct header_t - { - char tag [5]; - byte vers; - byte track_count; - byte first_track; - byte load_addr [2]; - byte init_addr [2]; - byte play_addr [2]; - char game [32]; - char author [32]; - char copyright [32]; - byte ntsc_speed [2]; - byte banks [8]; - byte pal_speed [2]; - byte speed_flags; - byte chip_flags; - byte unused [4]; - }; - - // Header for currently loaded file - header_t const& header() const { return header_; } - - static gme_type_t static_type() { return gme_nsf_type; } - -public: - // deprecated - using Music_Emu::load; - blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader - { return load_remaining_( &h, sizeof h, in ); } - -public: - Nsf_Emu(); - ~Nsf_Emu(); - Nes_Apu* apu_() { return &apu; } -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_( Data_Reader& ); - blargg_err_t start_track_( int ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); - void unload(); -protected: - enum { bank_count = 8 }; - byte initial_banks [bank_count]; - nes_addr_t init_addr; - nes_addr_t play_addr; - double clock_rate_; - bool pal_only; - - // timing - Nes_Cpu::registers_t saved_state; - nes_time_t next_play; - nes_time_t play_period; - int play_extra; - int play_ready; - - enum { rom_begin = 0x8000 }; - enum { bank_select_addr = 0x5FF8 }; - enum { bank_size = 0x1000 }; - Rom_Data rom; - -public: private: friend class Nes_Cpu; - void cpu_jsr( nes_addr_t ); - int cpu_read( nes_addr_t ); - void cpu_write( nes_addr_t, int ); - void cpu_write_misc( nes_addr_t, int ); - enum { badop_addr = bank_select_addr }; - -private: - class Nes_Namco_Apu* namco; - class Nes_Vrc6_Apu* vrc6; - class Nes_Fme7_Apu* fme7; - Nes_Apu apu; - static int pcm_read( void*, nes_addr_t ); - blargg_err_t init_sound(); - - header_t header_; - - enum { sram_addr = 0x6000 }; - byte sram [0x2000]; - byte unmapped_code [Nes_Cpu::page_size + 8]; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Nsfe_Emu.cpp b/libraries/game-music-emu/gme/Nsfe_Emu.cpp deleted file mode 100644 index 035f99dee..000000000 --- a/libraries/game-music-emu/gme/Nsfe_Emu.cpp +++ /dev/null @@ -1,335 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Nsfe_Emu.h" - -#include "blargg_endian.h" -#include -#include - -/* 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 -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" - -Nsfe_Info::Nsfe_Info() { playlist_disabled = false; } - -Nsfe_Info::~Nsfe_Info() { } - -inline void Nsfe_Info::unload() -{ - track_name_data.clear(); - track_names.clear(); - playlist.clear(); - track_times.clear(); -} - -// TODO: if no playlist, treat as if there is a playlist that is just 1,2,3,4,5... ? -void Nsfe_Info::disable_playlist( bool b ) -{ - playlist_disabled = b; - info.track_count = playlist.size(); - if ( !info.track_count || playlist_disabled ) - info.track_count = actual_track_count_; -} - -int Nsfe_Info::remap_track( int track ) const -{ - if ( !playlist_disabled && (unsigned) track < playlist.size() ) - track = playlist [track]; - return track; -} - -// Read multiple strings and separate into individual strings -static blargg_err_t read_strs( Data_Reader& in, long size, blargg_vector& chars, - blargg_vector& strs ) -{ - RETURN_ERR( chars.resize( size + 1 ) ); - chars [size] = 0; // in case last string doesn't have terminator - RETURN_ERR( in.read( &chars [0], size ) ); - - RETURN_ERR( strs.resize( 128 ) ); - int count = 0; - for ( int i = 0; i < size; i++ ) - { - if ( (int) strs.size() <= count ) - RETURN_ERR( strs.resize( count * 2 ) ); - strs [count++] = &chars [i]; - while ( i < size && chars [i] ) - i++; - } - - return strs.resize( count ); -} - -// Copy in to out, where out has out_max characters allocated. Truncate to -// out_max - 1 characters. -static void copy_str( const char* in, char* out, int out_max ) -{ - out [out_max - 1] = 0; - strncpy( out, in, out_max - 1 ); -} - -struct nsfe_info_t -{ - byte load_addr [2]; - byte init_addr [2]; - byte play_addr [2]; - byte speed_flags; - byte chip_flags; - byte track_count; - byte first_track; - byte unused [6]; -}; - -blargg_err_t Nsfe_Info::load( Data_Reader& in, Nsf_Emu* nsf_emu ) -{ - int const nsfe_info_size = 16; - assert( offsetof (nsfe_info_t,unused [6]) == nsfe_info_size ); - - // check header - byte signature [4]; - blargg_err_t err = in.read( signature, sizeof signature ); - if ( err ) - return (err == in.eof_error ? gme_wrong_file_type : err); - if ( memcmp( signature, "NSFE", 4 ) ) - return gme_wrong_file_type; - - // free previous info - track_name_data.clear(); - track_names.clear(); - playlist.clear(); - track_times.clear(); - - // default nsf header - static const Nsf_Emu::header_t base_header = - { - {'N','E','S','M','\x1A'},// tag - 1, // version - 1, 1, // track count, first track - {0,0},{0,0},{0,0}, // addresses - "","","", // strings - {0x1A, 0x41}, // NTSC rate - {0,0,0,0,0,0,0,0}, // banks - {0x20, 0x4E}, // PAL rate - 0, 0, // flags - {0,0,0,0} // unused - }; - Nsf_Emu::header_t& header = info; - header = base_header; - - // parse tags - int phase = 0; - while ( phase != 3 ) - { - // read size and tag - byte block_header [2] [4]; - RETURN_ERR( in.read( block_header, sizeof block_header ) ); - blargg_long size = get_le32( block_header [0] ); - blargg_long tag = get_le32( block_header [1] ); - - if ( size < 0 ) - return "Corrupt file"; - - //debug_printf( "tag: %c%c%c%c\n", char(tag), char(tag>>8), char(tag>>16), char(tag>>24) ); - - switch ( tag ) - { - case BLARGG_4CHAR('O','F','N','I'): { - check( phase == 0 ); - if ( size < 8 ) - return "Corrupt file"; - - nsfe_info_t finfo; - finfo.track_count = 1; - finfo.first_track = 0; - - RETURN_ERR( in.read( &finfo, min( size, (blargg_long) nsfe_info_size ) ) ); - if ( size > nsfe_info_size ) - RETURN_ERR( in.skip( size - nsfe_info_size ) ); - phase = 1; - info.speed_flags = finfo.speed_flags; - info.chip_flags = finfo.chip_flags; - info.track_count = finfo.track_count; - this->actual_track_count_ = finfo.track_count; - info.first_track = finfo.first_track; - memcpy( info.load_addr, finfo.load_addr, 2 * 3 ); - break; - } - - case BLARGG_4CHAR('K','N','A','B'): - if ( size > (int) sizeof info.banks ) - return "Corrupt file"; - RETURN_ERR( in.read( info.banks, size ) ); - break; - - case BLARGG_4CHAR('h','t','u','a'): { - blargg_vector chars; - blargg_vector strs; - RETURN_ERR( read_strs( in, size, chars, strs ) ); - int n = strs.size(); - - if ( n > 3 ) - copy_str( strs [3], info.dumper, sizeof info.dumper ); - - if ( n > 2 ) - copy_str( strs [2], info.copyright, sizeof info.copyright ); - - if ( n > 1 ) - copy_str( strs [1], info.author, sizeof info.author ); - - if ( n > 0 ) - copy_str( strs [0], info.game, sizeof info.game ); - - break; - } - - case BLARGG_4CHAR('e','m','i','t'): - RETURN_ERR( track_times.resize( size / 4 ) ); - RETURN_ERR( in.read( track_times.begin(), track_times.size() * 4 ) ); - break; - - case BLARGG_4CHAR('l','b','l','t'): - RETURN_ERR( read_strs( in, size, track_name_data, track_names ) ); - break; - - case BLARGG_4CHAR('t','s','l','p'): - RETURN_ERR( playlist.resize( size ) ); - RETURN_ERR( in.read( &playlist [0], size ) ); - break; - - case BLARGG_4CHAR('A','T','A','D'): { - check( phase == 1 ); - phase = 2; - if ( !nsf_emu ) - { - RETURN_ERR( in.skip( size ) ); - } - else - { - Subset_Reader sub( &in, size ); // limit emu to nsf data - Remaining_Reader rem( &header, Nsf_Emu::header_size, &sub ); - RETURN_ERR( nsf_emu->load( rem ) ); - check( rem.remain() == 0 ); - } - break; - } - - case BLARGG_4CHAR('D','N','E','N'): - check( phase == 2 ); - phase = 3; - break; - - default: - // tags that can be skipped start with a lowercase character - check( islower( (tag >> 24) & 0xFF ) ); - RETURN_ERR( in.skip( size ) ); - break; - } - } - - return 0; -} - -blargg_err_t Nsfe_Info::track_info_( track_info_t* out, int track ) const -{ - int remapped = remap_track( track ); - if ( (unsigned) remapped < track_times.size() ) - { - long length = (int32_t) get_le32( track_times [remapped] ); - if ( length > 0 ) - out->length = length; - } - if ( (unsigned) remapped < track_names.size() ) - Gme_File::copy_field_( out->song, track_names [remapped] ); - - GME_COPY_FIELD( info, out, game ); - GME_COPY_FIELD( info, out, author ); - GME_COPY_FIELD( info, out, copyright ); - GME_COPY_FIELD( info, out, dumper ); - return 0; -} - -Nsfe_Emu::Nsfe_Emu() -{ - loading = false; - set_type( gme_nsfe_type ); -} - -Nsfe_Emu::~Nsfe_Emu() { } - -void Nsfe_Emu::unload() -{ - if ( !loading ) - info.unload(); // TODO: extremely hacky! - Nsf_Emu::unload(); -} - -blargg_err_t Nsfe_Emu::track_info_( track_info_t* out, int track ) const -{ - return info.track_info_( out, track ); -} - -struct Nsfe_File : Gme_Info_ -{ - Nsfe_Info info; - - Nsfe_File() { set_type( gme_nsfe_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - RETURN_ERR( info.load( in, 0 ) ); - info.disable_playlist( false ); - set_track_count( info.info.track_count ); - return 0; - } - - blargg_err_t track_info_( track_info_t* out, int track ) const - { - return info.track_info_( out, track ); - } -}; - -static Music_Emu* new_nsfe_emu () { return BLARGG_NEW Nsfe_Emu ; } -static Music_Emu* new_nsfe_file() { return BLARGG_NEW Nsfe_File; } - -static gme_type_t_ const gme_nsfe_type_ = { "Nintendo NES", 0, &new_nsfe_emu, &new_nsfe_file, "NSFE", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_nsfe_type = &gme_nsfe_type_; - - -blargg_err_t Nsfe_Emu::load_( Data_Reader& in ) -{ - if ( loading ) - return Nsf_Emu::load_( in ); - - // TODO: this hacky recursion-avoidance could have subtle problems - loading = true; - blargg_err_t err = info.load( in, this ); - loading = false; - disable_playlist( false ); - return err; -} - -void Nsfe_Emu::disable_playlist( bool b ) -{ - info.disable_playlist( b ); - set_track_count( info.info.track_count ); -} - -void Nsfe_Emu::clear_playlist_() -{ - disable_playlist(); - Nsf_Emu::clear_playlist_(); -} - -blargg_err_t Nsfe_Emu::start_track_( int track ) -{ - return Nsf_Emu::start_track_( info.remap_track( track ) ); -} diff --git a/libraries/game-music-emu/gme/Nsfe_Emu.h b/libraries/game-music-emu/gme/Nsfe_Emu.h deleted file mode 100644 index fd65f0af8..000000000 --- a/libraries/game-music-emu/gme/Nsfe_Emu.h +++ /dev/null @@ -1,68 +0,0 @@ -// Nintendo NES/Famicom NSFE music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef NSFE_EMU_H -#define NSFE_EMU_H - -#include "blargg_common.h" -#include "Nsf_Emu.h" - -// Allows reading info from NSFE file without creating emulator -class Nsfe_Info { -public: - blargg_err_t load( Data_Reader&, Nsf_Emu* ); - - struct info_t : Nsf_Emu::header_t - { - char game [256]; - char author [256]; - char copyright [256]; - char dumper [256]; - } info; - - void disable_playlist( bool = true ); - - blargg_err_t track_info_( track_info_t* out, int track ) const; - - int remap_track( int i ) const; - - void unload(); - - Nsfe_Info(); - ~Nsfe_Info(); -private: - blargg_vector track_name_data; - blargg_vector track_names; - blargg_vector playlist; - blargg_vector track_times; - int actual_track_count_; - bool playlist_disabled; -}; - -class Nsfe_Emu : public Nsf_Emu { -public: - static gme_type_t static_type() { return gme_nsfe_type; } - -public: - // deprecated - struct header_t { char tag [4]; }; - using Music_Emu::load; - blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader - { return load_remaining_( &h, sizeof h, in ); } - void disable_playlist( bool = true ); // use clear_playlist() - -public: - Nsfe_Emu(); - ~Nsfe_Emu(); -protected: - blargg_err_t load_( Data_Reader& ); - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t start_track_( int ); - void unload(); - void clear_playlist_(); -private: - Nsfe_Info info; - bool loading; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Sap_Apu.cpp b/libraries/game-music-emu/gme/Sap_Apu.cpp deleted file mode 100644 index 26fa2d13f..000000000 --- a/libraries/game-music-emu/gme/Sap_Apu.cpp +++ /dev/null @@ -1,334 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Sap_Apu.h" - -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -int const max_frequency = 12000; // pure waves above this frequency are silenced - -static void gen_poly( blargg_ulong mask, int count, byte* out ) -{ - blargg_ulong n = 1; - do - { - int bits = 0; - int b = 0; - do - { - // implemented using "Galios configuration" - bits |= (n & 1) << b; - n = (n >> 1) ^ (mask & -(n & 1)); - } - while ( b++ < 7 ); - *out++ = bits; - } - while ( --count ); -} - -// poly5 -int const poly5_len = (1 << 5) - 1; -blargg_ulong const poly5_mask = (1UL << poly5_len) - 1; -blargg_ulong const poly5 = 0x167C6EA1; - -inline blargg_ulong run_poly5( blargg_ulong in, int shift ) -{ - return (in << shift & poly5_mask) | (in >> (poly5_len - shift)); -} - -#define POLY_MASK( width, tap1, tap2 ) \ - ((1UL << (width - 1 - tap1)) | (1UL << (width - 1 - tap2))) - -Sap_Apu_Impl::Sap_Apu_Impl() -{ - gen_poly( POLY_MASK( 4, 1, 0 ), sizeof poly4, poly4 ); - gen_poly( POLY_MASK( 9, 5, 0 ), sizeof poly9, poly9 ); - gen_poly( POLY_MASK( 17, 5, 0 ), sizeof poly17, poly17 ); - - if ( 0 ) // comment out to recauculate poly5 constant - { - byte poly5 [4]; - gen_poly( POLY_MASK( 5, 2, 0 ), sizeof poly5, poly5 ); - blargg_ulong n = poly5 [3] * 0x1000000L + poly5 [2] * 0x10000L + - poly5 [1] * 0x100L + poly5 [0]; - blargg_ulong rev = n & 1; - for ( int i = 1; i < poly5_len; i++ ) - rev |= (n >> i & 1) << (poly5_len - i); - debug_printf( "poly5: 0x%08lX\n", rev ); - } -} - -Sap_Apu::Sap_Apu() -{ - impl = 0; - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, 0 ); -} - -void Sap_Apu::reset( Sap_Apu_Impl* new_impl ) -{ - impl = new_impl; - last_time = 0; - poly5_pos = 0; - poly4_pos = 0; - polym_pos = 0; - control = 0; - - for ( int i = 0; i < osc_count; i++ ) - memset( &oscs [i], 0, offsetof (osc_t,output) ); -} - -inline void Sap_Apu::calc_periods() -{ - // 15/64 kHz clock - int divider = 28; - if ( this->control & 1 ) - divider = 114; - - for ( int i = 0; i < osc_count; i++ ) - { - osc_t* const osc = &oscs [i]; - - int const osc_reload = osc->regs [0]; // cache - blargg_long period = (osc_reload + 1) * divider; - static byte const fast_bits [osc_count] = { 1 << 6, 1 << 4, 1 << 5, 1 << 3 }; - if ( this->control & fast_bits [i] ) - { - period = osc_reload + 4; - if ( i & 1 ) - { - period = osc_reload * 0x100L + osc [-1].regs [0] + 7; - if ( !(this->control & fast_bits [i - 1]) ) - period = (period - 6) * divider; - - if ( (osc [-1].regs [1] & 0x1F) > 0x10 ) - debug_printf( "Use of slave channel in 16-bit mode not supported\n" ); - } - } - osc->period = period; - } -} - -void Sap_Apu::run_until( blip_time_t end_time ) -{ - calc_periods(); - Sap_Apu_Impl* const impl = this->impl; // cache - - // 17/9-bit poly selection - byte const* polym = impl->poly17; - int polym_len = poly17_len; - if ( this->control & 0x80 ) - { - polym_len = poly9_len; - polym = impl->poly9; - } - polym_pos %= polym_len; - - for ( int i = 0; i < osc_count; i++ ) - { - osc_t* const osc = &oscs [i]; - blip_time_t time = last_time + osc->delay; - blip_time_t const period = osc->period; - - // output - Blip_Buffer* output = osc->output; - if ( output ) - { - output->set_modified(); - - int const osc_control = osc->regs [1]; // cache - int volume = (osc_control & 0x0F) * 2; - if ( !volume || osc_control & 0x10 || // silent, DAC mode, or inaudible frequency - ((osc_control & 0xA0) == 0xA0 && period < 1789773 / 2 / max_frequency) ) - { - if ( !(osc_control & 0x10) ) - volume >>= 1; // inaudible frequency = half volume - - int delta = volume - osc->last_amp; - if ( delta ) - { - osc->last_amp = volume; - impl->synth.offset( last_time, delta, output ); - } - - // TODO: doesn't maintain high pass flip-flop (very minor issue) - } - else - { - // high pass - static byte const hipass_bits [osc_count] = { 1 << 2, 1 << 1, 0, 0 }; - blip_time_t period2 = 0; // unused if no high pass - blip_time_t time2 = end_time; - if ( this->control & hipass_bits [i] ) - { - period2 = osc [2].period; - time2 = last_time + osc [2].delay; - if ( osc->invert ) - { - // trick inner wave loop into inverting output - osc->last_amp -= volume; - volume = -volume; - } - } - - if ( time < end_time || time2 < end_time ) - { - // poly source - static byte const poly1 [] = { 0x55, 0x55 }; // square wave - byte const* poly = poly1; - int poly_len = 8 * sizeof poly1; // can be just 2 bits, but this is faster - int poly_pos = osc->phase & 1; - int poly_inc = 1; - if ( !(osc_control & 0x20) ) - { - poly = polym; - poly_len = polym_len; - poly_pos = polym_pos; - if ( osc_control & 0x40 ) - { - poly = impl->poly4; - poly_len = poly4_len; - poly_pos = poly4_pos; - } - poly_inc = period % poly_len; - poly_pos = (poly_pos + osc->delay) % poly_len; - } - poly_inc -= poly_len; // allows more optimized inner loop below - - // square/poly5 wave - blargg_ulong wave = poly5; - check( poly5 & 1 ); // low bit is set for pure wave - int poly5_inc = 0; - if ( !(osc_control & 0x80) ) - { - wave = run_poly5( wave, (osc->delay + poly5_pos) % poly5_len ); - poly5_inc = period % poly5_len; - } - - // Run wave and high pass interleved with each catching up to the other. - // Disabled high pass has no performance effect since inner wave loop - // makes no compromise for high pass, and only runs once in that case. - int osc_last_amp = osc->last_amp; - do - { - // run high pass - if ( time2 < time ) - { - int delta = -osc_last_amp; - if ( volume < 0 ) - delta += volume; - if ( delta ) - { - osc_last_amp += delta - volume; - volume = -volume; - impl->synth.offset( time2, delta, output ); - } - } - while ( time2 <= time ) // must advance *past* time to avoid hang - time2 += period2; - - // run wave - blip_time_t end = end_time; - if ( end > time2 ) - end = time2; - while ( time < end ) - { - if ( wave & 1 ) - { - int amp = volume & -(poly [poly_pos >> 3] >> (poly_pos & 7) & 1); - if ( (poly_pos += poly_inc) < 0 ) - poly_pos += poly_len; - int delta = amp - osc_last_amp; - if ( delta ) - { - osc_last_amp = amp; - impl->synth.offset( time, delta, output ); - } - } - wave = run_poly5( wave, poly5_inc ); - time += period; - } - } - while ( time < end_time || time2 < end_time ); - - osc->phase = poly_pos; - osc->last_amp = osc_last_amp; - } - - osc->invert = 0; - if ( volume < 0 ) - { - // undo inversion trickery - osc->last_amp -= volume; - osc->invert = 1; - } - } - } - - // maintain divider - blip_time_t remain = end_time - time; - if ( remain > 0 ) - { - blargg_long count = (remain + period - 1) / period; - osc->phase ^= count; - time += count * period; - } - osc->delay = time - end_time; - } - - // advance polies - blip_time_t duration = end_time - last_time; - last_time = end_time; - poly4_pos = (poly4_pos + duration) % poly4_len; - poly5_pos = (poly5_pos + duration) % poly5_len; - polym_pos += duration; // will get %'d on next call -} - -void Sap_Apu::write_data( blip_time_t time, unsigned addr, int data ) -{ - run_until( time ); - int i = (addr ^ 0xD200) >> 1; - if ( i < osc_count ) - { - oscs [i].regs [addr & 1] = data; - } - else if ( addr == 0xD208 ) - { - control = data; - } - else if ( addr == 0xD209 ) - { - oscs [0].delay = 0; - oscs [1].delay = 0; - oscs [2].delay = 0; - oscs [3].delay = 0; - } - /* - // TODO: are polynomials reset in this case? - else if ( addr == 0xD20F ) - { - if ( (data & 3) == 0 ) - polym_pos = 0; - } - */ -} - -void Sap_Apu::end_frame( blip_time_t end_time ) -{ - if ( end_time > last_time ) - run_until( end_time ); - - last_time -= end_time; -} diff --git a/libraries/game-music-emu/gme/Sap_Apu.h b/libraries/game-music-emu/gme/Sap_Apu.h deleted file mode 100644 index 1b67571bc..000000000 --- a/libraries/game-music-emu/gme/Sap_Apu.h +++ /dev/null @@ -1,77 +0,0 @@ -// Atari POKEY sound chip emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef SAP_APU_H -#define SAP_APU_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -class Sap_Apu_Impl; - -class Sap_Apu { -public: - enum { osc_count = 4 }; - void osc_output( int index, Blip_Buffer* ); - - void reset( Sap_Apu_Impl* ); - - enum { start_addr = 0xD200 }; - enum { end_addr = 0xD209 }; - void write_data( blip_time_t, unsigned addr, int data ); - - void end_frame( blip_time_t ); - -public: - Sap_Apu(); -private: - struct osc_t - { - unsigned char regs [2]; - unsigned char phase; - unsigned char invert; - int last_amp; - blip_time_t delay; - blip_time_t period; // always recalculated before use; here for convenience - Blip_Buffer* output; - }; - osc_t oscs [osc_count]; - Sap_Apu_Impl* impl; - blip_time_t last_time; - int poly5_pos; - int poly4_pos; - int polym_pos; - int control; - - void calc_periods(); - void run_until( blip_time_t ); - - enum { poly4_len = (1L << 4) - 1 }; - enum { poly9_len = (1L << 9) - 1 }; - enum { poly17_len = (1L << 17) - 1 }; - friend class Sap_Apu_Impl; -}; - -// Common tables and Blip_Synth that can be shared among multiple Sap_Apu objects -class Sap_Apu_Impl { -public: - Blip_Synth synth; - - Sap_Apu_Impl(); - void volume( double d ) { synth.volume( 1.0 / Sap_Apu::osc_count / 30 * d ); } - -private: - typedef unsigned char byte; - byte poly4 [Sap_Apu::poly4_len / 8 + 1]; - byte poly9 [Sap_Apu::poly9_len / 8 + 1]; - byte poly17 [Sap_Apu::poly17_len / 8 + 1]; - friend class Sap_Apu; -}; - -inline void Sap_Apu::osc_output( int i, Blip_Buffer* b ) -{ - assert( (unsigned) i < osc_count ); - oscs [i].output = b; -} - -#endif diff --git a/libraries/game-music-emu/gme/Sap_Cpu.cpp b/libraries/game-music-emu/gme/Sap_Cpu.cpp deleted file mode 100644 index 76ae277ad..000000000 --- a/libraries/game-music-emu/gme/Sap_Cpu.cpp +++ /dev/null @@ -1,1004 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Sap_Cpu.h" - -#include -#include "blargg_endian.h" - -//#include "nes_cpu_log.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -#define FLUSH_TIME() (void) (s.time = s_time) -#define CACHE_TIME() (void) (s_time = s.time) - -#include "sap_cpu_io.h" - -#ifndef CPU_DONE - #define CPU_DONE( cpu, time, result_out ) { result_out = -1; } -#endif - -#include "blargg_source.h" - -int const st_n = 0x80; -int const st_v = 0x40; -int const st_r = 0x20; -int const st_b = 0x10; -int const st_d = 0x08; -int const st_i = 0x04; -int const st_z = 0x02; -int const st_c = 0x01; - -void Sap_Cpu::reset( void* new_mem ) -{ - check( state == &state_ ); - state = &state_; - mem = (uint8_t*) new_mem; - r.status = st_i; - r.sp = 0xFF; - r.pc = 0; - r.a = 0; - r.x = 0; - r.y = 0; - state_.time = 0; - state_.base = 0; - irq_time_ = future_sap_time; - end_time_ = future_sap_time; - - blargg_verify_byte_order(); -} - -#define TIME (s_time + s.base) -#define READ( addr ) CPU_READ( this, (addr), TIME ) -#define WRITE( addr, data ) {CPU_WRITE( this, (addr), (data), TIME );} -#define READ_LOW( addr ) (mem [int (addr)]) -#define WRITE_LOW( addr, data ) (void) (READ_LOW( addr ) = (data)) -#define READ_PROG( addr ) (READ_LOW( addr )) - -#define SET_SP( v ) (sp = ((v) + 1) | 0x100) -#define GET_SP() ((sp - 1) & 0xFF) -#define PUSH( v ) ((sp = (sp - 1) | 0x100), WRITE_LOW( sp, v )) - -bool Sap_Cpu::run( sap_time_t end_time ) -{ - bool illegal_encountered = false; - set_end_time( end_time ); - state_t s = this->state_; - this->state = &s; - int32_t s_time = s.time; - uint8_t* const mem = this->mem; // cache - - // registers - uint16_t pc = r.pc; - uint8_t a = r.a; - uint8_t x = r.x; - uint8_t y = r.y; - uint16_t sp; - SET_SP( r.sp ); - - // status flags - #define IS_NEG (nz & 0x8080) - - #define CALC_STATUS( out ) do {\ - out = status & (st_v | st_d | st_i);\ - out |= ((nz >> 8) | nz) & st_n;\ - out |= c >> 8 & st_c;\ - if ( !(nz & 0xFF) ) out |= st_z;\ - } while ( 0 ) - - #define SET_STATUS( in ) do {\ - status = in & (st_v | st_d | st_i);\ - nz = in << 8;\ - c = nz;\ - nz |= ~in & st_z;\ - } while ( 0 ) - - uint8_t status; - uint16_t c; // carry set if (c & 0x100) != 0 - uint16_t nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x8080) != 0 - { - uint8_t temp = r.status; - SET_STATUS( temp ); - } - - goto loop; -dec_clock_loop: - s_time--; -loop: - - #ifndef NDEBUG - { - sap_time_t correct = end_time_; - if ( !(status & st_i) && correct > irq_time_ ) - correct = irq_time_; - check( s.base == correct ); - } - #endif - - check( (unsigned) GET_SP() < 0x100 ); - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - uint8_t opcode = mem [pc]; - pc++; - uint8_t const* instr = mem + pc; - - static uint8_t const clock_table [256] = - {// 0 1 2 3 4 5 6 7 8 9 A B C D E F - 0,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,// 0 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 1 - 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,// 2 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 3 - 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,// 4 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 5 - 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,// 6 - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// 7 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// 8 - 3,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,// 9 - 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,// A - 3,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,// B - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// C - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,// D - 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,// E - 3,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 // F - }; // 0x00 was 7 - - uint16_t data; - data = clock_table [opcode]; - if ( (s_time += data) >= 0 ) - goto possibly_out_of_time; -almost_out_of_time: - - data = *instr; - - #ifdef NES_CPU_LOG_H - nes_cpu_log( "cpu_log", pc - 1, opcode, instr [0], instr [1] ); - #endif - - switch ( opcode ) - { -possibly_out_of_time: - if ( s_time < (int) data ) - goto almost_out_of_time; - s_time -= data; - goto out_of_time; - -// Macros - -#define GET_MSB() (instr [1]) -#define ADD_PAGE() (pc++, data += 0x100 * GET_MSB()) -#define GET_ADDR() GET_LE16( instr ) - -#define NO_PAGE_CROSSING( lsb ) -#define HANDLE_PAGE_CROSSING( lsb ) s_time += (lsb) >> 8; - -#define INC_DEC_XY( reg, n ) reg = uint8_t (nz = reg + n); goto loop; - -#define IND_Y( cross, out ) {\ - uint16_t temp = READ_LOW( data ) + y;\ - out = temp + 0x100 * READ_LOW( uint8_t (data + 1) );\ - cross( temp );\ - } - -#define IND_X( out ) {\ - uint16_t temp = data + x;\ - out = 0x100 * READ_LOW( uint8_t (temp + 1) ) + READ_LOW( uint8_t (temp) );\ - } - -#define ARITH_ADDR_MODES( op )\ -case op - 0x04: /* (ind,x) */\ - IND_X( data )\ - goto ptr##op;\ -case op + 0x0C: /* (ind),y */\ - IND_Y( HANDLE_PAGE_CROSSING, data )\ - goto ptr##op;\ -case op + 0x10: /* zp,X */\ - data = uint8_t (data + x);\ -case op + 0x00: /* zp */\ - data = READ_LOW( data );\ - goto imm##op;\ -case op + 0x14: /* abs,Y */\ - data += y;\ - goto ind##op;\ -case op + 0x18: /* abs,X */\ - data += x;\ -ind##op:\ - HANDLE_PAGE_CROSSING( data );\ -case op + 0x08: /* abs */\ - ADD_PAGE();\ -ptr##op:\ - FLUSH_TIME();\ - data = READ( data );\ - CACHE_TIME();\ -case op + 0x04: /* imm */\ -imm##op: - -// TODO: more efficient way to handle negative branch that wraps PC around -#define BRANCH( cond )\ -{\ - int16_t offset = (int8_t) data;\ - uint16_t extra_clock = (++pc & 0xFF) + offset;\ - if ( !(cond) ) goto dec_clock_loop;\ - pc += offset;\ - s_time += extra_clock >> 8 & 1;\ - goto loop;\ -} - -// Often-Used - - case 0xB5: // LDA zp,x - a = nz = READ_LOW( uint8_t (data + x) ); - pc++; - goto loop; - - case 0xA5: // LDA zp - a = nz = READ_LOW( data ); - pc++; - goto loop; - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ); - - case 0x20: { // JSR - uint16_t temp = pc + 1; - pc = GET_ADDR(); - WRITE_LOW( 0x100 | (sp - 1), temp >> 8 ); - sp = (sp - 2) | 0x100; - WRITE_LOW( sp, temp ); - goto loop; - } - - case 0x4C: // JMP abs - pc = GET_ADDR(); - goto loop; - - case 0xE8: // INX - INC_DEC_XY( x, 1 ) - - case 0x10: // BPL - BRANCH( !IS_NEG ) - - ARITH_ADDR_MODES( 0xC5 ) // CMP - nz = a - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x30: // BMI - BRANCH( IS_NEG ) - - case 0xF0: // BEQ - BRANCH( !(uint8_t) nz ); - - case 0x95: // STA zp,x - data = uint8_t (data + x); - case 0x85: // STA zp - pc++; - WRITE_LOW( data, a ); - goto loop; - - case 0xC8: // INY - INC_DEC_XY( y, 1 ) - - case 0xA8: // TAY - y = a; - nz = a; - goto loop; - - case 0x98: // TYA - a = y; - nz = y; - goto loop; - - case 0xAD:{// LDA abs - unsigned addr = GET_ADDR(); - pc += 2; - nz = READ( addr ); - a = nz; - goto loop; - } - - case 0x60: // RTS - pc = 1 + READ_LOW( sp ); - pc += 0x100 * READ_LOW( 0x100 | (sp - 0xFF) ); - sp = (sp - 0xFE) | 0x100; - goto loop; - - { - uint16_t addr; - - case 0x99: // STA abs,Y - addr = y + GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, a ); - goto loop; - } - goto sta_ptr; - - case 0x8D: // STA abs - addr = GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, a ); - goto loop; - } - goto sta_ptr; - - case 0x9D: // STA abs,X (slightly more common than STA abs) - addr = x + GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, a ); - goto loop; - } - sta_ptr: - FLUSH_TIME(); - WRITE( addr, a ); - CACHE_TIME(); - goto loop; - - case 0x91: // STA (ind),Y - IND_Y( NO_PAGE_CROSSING, addr ) - pc++; - goto sta_ptr; - - case 0x81: // STA (ind,X) - IND_X( addr ) - pc++; - goto sta_ptr; - - } - - case 0xA9: // LDA #imm - pc++; - a = data; - nz = data; - goto loop; - - // common read instructions - { - uint16_t addr; - - case 0xA1: // LDA (ind,X) - IND_X( addr ) - pc++; - goto a_nz_read_addr; - - case 0xB1:// LDA (ind),Y - addr = READ_LOW( data ) + y; - HANDLE_PAGE_CROSSING( addr ); - addr += 0x100 * READ_LOW( (uint8_t) (data + 1) ); - pc++; - a = nz = READ_PROG( addr ); - if ( (addr ^ 0x8000) <= 0x9FFF ) - goto loop; - goto a_nz_read_addr; - - case 0xB9: // LDA abs,Y - HANDLE_PAGE_CROSSING( data + y ); - addr = GET_ADDR() + y; - pc += 2; - a = nz = READ_PROG( addr ); - if ( (addr ^ 0x8000) <= 0x9FFF ) - goto loop; - goto a_nz_read_addr; - - case 0xBD: // LDA abs,X - HANDLE_PAGE_CROSSING( data + x ); - addr = GET_ADDR() + x; - pc += 2; - a = nz = READ_PROG( addr ); - if ( (addr ^ 0x8000) <= 0x9FFF ) - goto loop; - a_nz_read_addr: - FLUSH_TIME(); - a = nz = READ( addr ); - CACHE_TIME(); - goto loop; - - } - -// Branch - - case 0x50: // BVC - BRANCH( !(status & st_v) ) - - case 0x70: // BVS - BRANCH( status & st_v ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - -// Load/store - - case 0x94: // STY zp,x - data = uint8_t (data + x); - case 0x84: // STY zp - pc++; - WRITE_LOW( data, y ); - goto loop; - - case 0x96: // STX zp,y - data = uint8_t (data + y); - case 0x86: // STX zp - pc++; - WRITE_LOW( data, x ); - goto loop; - - case 0xB6: // LDX zp,y - data = uint8_t (data + y); - case 0xA6: // LDX zp - data = READ_LOW( data ); - case 0xA2: // LDX #imm - pc++; - x = data; - nz = data; - goto loop; - - case 0xB4: // LDY zp,x - data = uint8_t (data + x); - case 0xA4: // LDY zp - data = READ_LOW( data ); - case 0xA0: // LDY #imm - pc++; - y = data; - nz = data; - goto loop; - - case 0xBC: // LDY abs,X - data += x; - HANDLE_PAGE_CROSSING( data ); - case 0xAC:{// LDY abs - unsigned addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - y = nz = READ( addr ); - CACHE_TIME(); - goto loop; - } - - case 0xBE: // LDX abs,y - data += y; - HANDLE_PAGE_CROSSING( data ); - case 0xAE:{// LDX abs - unsigned addr = data + 0x100 * GET_MSB(); - pc += 2; - FLUSH_TIME(); - x = nz = READ( addr ); - CACHE_TIME(); - goto loop; - } - - { - uint8_t temp; - case 0x8C: // STY abs - temp = y; - goto store_abs; - - case 0x8E: // STX abs - temp = x; - store_abs: - unsigned addr = GET_ADDR(); - pc += 2; - if ( addr <= 0x7FF ) - { - WRITE_LOW( addr, temp ); - goto loop; - } - FLUSH_TIME(); - WRITE( addr, temp ); - CACHE_TIME(); - goto loop; - } - -// Compare - - case 0xEC:{// CPX abs - unsigned addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ( addr ); - CACHE_TIME(); - goto cpx_data; - } - - case 0xE4: // CPX zp - data = READ_LOW( data ); - case 0xE0: // CPX #imm - cpx_data: - nz = x - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0xCC:{// CPY abs - unsigned addr = GET_ADDR(); - pc++; - FLUSH_TIME(); - data = READ( addr ); - CACHE_TIME(); - goto cpy_data; - } - - case 0xC4: // CPY zp - data = READ_LOW( data ); - case 0xC0: // CPY #imm - cpy_data: - nz = y - data; - pc++; - c = ~nz; - nz &= 0xFF; - goto loop; - -// Logical - - ARITH_ADDR_MODES( 0x25 ) // AND - nz = (a &= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x45 ) // EOR - nz = (a ^= data); - pc++; - goto loop; - - ARITH_ADDR_MODES( 0x05 ) // ORA - nz = (a |= data); - pc++; - goto loop; - - case 0x2C:{// BIT abs - unsigned addr = GET_ADDR(); - pc += 2; - status &= ~st_v; - nz = READ( addr ); - status |= nz & st_v; - if ( a & nz ) - goto loop; - nz <<= 8; // result must be zero, even if N bit is set - goto loop; - } - - case 0x24: // BIT zp - nz = READ_LOW( data ); - pc++; - status &= ~st_v; - status |= nz & st_v; - if ( a & nz ) - goto loop; - nz <<= 8; // result must be zero, even if N bit is set - goto loop; - -// Add/subtract - - ARITH_ADDR_MODES( 0xE5 ) // SBC - case 0xEB: // unofficial equivalent - data ^= 0xFF; - goto adc_imm; - - ARITH_ADDR_MODES( 0x65 ) // ADC - adc_imm: { - check( !(status & st_d) ); - int16_t carry = c >> 8 & 1; - int16_t ov = (a ^ 0x80) + carry + (int8_t) data; // sign-extend - status &= ~st_v; - status |= ov >> 2 & 0x40; - c = nz = a + data + carry; - pc++; - a = (uint8_t) nz; - goto loop; - } - -// Shift/rotate - - case 0x4A: // LSR A - c = 0; - case 0x6A: // ROR A - nz = c >> 1 & 0x80; - c = a << 8; - nz |= a >> 1; - a = nz; - goto loop; - - case 0x0A: // ASL A - nz = a << 1; - c = nz; - a = (uint8_t) nz; - goto loop; - - case 0x2A: { // ROL A - nz = a << 1; - int16_t temp = c >> 8 & 1; - c = nz; - nz |= temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x5E: // LSR abs,X - data += x; - case 0x4E: // LSR abs - c = 0; - case 0x6E: // ROR abs - ror_abs: { - ADD_PAGE(); - FLUSH_TIME(); - int temp = READ( data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - goto rotate_common; - } - - case 0x3E: // ROL abs,X - data += x; - goto rol_abs; - - case 0x1E: // ASL abs,X - data += x; - case 0x0E: // ASL abs - c = 0; - case 0x2E: // ROL abs - rol_abs: - ADD_PAGE(); - nz = c >> 8 & 1; - FLUSH_TIME(); - nz |= (c = READ( data ) << 1); - rotate_common: - pc++; - WRITE( data, (uint8_t) nz ); - CACHE_TIME(); - goto loop; - - case 0x7E: // ROR abs,X - data += x; - goto ror_abs; - - case 0x76: // ROR zp,x - data = uint8_t (data + x); - goto ror_zp; - - case 0x56: // LSR zp,x - data = uint8_t (data + x); - case 0x46: // LSR zp - c = 0; - case 0x66: // ROR zp - ror_zp: { - int temp = READ_LOW( data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - goto write_nz_zp; - } - - case 0x36: // ROL zp,x - data = uint8_t (data + x); - goto rol_zp; - - case 0x16: // ASL zp,x - data = uint8_t (data + x); - case 0x06: // ASL zp - c = 0; - case 0x26: // ROL zp - rol_zp: - nz = c >> 8 & 1; - nz |= (c = READ_LOW( data ) << 1); - goto write_nz_zp; - -// Increment/decrement - - case 0xCA: // DEX - INC_DEC_XY( x, -1 ) - - case 0x88: // DEY - INC_DEC_XY( y, -1 ) - - case 0xF6: // INC zp,x - data = uint8_t (data + x); - case 0xE6: // INC zp - nz = 1; - goto add_nz_zp; - - case 0xD6: // DEC zp,x - data = uint8_t (data + x); - case 0xC6: // DEC zp - nz = (uint16_t) -1; - add_nz_zp: - nz += READ_LOW( data ); - write_nz_zp: - pc++; - WRITE_LOW( data, nz ); - goto loop; - - case 0xFE: // INC abs,x - data = x + GET_ADDR(); - goto inc_ptr; - - case 0xEE: // INC abs - data = GET_ADDR(); - inc_ptr: - nz = 1; - goto inc_common; - - case 0xDE: // DEC abs,x - data = x + GET_ADDR(); - goto dec_ptr; - - case 0xCE: // DEC abs - data = GET_ADDR(); - dec_ptr: - nz = (uint16_t) -1; - inc_common: - FLUSH_TIME(); - nz += READ( data ); - pc += 2; - WRITE( data, (uint8_t) nz ); - CACHE_TIME(); - goto loop; - -// Transfer - - case 0xAA: // TAX - x = a; - nz = a; - goto loop; - - case 0x8A: // TXA - a = x; - nz = x; - goto loop; - - case 0x9A: // TXS - SET_SP( x ); // verified (no flag change) - goto loop; - - case 0xBA: // TSX - x = nz = GET_SP(); - goto loop; - -// Stack - - case 0x48: // PHA - PUSH( a ); // verified - goto loop; - - case 0x68: // PLA - a = nz = READ_LOW( sp ); - sp = (sp - 0xFF) | 0x100; - goto loop; - - case 0x40:{// RTI - uint8_t temp = READ_LOW( sp ); - pc = READ_LOW( 0x100 | (sp - 0xFF) ); - pc |= READ_LOW( 0x100 | (sp - 0xFE) ) * 0x100; - sp = (sp - 0xFD) | 0x100; - data = status; - SET_STATUS( temp ); - this->r.status = status; // update externally-visible I flag - if ( (data ^ status) & st_i ) - { - sap_time_t new_time = end_time_; - if ( !(status & st_i) && new_time > irq_time_ ) - new_time = irq_time_; - blargg_long delta = s.base - new_time; - s.base = new_time; - s_time += delta; - } - goto loop; - } - - case 0x28:{// PLP - uint8_t temp = READ_LOW( sp ); - sp = (sp - 0xFF) | 0x100; - uint8_t changed = status ^ temp; - SET_STATUS( temp ); - if ( !(changed & st_i) ) - goto loop; // I flag didn't change - if ( status & st_i ) - goto handle_sei; - goto handle_cli; - } - - case 0x08: { // PHP - uint8_t temp; - CALC_STATUS( temp ); - PUSH( temp | (st_b | st_r) ); - goto loop; - } - - case 0x6C:{// JMP (ind) - data = GET_ADDR(); - pc = READ_PROG( data ); - data = (data & 0xFF00) | ((data + 1) & 0xFF); - pc |= 0x100 * READ_PROG( data ); - goto loop; - } - - case 0x00: // BRK - goto handle_brk; - -// Flags - - case 0x38: // SEC - c = (uint16_t) ~0; - goto loop; - - case 0x18: // CLC - c = 0; - goto loop; - - case 0xB8: // CLV - status &= ~st_v; - goto loop; - - case 0xD8: // CLD - status &= ~st_d; - goto loop; - - case 0xF8: // SED - status |= st_d; - goto loop; - - case 0x58: // CLI - if ( !(status & st_i) ) - goto loop; - status &= ~st_i; - handle_cli: { - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - irq_time_; - if ( delta <= 0 ) - { - if ( TIME < irq_time_ ) - goto loop; - goto delayed_cli; - } - s.base = irq_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - - if ( delta >= s_time + 1 ) - { - // delayed irq until after next instruction - s.base += s_time + 1; - s_time = -1; - irq_time_ = s.base; // TODO: remove, as only to satisfy debug check in loop - goto loop; - } - delayed_cli: - debug_printf( "Delayed CLI not emulated\n" ); - goto loop; - } - - case 0x78: // SEI - if ( status & st_i ) - goto loop; - status |= st_i; - handle_sei: { - this->r.status = status; // update externally-visible I flag - blargg_long delta = s.base - end_time_; - s.base = end_time_; - s_time += delta; - if ( s_time < 0 ) - goto loop; - debug_printf( "Delayed SEI not emulated\n" ); - goto loop; - } - -// Unofficial - - // SKW - Skip word - case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC: - HANDLE_PAGE_CROSSING( data + x ); - case 0x0C: - pc++; - // SKB - Skip byte - case 0x74: case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64: - case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2: case 0xF4: - pc++; - goto loop; - - // NOP - case 0xEA: case 0x1A: case 0x3A: case 0x5A: case 0x7A: case 0xDA: case 0xFA: - goto loop; - -// Unimplemented - - // halt - //case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: - //case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2: - - default: - illegal_encountered = true; - pc--; - goto stop; - } - assert( false ); - - int result_; -handle_brk: - if ( (pc - 1) >= idle_addr ) - goto idle_done; - pc++; - result_ = 4; - debug_printf( "BRK executed\n" ); - -interrupt: - { - s_time += 7; - - WRITE_LOW( 0x100 | (sp - 1), pc >> 8 ); - WRITE_LOW( 0x100 | (sp - 2), pc ); - pc = GET_LE16( &READ_PROG( 0xFFFA ) + result_ ); - - sp = (sp - 3) | 0x100; - uint8_t temp; - CALC_STATUS( temp ); - temp |= st_r; - if ( result_ ) - temp |= st_b; // TODO: incorrectly sets B flag for IRQ - WRITE_LOW( sp, temp ); - - status &= ~st_d; - status |= st_i; - this->r.status = status; // update externally-visible I flag - - blargg_long delta = s.base - end_time_; - s.base = end_time_; - s_time += delta; - goto loop; - } - -idle_done: - //s_time = 0; - pc--; - goto stop; -out_of_time: - pc--; - FLUSH_TIME(); - CPU_DONE( this, TIME, result_ ); - CACHE_TIME(); - if ( result_ >= 0 ) - goto interrupt; - if ( s_time < 0 ) - goto loop; - -stop: - - s.time = s_time; - - r.pc = pc; - r.sp = GET_SP(); - r.a = a; - r.x = x; - r.y = y; - - { - uint8_t temp; - CALC_STATUS( temp ); - r.status = temp; - } - - this->state_ = s; - this->state = &this->state_; - - return illegal_encountered; -} - diff --git a/libraries/game-music-emu/gme/Sap_Cpu.h b/libraries/game-music-emu/gme/Sap_Cpu.h deleted file mode 100644 index fdfb9a310..000000000 --- a/libraries/game-music-emu/gme/Sap_Cpu.h +++ /dev/null @@ -1,81 +0,0 @@ -// Atari 6502 CPU emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef SAP_CPU_H -#define SAP_CPU_H - -#include "blargg_common.h" - -typedef blargg_long sap_time_t; // clock cycle count -typedef unsigned sap_addr_t; // 16-bit address -enum { future_sap_time = INT_MAX / 2 + 1 }; - -class Sap_Cpu { -public: - // Clear all registers and keep pointer to 64K memory passed in - void reset( void* mem_64k ); - - // Run until specified time is reached. Returns true if suspicious/unsupported - // instruction was encountered at any point during run. - bool run( sap_time_t end_time ); - - // Registers are not updated until run() returns (except I flag in status) - struct registers_t { - uint16_t pc; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t status; - uint8_t sp; - }; - registers_t r; - - enum { idle_addr = 0xFEFF }; - - // Time of beginning of next instruction to be executed - sap_time_t time() const { return state->time + state->base; } - void set_time( sap_time_t t ) { state->time = t - state->base; } - void adjust_time( int delta ) { state->time += delta; } - - sap_time_t irq_time() const { return irq_time_; } - void set_irq_time( sap_time_t ); - - sap_time_t end_time() const { return end_time_; } - void set_end_time( sap_time_t ); - -public: - Sap_Cpu() { state = &state_; } - enum { irq_inhibit = 0x04 }; -private: - struct state_t { - sap_time_t base; - sap_time_t time; - }; - state_t* state; // points to state_ or a local copy within run() - state_t state_; - sap_time_t irq_time_; - sap_time_t end_time_; - uint8_t* mem; - - inline sap_time_t update_end_time( sap_time_t end, sap_time_t irq ); -}; - -inline sap_time_t Sap_Cpu::update_end_time( sap_time_t t, sap_time_t irq ) -{ - if ( irq < t && !(r.status & irq_inhibit) ) t = irq; - sap_time_t delta = state->base - t; - state->base = t; - return delta; -} - -inline void Sap_Cpu::set_irq_time( sap_time_t t ) -{ - state->time += update_end_time( end_time_, (irq_time_ = t) ); -} - -inline void Sap_Cpu::set_end_time( sap_time_t t ) -{ - state->time += update_end_time( (end_time_ = t), irq_time_ ); -} - -#endif diff --git a/libraries/game-music-emu/gme/Sap_Emu.cpp b/libraries/game-music-emu/gme/Sap_Emu.cpp deleted file mode 100644 index dc5d666d6..000000000 --- a/libraries/game-music-emu/gme/Sap_Emu.cpp +++ /dev/null @@ -1,443 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Sap_Emu.h" - -#include "blargg_endian.h" -#include - -/* Copyright (C) 2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -long const base_scanline_period = 114; - -Sap_Emu::Sap_Emu() -{ - set_type( gme_sap_type ); - - static const char* const names [Sap_Apu::osc_count * 2] = { - "Wave 1", "Wave 2", "Wave 3", "Wave 4", - "Wave 5", "Wave 6", "Wave 7", "Wave 8", - }; - set_voice_names( names ); - - static int const types [Sap_Apu::osc_count * 2] = { - wave_type | 1, wave_type | 2, wave_type | 3, wave_type | 0, - wave_type | 5, wave_type | 6, wave_type | 7, wave_type | 4, - }; - set_voice_types( types ); - set_silence_lookahead( 6 ); -} - -Sap_Emu::~Sap_Emu() { } - -// Track info - -// Returns 16 or greater if not hex -inline int from_hex_char( int h ) -{ - h -= 0x30; - if ( (unsigned) h > 9 ) - h = ((h - 0x11) & 0xDF) + 10; - return h; -} - -static long from_hex( byte const* in ) -{ - unsigned result = 0; - for ( int n = 4; n--; ) - { - int h = from_hex_char( *in++ ); - if ( h > 15 ) - return -1; - result = result * 0x10 + h; - } - return result; -} - -static int from_dec( byte const* in, byte const* end ) -{ - if ( in >= end ) - return -1; - - int n = 0; - while ( in < end ) - { - int dig = *in++ - '0'; - if ( (unsigned) dig > 9 ) - return -1; - n = n * 10 + dig; - } - return n; -} - -static void parse_string( byte const* in, byte const* end, int len, char* out ) -{ - byte const* start = in; - if ( *in++ == '\"' ) - { - start++; - while ( in < end && *in != '\"' ) - in++; - } - else - { - in = end; - } - len = min( len - 1, int (in - start) ); - out [len] = 0; - memcpy( out, start, len ); -} - -static blargg_err_t parse_info( byte const* in, long size, Sap_Emu::info_t* out ) -{ - out->track_count = 1; - out->author [0] = 0; - out->name [0] = 0; - out->copyright [0] = 0; - - if ( size < 16 || memcmp( in, "SAP\x0D\x0A", 5 ) ) - return gme_wrong_file_type; - - byte const* file_end = in + size - 5; - in += 5; - while ( in < file_end && (in [0] != 0xFF || in [1] != 0xFF) ) - { - byte const* line_end = in; - while ( line_end < file_end && *line_end != 0x0D ) - line_end++; - - char const* tag = (char const*) in; - while ( in < line_end && *in > ' ' ) - in++; - int tag_len = (char const*) in - tag; - - while ( in < line_end && *in <= ' ' ) in++; - - if ( tag_len <= 0 ) - { - // skip line - } - else if ( !strncmp( "INIT", tag, tag_len ) ) - { - out->init_addr = from_hex( in ); - if ( (unsigned long) out->init_addr > 0xFFFF ) - return "Invalid init address"; - } - else if ( !strncmp( "PLAYER", tag, tag_len ) ) - { - out->play_addr = from_hex( in ); - if ( (unsigned long) out->play_addr > 0xFFFF ) - return "Invalid play address"; - } - else if ( !strncmp( "MUSIC", tag, tag_len ) ) - { - out->music_addr = from_hex( in ); - if ( (unsigned long) out->music_addr > 0xFFFF ) - return "Invalid music address"; - } - else if ( !strncmp( "SONGS", tag, tag_len ) ) - { - out->track_count = from_dec( in, line_end ); - if ( out->track_count <= 0 ) - return "Invalid track count"; - } - else if ( !strncmp( "TYPE", tag, tag_len ) ) - { - switch ( out->type = *in ) - { - case 'C': - case 'B': - break; - - case 'D': - return "Digimusic not supported"; - - default: - return "Unsupported player type"; - } - } - else if ( !strncmp( "STEREO", tag, tag_len ) ) - { - out->stereo = true; - } - else if ( !strncmp( "FASTPLAY", tag, tag_len ) ) - { - out->fastplay = from_dec( in, line_end ); - if ( out->fastplay <= 0 ) - return "Invalid fastplay value"; - } - else if ( !strncmp( "AUTHOR", tag, tag_len ) ) - { - parse_string( in, line_end, sizeof out->author, out->author ); - } - else if ( !strncmp( "NAME", tag, tag_len ) ) - { - parse_string( in, line_end, sizeof out->name, out->name ); - } - else if ( !strncmp( "DATE", tag, tag_len ) ) - { - parse_string( in, line_end, sizeof out->copyright, out->copyright ); - } - - in = line_end + 2; - } - - if ( in [0] != 0xFF || in [1] != 0xFF ) - return "ROM data missing"; - out->rom_data = in + 2; - - return 0; -} - -static void copy_sap_fields( Sap_Emu::info_t const& in, track_info_t* out ) -{ - Gme_File::copy_field_( out->game, in.name ); - Gme_File::copy_field_( out->author, in.author ); - Gme_File::copy_field_( out->copyright, in.copyright ); -} - -blargg_err_t Sap_Emu::track_info_( track_info_t* out, int ) const -{ - copy_sap_fields( info, out ); - return 0; -} - -struct Sap_File : Gme_Info_ -{ - Sap_Emu::info_t info; - - Sap_File() { set_type( gme_sap_type ); } - - blargg_err_t load_mem_( byte const* begin, long size ) - { - RETURN_ERR( parse_info( begin, size, &info ) ); - set_track_count( info.track_count ); - return 0; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - copy_sap_fields( info, out ); - return 0; - } -}; - -static Music_Emu* new_sap_emu () { return BLARGG_NEW Sap_Emu ; } -static Music_Emu* new_sap_file() { return BLARGG_NEW Sap_File; } - -static gme_type_t_ const gme_sap_type_ = { "Atari XL", 0, &new_sap_emu, &new_sap_file, "SAP", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_sap_type = &gme_sap_type_; - -// Setup - -blargg_err_t Sap_Emu::load_mem_( byte const* in, long size ) -{ - file_end = in + size; - - info.warning = 0; - info.type = 'B'; - info.stereo = false; - info.init_addr = -1; - info.play_addr = -1; - info.music_addr = -1; - info.fastplay = 312; - RETURN_ERR( parse_info( in, size, &info ) ); - - set_warning( info.warning ); - set_track_count( info.track_count ); - set_voice_count( Sap_Apu::osc_count << info.stereo ); - apu_impl.volume( gain() ); - - return setup_buffer( 1773447 ); -} - -void Sap_Emu::update_eq( blip_eq_t const& eq ) -{ - apu_impl.synth.treble_eq( eq ); -} - -void Sap_Emu::set_voice( int i, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - int i2 = i - Sap_Apu::osc_count; - if ( i2 >= 0 ) - apu2.osc_output( i2, right ); - else - apu.osc_output( i, (info.stereo ? left : center) ); -} - -// Emulation - -void Sap_Emu::set_tempo_( double t ) -{ - scanline_period = sap_time_t (base_scanline_period / t); -} - -inline sap_time_t Sap_Emu::play_period() const { return info.fastplay * scanline_period; } - -void Sap_Emu::cpu_jsr( sap_addr_t addr ) -{ - check( r.sp >= 0xFE ); // catch anything trying to leave data on stack - r.pc = addr; - int high_byte = (idle_addr - 1) >> 8; - if ( r.sp == 0xFE && mem.ram [0x1FF] == high_byte ) - r.sp = 0xFF; // pop extra byte off - mem.ram [0x100 + r.sp--] = high_byte; // some routines use RTI to return - mem.ram [0x100 + r.sp--] = high_byte; - mem.ram [0x100 + r.sp--] = (idle_addr - 1) & 0xFF; -} - -void Sap_Emu::run_routine( sap_addr_t addr ) -{ - cpu_jsr( addr ); - cpu::run( 312 * base_scanline_period * 60 ); - check( r.pc == idle_addr ); -} - -inline void Sap_Emu::call_init( int track ) -{ - switch ( info.type ) - { - case 'B': - r.a = track; - run_routine( info.init_addr ); - break; - - case 'C': - r.a = 0x70; - r.x = info.music_addr&0xFF; - r.y = info.music_addr >> 8; - run_routine( info.play_addr + 3 ); - r.a = 0; - r.x = track; - run_routine( info.play_addr + 3 ); - break; - } -} - -blargg_err_t Sap_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - - memset( &mem, 0, sizeof mem ); - - byte const* in = info.rom_data; - while ( file_end - in >= 5 ) - { - unsigned start = get_le16( in ); - unsigned end = get_le16( in + 2 ); - //debug_printf( "Block $%04X-$%04X\n", start, end ); - in += 4; - if ( end < start ) - { - set_warning( "Invalid file data block" ); - break; - } - long len = end - start + 1; - if ( len > file_end - in ) - { - set_warning( "Invalid file data block" ); - break; - } - - memcpy( mem.ram + start, in, len ); - in += len; - if ( file_end - in >= 2 && in [0] == 0xFF && in [1] == 0xFF ) - in += 2; - } - - apu.reset( &apu_impl ); - apu2.reset( &apu_impl ); - cpu::reset( mem.ram ); - time_mask = 0; // disables sound during init - call_init( track ); - time_mask = -1; - - next_play = play_period(); - - return 0; -} - -// Emulation - -// see sap_cpu_io.h for read/write functions - -void Sap_Emu::cpu_write_( sap_addr_t addr, int data ) -{ - if ( (addr ^ Sap_Apu::start_addr) <= (Sap_Apu::end_addr - Sap_Apu::start_addr) ) - { - GME_APU_HOOK( this, addr - Sap_Apu::start_addr, data ); - apu.write_data( time() & time_mask, addr, data ); - return; - } - - if ( (addr ^ (Sap_Apu::start_addr + 0x10)) <= (Sap_Apu::end_addr - Sap_Apu::start_addr) && - info.stereo ) - { - GME_APU_HOOK( this, addr - 0x10 - Sap_Apu::start_addr + 10, data ); - apu2.write_data( time() & time_mask, addr ^ 0x10, data ); - return; - } - - if ( (addr & ~0x0010) != 0xD20F || data != 0x03 ) - debug_printf( "Unmapped write $%04X <- $%02X\n", addr, data ); -} - -inline void Sap_Emu::call_play() -{ - switch ( info.type ) - { - case 'B': - cpu_jsr( info.play_addr ); - break; - - case 'C': - cpu_jsr( info.play_addr + 6 ); - break; - } -} - -blargg_err_t Sap_Emu::run_clocks( blip_time_t& duration, int ) -{ - set_time( 0 ); - while ( time() < duration ) - { - if ( cpu::run( duration ) || r.pc > idle_addr ) - return "Emulation error (illegal instruction)"; - - if ( r.pc == idle_addr ) - { - if ( next_play <= duration ) - { - set_time( next_play ); - next_play += play_period(); - call_play(); - GME_FRAME_HOOK( this ); - } - else - { - set_time( duration ); - } - } - } - - duration = time(); - next_play -= duration; - check( next_play >= 0 ); - if ( next_play < 0 ) - next_play = 0; - apu.end_frame( duration ); - if ( info.stereo ) - apu2.end_frame( duration ); - - return 0; -} diff --git a/libraries/game-music-emu/gme/Sap_Emu.h b/libraries/game-music-emu/gme/Sap_Emu.h deleted file mode 100644 index f75312713..000000000 --- a/libraries/game-music-emu/gme/Sap_Emu.h +++ /dev/null @@ -1,68 +0,0 @@ -// Atari XL/XE SAP music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef SAP_EMU_H -#define SAP_EMU_H - -#include "Classic_Emu.h" -#include "Sap_Apu.h" -#include "Sap_Cpu.h" - -class Sap_Emu : private Sap_Cpu, public Classic_Emu { - typedef Sap_Cpu cpu; -public: - static gme_type_t static_type() { return gme_sap_type; } -public: - Sap_Emu(); - ~Sap_Emu(); - struct info_t { - byte const* rom_data; - const char* warning; - long init_addr; - long play_addr; - long music_addr; - int type; - int track_count; - int fastplay; - bool stereo; - char author [256]; - char name [256]; - char copyright [ 32]; - }; -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_mem_( byte const*, long ); - blargg_err_t start_track_( int ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); -public: private: friend class Sap_Cpu; - int cpu_read( sap_addr_t ); - void cpu_write( sap_addr_t, int ); - void cpu_write_( sap_addr_t, int ); -private: - info_t info; - - byte const* file_end; - sap_time_t scanline_period; - sap_time_t next_play; - sap_time_t time_mask; - Sap_Apu apu; - Sap_Apu apu2; - - // large items - struct { - byte padding1 [0x100]; - byte ram [0x10000 + 0x100]; - } mem; - Sap_Apu_Impl apu_impl; - - sap_time_t play_period() const; - void call_play(); - void cpu_jsr( sap_addr_t ); - void call_init( int track ); - void run_routine( sap_addr_t ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Sms_Apu.cpp b/libraries/game-music-emu/gme/Sms_Apu.cpp deleted file mode 100644 index b41fdec41..000000000 --- a/libraries/game-music-emu/gme/Sms_Apu.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Sms_Snd_Emu 0.1.4. http://www.slack.net/~ant/ - -#include "Sms_Apu.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// Sms_Osc - -Sms_Osc::Sms_Osc() -{ - output = 0; - outputs [0] = 0; // always stays NULL - outputs [1] = 0; - outputs [2] = 0; - outputs [3] = 0; -} - -void Sms_Osc::reset() -{ - delay = 0; - last_amp = 0; - volume = 0; - output_select = 3; - output = outputs [3]; -} - -// Sms_Square - -inline void Sms_Square::reset() -{ - period = 0; - phase = 0; - Sms_Osc::reset(); -} - -void Sms_Square::run( blip_time_t time, blip_time_t end_time ) -{ - if ( !volume || period <= 128 ) - { - // ignore 16kHz and higher - if ( last_amp ) - { - synth->offset( time, -last_amp, output ); - last_amp = 0; - } - time += delay; - if ( !period ) - { - time = end_time; - } - else if ( time < end_time ) - { - // keep calculating phase - int count = (end_time - time + period - 1) / period; - phase = (phase + count) & 1; - time += count * period; - } - } - else - { - int amp = phase ? volume : -volume; - { - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth->offset( time, delta, output ); - } - } - - time += delay; - if ( time < end_time ) - { - Blip_Buffer* const output = this->output; - int delta = amp * 2; - do - { - delta = -delta; - synth->offset_inline( time, delta, output ); - time += period; - phase ^= 1; - } - while ( time < end_time ); - this->last_amp = phase ? volume : -volume; - } - } - delay = time - end_time; -} - -// Sms_Noise - -static int const noise_periods [3] = { 0x100, 0x200, 0x400 }; - -inline void Sms_Noise::reset() -{ - period = &noise_periods [0]; - shifter = 0x8000; - feedback = 0x9000; - Sms_Osc::reset(); -} - -void Sms_Noise::run( blip_time_t time, blip_time_t end_time ) -{ - int amp = volume; - if ( shifter & 1 ) - amp = -amp; - - { - int delta = amp - last_amp; - if ( delta ) - { - last_amp = amp; - synth.offset( time, delta, output ); - } - } - - time += delay; - if ( !volume ) - time = end_time; - - if ( time < end_time ) - { - Blip_Buffer* const output = this->output; - unsigned shifter = this->shifter; - int delta = amp * 2; - int period = *this->period * 2; - if ( !period ) - period = 16; - - do - { - int changed = shifter + 1; - shifter = (feedback & -(shifter & 1)) ^ (shifter >> 1); - if ( changed & 2 ) // true if bits 0 and 1 differ - { - delta = -delta; - synth.offset_inline( time, delta, output ); - } - time += period; - } - while ( time < end_time ); - - this->shifter = shifter; - this->last_amp = delta >> 1; - } - delay = time - end_time; -} - -// Sms_Apu - -Sms_Apu::Sms_Apu() -{ - for ( int i = 0; i < 3; i++ ) - { - squares [i].synth = &square_synth; - oscs [i] = &squares [i]; - } - oscs [3] = &noise; - - volume( 1.0 ); - reset(); -} - -Sms_Apu::~Sms_Apu() -{ -} - -void Sms_Apu::volume( double vol ) -{ - vol *= 0.85 / (osc_count * 64 * 2); - square_synth.volume( vol ); - noise.synth.volume( vol ); -} - -void Sms_Apu::treble_eq( const blip_eq_t& eq ) -{ - square_synth.treble_eq( eq ); - noise.synth.treble_eq( eq ); -} - -void Sms_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - require( (unsigned) index < osc_count ); - require( (center && left && right) || (!center && !left && !right) ); - Sms_Osc& osc = *oscs [index]; - osc.outputs [1] = right; - osc.outputs [2] = left; - osc.outputs [3] = center; - osc.output = osc.outputs [osc.output_select]; -} - -void Sms_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ) -{ - for ( int i = 0; i < osc_count; i++ ) - osc_output( i, center, left, right ); -} - -void Sms_Apu::reset( unsigned feedback, int noise_width ) -{ - last_time = 0; - latch = 0; - - if ( !feedback || !noise_width ) - { - feedback = 0x0009; - noise_width = 16; - } - // convert to "Galios configuration" - looped_feedback = 1 << (noise_width - 1); - noise_feedback = 0; - while ( noise_width-- ) - { - noise_feedback = (noise_feedback << 1) | (feedback & 1); - feedback >>= 1; - } - - squares [0].reset(); - squares [1].reset(); - squares [2].reset(); - noise.reset(); -} - -void Sms_Apu::run_until( blip_time_t end_time ) -{ - require( end_time >= last_time ); // end_time must not be before previous time - - if ( end_time > last_time ) - { - // run oscillators - for ( int i = 0; i < osc_count; ++i ) - { - Sms_Osc& osc = *oscs [i]; - if ( osc.output ) - { - osc.output->set_modified(); - if ( i < 3 ) - squares [i].run( last_time, end_time ); - else - noise.run( last_time, end_time ); - } - } - - last_time = end_time; - } -} - -void Sms_Apu::end_frame( blip_time_t end_time ) -{ - if ( end_time > last_time ) - run_until( end_time ); - - assert( last_time >= end_time ); - last_time -= end_time; -} - -void Sms_Apu::write_ggstereo( blip_time_t time, int data ) -{ - require( (unsigned) data <= 0xFF ); - - run_until( time ); - - for ( int i = 0; i < osc_count; i++ ) - { - Sms_Osc& osc = *oscs [i]; - int flags = data >> i; - Blip_Buffer* old_output = osc.output; - osc.output_select = (flags >> 3 & 2) | (flags & 1); - osc.output = osc.outputs [osc.output_select]; - if ( osc.output != old_output && osc.last_amp ) - { - if ( old_output ) - { - old_output->set_modified(); - square_synth.offset( time, -osc.last_amp, old_output ); - } - osc.last_amp = 0; - } - } -} - -// volumes [i] = 64 * pow( 1.26, 15 - i ) / pow( 1.26, 15 ) -static unsigned char const volumes [16] = { - 64, 50, 39, 31, 24, 19, 15, 12, 9, 7, 5, 4, 3, 2, 1, 0 -}; - -void Sms_Apu::write_data( blip_time_t time, int data ) -{ - require( (unsigned) data <= 0xFF ); - - run_until( time ); - - if ( data & 0x80 ) - latch = data; - - int index = (latch >> 5) & 3; - if ( latch & 0x10 ) - { - oscs [index]->volume = volumes [data & 15]; - } - else if ( index < 3 ) - { - Sms_Square& sq = squares [index]; - if ( data & 0x80 ) - sq.period = (sq.period & 0xFF00) | (data << 4 & 0x00FF); - else - sq.period = (sq.period & 0x00FF) | (data << 8 & 0x3F00); - } - else - { - int select = data & 3; - if ( select < 3 ) - noise.period = &noise_periods [select]; - else - noise.period = &squares [2].period; - - noise.feedback = (data & 0x04) ? noise_feedback : looped_feedback; - noise.shifter = 0x8000; - } -} diff --git a/libraries/game-music-emu/gme/Sms_Apu.h b/libraries/game-music-emu/gme/Sms_Apu.h deleted file mode 100644 index 3c11a9c3c..000000000 --- a/libraries/game-music-emu/gme/Sms_Apu.h +++ /dev/null @@ -1,75 +0,0 @@ -// Sega Master System SN76489 PSG sound chip emulator - -// Sms_Snd_Emu 0.1.4 -#ifndef SMS_APU_H -#define SMS_APU_H - -#include "Sms_Oscs.h" - -class Sms_Apu { -public: - // Set overall volume of all oscillators, where 1.0 is full volume - void volume( double ); - - // Set treble equalization - void treble_eq( const blip_eq_t& ); - - // Outputs can be assigned to a single buffer for mono output, or to three - // buffers for stereo output (using Stereo_Buffer to do the mixing). - - // Assign all oscillator outputs to specified buffer(s). If buffer - // is NULL, silences all oscillators. - void output( Blip_Buffer* mono ); - void output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ); - - // Assign single oscillator output to buffer(s). Valid indicies are 0 to 3, - // which refer to Square 1, Square 2, Square 3, and Noise. If buffer is NULL, - // silences oscillator. - enum { osc_count = 4 }; - void osc_output( int index, Blip_Buffer* mono ); - void osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right ); - - // Reset oscillators and internal state - void reset( unsigned noise_feedback = 0, int noise_width = 0 ); - - // Write GameGear left/right assignment byte - void write_ggstereo( blip_time_t, int ); - - // Write to data port - void write_data( blip_time_t, int ); - - // Run all oscillators up to specified time, end current frame, then - // start a new frame at time 0. - void end_frame( blip_time_t ); - -public: - Sms_Apu(); - ~Sms_Apu(); -private: - // noncopyable - Sms_Apu( const Sms_Apu& ); - Sms_Apu& operator = ( const Sms_Apu& ); - - Sms_Osc* oscs [osc_count]; - Sms_Square squares [3]; - Sms_Square::Synth square_synth; // used by squares - blip_time_t last_time; - int latch; - Sms_Noise noise; - unsigned noise_feedback; - unsigned looped_feedback; - - void run_until( blip_time_t ); -}; - -struct sms_apu_state_t -{ - unsigned char regs [8] [2]; - unsigned char latch; -}; - -inline void Sms_Apu::output( Blip_Buffer* b ) { output( b, b, b ); } - -inline void Sms_Apu::osc_output( int i, Blip_Buffer* b ) { osc_output( i, b, b, b ); } - -#endif diff --git a/libraries/game-music-emu/gme/Sms_Oscs.h b/libraries/game-music-emu/gme/Sms_Oscs.h deleted file mode 100644 index 2a896fef3..000000000 --- a/libraries/game-music-emu/gme/Sms_Oscs.h +++ /dev/null @@ -1,49 +0,0 @@ -// Private oscillators used by Sms_Apu - -// Sms_Snd_Emu 0.1.4 -#ifndef SMS_OSCS_H -#define SMS_OSCS_H - -#include "blargg_common.h" -#include "Blip_Buffer.h" - -struct Sms_Osc -{ - Blip_Buffer* outputs [4]; // NULL, right, left, center - Blip_Buffer* output; - int output_select; - - int delay; - int last_amp; - int volume; - - Sms_Osc(); - void reset(); -}; - -struct Sms_Square : Sms_Osc -{ - int period; - int phase; - - typedef Blip_Synth Synth; - const Synth* synth; - - void reset(); - void run( blip_time_t, blip_time_t ); -}; - -struct Sms_Noise : Sms_Osc -{ - const int* period; - unsigned shifter; - unsigned feedback; - - typedef Blip_Synth Synth; - Synth synth; - - void reset(); - void run( blip_time_t, blip_time_t ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Snes_Spc.cpp b/libraries/game-music-emu/gme/Snes_Spc.cpp deleted file mode 100644 index 0b2077d8c..000000000 --- a/libraries/game-music-emu/gme/Snes_Spc.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// SPC emulation support: init, sample buffering, reset, SPC loading - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Snes_Spc.h" - -#include - -/* 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 -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" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - - -//// Init - -blargg_err_t Snes_Spc::init() -{ - memset( &m, 0, sizeof m ); - dsp.init( RAM ); - - m.tempo = tempo_unit; - - // Most SPC music doesn't need ROM, and almost all the rest only rely - // on these two bytes - m.rom [0x3E] = 0xFF; - m.rom [0x3F] = 0xC0; - - static unsigned char const cycle_table [128] = - {// 01 23 45 67 89 AB CD EF - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1 - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4 - 0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7 - 0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9 - 0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B - 0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C - 0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D - 0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E - 0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F - }; - - // unpack cycle table - for ( int i = 0; i < 128; i++ ) - { - int n = cycle_table [i]; - m.cycle_table [i * 2 + 0] = n >> 4; - m.cycle_table [i * 2 + 1] = n & 0x0F; - } - - #if SPC_LESS_ACCURATE - memcpy( reg_times, reg_times_, sizeof reg_times ); - #endif - - reset(); - return 0; -} - -void Snes_Spc::init_rom( uint8_t const in [rom_size] ) -{ - memcpy( m.rom, in, sizeof m.rom ); -} - -void Snes_Spc::set_tempo( int t ) -{ - m.tempo = t; - int const timer2_shift = 4; // 64 kHz - int const other_shift = 3; // 8 kHz - - #if SPC_DISABLE_TEMPO - m.timers [2].prescaler = timer2_shift; - m.timers [1].prescaler = timer2_shift + other_shift; - m.timers [0].prescaler = timer2_shift + other_shift; - #else - if ( !t ) - t = 1; - int const timer2_rate = 1 << timer2_shift; - int rate = (timer2_rate * tempo_unit + (t >> 1)) / t; - if ( rate < timer2_rate / 4 ) - rate = timer2_rate / 4; // max 4x tempo - m.timers [2].prescaler = rate; - m.timers [1].prescaler = rate << other_shift; - m.timers [0].prescaler = rate << other_shift; - #endif -} - -// Timer registers have been loaded. Applies these to the timers. Does not -// reset timer prescalers or dividers. -void Snes_Spc::timers_loaded() -{ - int i; - for ( i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->period = IF_0_THEN_256( REGS [r_t0target + i] ); - t->enabled = REGS [r_control] >> i & 1; - t->counter = REGS_IN [r_t0out + i] & 0x0F; - } - - set_tempo( m.tempo ); -} - -// Loads registers from unified 16-byte format -void Snes_Spc::load_regs( uint8_t const in [reg_count] ) -{ - memcpy( REGS, in, reg_count ); - memcpy( REGS_IN, REGS, reg_count ); - - // These always read back as 0 - REGS_IN [r_test ] = 0; - REGS_IN [r_control ] = 0; - REGS_IN [r_t0target] = 0; - REGS_IN [r_t1target] = 0; - REGS_IN [r_t2target] = 0; -} - -// RAM was just loaded from SPC, with $F0-$FF containing SMP registers -// and timer counts. Copies these to proper registers. -void Snes_Spc::ram_loaded() -{ - m.rom_enabled = 0; - load_regs( &RAM [0xF0] ); - - // Put STOP instruction around memory to catch PC underflow/overflow - memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 ); - memset( m.ram.ram + 0x10000, cpu_pad_fill, sizeof m.ram.padding1 ); -} - -// Registers were just loaded. Applies these new values. -void Snes_Spc::regs_loaded() -{ - enable_rom( REGS [r_control] & 0x80 ); - timers_loaded(); -} - -void Snes_Spc::reset_time_regs() -{ - m.cpu_error = 0; - m.echo_accessed = 0; - m.spc_time = 0; - m.dsp_time = 0; - #if SPC_LESS_ACCURATE - m.dsp_time = clocks_per_sample + 1; - #endif - - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->next_time = 1; - t->divider = 0; - } - - regs_loaded(); - - m.extra_clocks = 0; - reset_buf(); -} - -void Snes_Spc::reset_common( int timer_counter_init ) -{ - int i; - for ( i = 0; i < timer_count; i++ ) - REGS_IN [r_t0out + i] = timer_counter_init; - - // Run IPL ROM - memset( &m.cpu_regs, 0, sizeof m.cpu_regs ); - m.cpu_regs.pc = rom_addr; - - REGS [r_test ] = 0x0A; - REGS [r_control] = 0xB0; // ROM enabled, clear ports - for ( i = 0; i < port_count; i++ ) - REGS_IN [r_cpuio0 + i] = 0; - - reset_time_regs(); -} - -void Snes_Spc::soft_reset() -{ - reset_common( 0 ); - dsp.soft_reset(); -} - -void Snes_Spc::reset() -{ - memset( RAM, 0xFF, 0x10000 ); - ram_loaded(); - reset_common( 0x0F ); - dsp.reset(); -} - -char const Snes_Spc::signature [signature_size + 1] = - "SNES-SPC700 Sound File Data v0.30\x1A\x1A"; - -blargg_err_t Snes_Spc::load_spc( void const* data, long size ) -{ - spc_file_t const* const spc = (spc_file_t const*) data; - - // be sure compiler didn't insert any padding into fle_t - assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 ); - - // Check signature and file size - if ( size < signature_size || memcmp( spc, signature, 27 ) ) - return "Not an SPC file"; - - if ( size < spc_min_file_size ) - return "Corrupt SPC file"; - - // CPU registers - m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl; - m.cpu_regs.a = spc->a; - m.cpu_regs.x = spc->x; - m.cpu_regs.y = spc->y; - m.cpu_regs.psw = spc->psw; - m.cpu_regs.sp = spc->sp; - - // RAM and registers - memcpy( RAM, spc->ram, 0x10000 ); - ram_loaded(); - - // DSP registers - dsp.load( spc->dsp ); - - reset_time_regs(); - - return 0; -} - -void Snes_Spc::clear_echo() -{ - if ( !(dsp.read( Spc_Dsp::r_flg ) & 0x20) ) - { - int addr = 0x100 * dsp.read( Spc_Dsp::r_esa ); - int end = addr + 0x800 * (dsp.read( Spc_Dsp::r_edl ) & 0x0F); - if ( end > 0x10000 ) - end = 0x10000; - memset( &RAM [addr], 0xFF, end - addr ); - } -} - - -//// Sample output - -void Snes_Spc::reset_buf() -{ - // Start with half extra buffer of silence - sample_t* out = m.extra_buf; - while ( out < &m.extra_buf [extra_size / 2] ) - *out++ = 0; - - m.extra_pos = out; - m.buf_begin = 0; - - dsp.set_output( 0, 0 ); -} - -void Snes_Spc::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // size must be even - - m.extra_clocks &= clocks_per_sample - 1; - if ( out ) - { - sample_t const* out_end = out + size; - m.buf_begin = out; - m.buf_end = out_end; - - // Copy extra to output - sample_t const* in = m.extra_buf; - while ( in < m.extra_pos && out < out_end ) - *out++ = *in++; - - // Handle output being full already - if ( out >= out_end ) - { - // Have DSP write to remaining extra space - out = dsp.extra(); - out_end = &dsp.extra() [extra_size]; - - // Copy any remaining extra samples as if DSP wrote them - while ( in < m.extra_pos ) - *out++ = *in++; - assert( out <= out_end ); - } - - dsp.set_output( out, out_end - out ); - } - else - { - reset_buf(); - } -} - -void Snes_Spc::save_extra() -{ - // Get end pointers - sample_t const* main_end = m.buf_end; // end of data written to buf - sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra() - if ( m.buf_begin <= dsp_end && dsp_end <= main_end ) - { - main_end = dsp_end; - dsp_end = dsp.extra(); // nothing in DSP's extra - } - - // Copy any extra samples at these ends into extra_buf - sample_t* out = m.extra_buf; - sample_t const* in; - for ( in = m.buf_begin + sample_count(); in < main_end; in++ ) - *out++ = *in; - for ( in = dsp.extra(); in < dsp_end ; in++ ) - *out++ = *in; - - m.extra_pos = out; - assert( out <= &m.extra_buf [extra_size] ); -} - -blargg_err_t Snes_Spc::play( int count, sample_t* out ) -{ - require( (count & 1) == 0 ); // must be even - if ( count ) - { - set_output( out, count ); - end_frame( count * (clocks_per_sample / 2) ); - } - - const char* err = m.cpu_error; - m.cpu_error = 0; - return err; -} - -blargg_err_t Snes_Spc::skip( int count ) -{ - #if SPC_LESS_ACCURATE - if ( count > 2 * sample_rate * 2 ) - { - set_output( 0, 0 ); - - // Skip a multiple of 4 samples - time_t end = count; - count = (count & 3) + 1 * sample_rate * 2; - end = (end - count) * (clocks_per_sample / 2); - - m.skipped_kon = 0; - m.skipped_koff = 0; - - // Preserve DSP and timer synchronization - // TODO: verify that this really preserves it - int old_dsp_time = m.dsp_time + m.spc_time; - m.dsp_time = end - m.spc_time + skipping_time; - end_frame( end ); - m.dsp_time = m.dsp_time - skipping_time + old_dsp_time; - - dsp.write( Spc_Dsp::r_koff, m.skipped_koff & ~m.skipped_kon ); - dsp.write( Spc_Dsp::r_kon , m.skipped_kon ); - clear_echo(); - } - #endif - - return play( count, 0 ); -} diff --git a/libraries/game-music-emu/gme/Snes_Spc.h b/libraries/game-music-emu/gme/Snes_Spc.h deleted file mode 100644 index 68c780ab7..000000000 --- a/libraries/game-music-emu/gme/Snes_Spc.h +++ /dev/null @@ -1,283 +0,0 @@ -// SNES SPC-700 APU emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef SNES_SPC_H -#define SNES_SPC_H - -#include "Spc_Dsp.h" -#include "blargg_endian.h" - -#include - -struct Snes_Spc { -public: - // Must be called once before using - blargg_err_t init(); - - // Sample pairs generated per second - enum { sample_rate = 32000 }; - -// Emulator use - - // Sets IPL ROM data. Library does not include ROM data. Most SPC music files - // don't need ROM, but a full emulator must provide this. - enum { rom_size = 0x40 }; - void init_rom( uint8_t const rom [rom_size] ); - - // Sets destination for output samples - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since last set - int sample_count() const; - - // Resets SPC to power-on state. This resets your output buffer, so you must - // call set_output() after this. - void reset(); - - // Emulates pressing reset switch on SNES. This resets your output buffer, so - // you must call set_output() after this. - void soft_reset(); - - // 1024000 SPC clocks per second, sample pair every 32 clocks - typedef int time_t; - enum { clock_rate = 1024000 }; - enum { clocks_per_sample = 32 }; - - // Emulated port read/write at specified time - enum { port_count = 4 }; - int read_port ( time_t, int port ); - void write_port( time_t, int port, int data ); - - // Runs SPC to end_time and starts a new time frame at 0 - void end_frame( time_t end_time ); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - - // If true, prevents channels and global volumes from being phase-negated. - // Only supported by fast DSP. - void disable_surround( bool disable = true ); - - // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. - enum { tempo_unit = 0x100 }; - void set_tempo( int ); - -// SPC music files - - // Loads SPC data into emulator - enum { spc_min_file_size = 0x10180 }; - enum { spc_file_size = 0x10200 }; - blargg_err_t load_spc( void const* in, long size ); - - // Clears echo region. Useful after loading an SPC as many have garbage in echo. - void clear_echo(); - - // Plays for count samples and write samples to out. Discards samples if out - // is NULL. Count must be a multiple of 2 since output is stereo. - blargg_err_t play( int count, sample_t* out ); - - // Skips count samples. Several times faster than play() when using fast DSP. - blargg_err_t skip( int count ); - -// State save/load (only available with accurate DSP) - -#if !SPC_NO_COPY_STATE_FUNCS - // Saves/loads state - enum { state_size = 67 * 1024L }; // maximum space needed when saving - typedef Spc_Dsp::copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); - - // Writes minimal header to spc_out - static void init_header( void* spc_out ); - - // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. - // Does not set up SPC header; use init_header() for that. - void save_spc( void* spc_out ); - - // Returns true if new key-on events occurred since last check. Useful for - // trimming silence while saving an SPC. - bool check_kon(); -#endif - -public: - // TODO: document - struct regs_t - { - uint16_t pc; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t psw; - uint8_t sp; - }; - regs_t& smp_regs() { return m.cpu_regs; } - - uint8_t* smp_ram() { return m.ram.ram; } - - void run_until( time_t t ) { run_until_( t ); } -public: - BLARGG_DISABLE_NOTHROW - - // Time relative to m_spc_time. Speeds up code a bit by eliminating need to - // constantly add m_spc_time to time from CPU. CPU uses time that ends at - // 0 to eliminate reloading end time every instruction. It pays off. - typedef int rel_time_t; - - struct Timer - { - rel_time_t next_time; // time of next event - int prescaler; - int period; - int divider; - int enabled; - int counter; - }; - enum { reg_count = 0x10 }; - enum { timer_count = 3 }; - enum { extra_size = Spc_Dsp::extra_size }; - - enum { signature_size = 35 }; - -private: - Spc_Dsp dsp; - - #if SPC_LESS_ACCURATE - static signed char const reg_times_ [256]; - signed char reg_times [256]; - #endif - - struct state_t - { - Timer timers [timer_count]; - - uint8_t smp_regs [2] [reg_count]; - - regs_t cpu_regs; - - rel_time_t dsp_time; - time_t spc_time; - bool echo_accessed; - - int tempo; - int skipped_kon; - int skipped_koff; - const char* cpu_error; - - int extra_clocks; - sample_t* buf_begin; - sample_t const* buf_end; - sample_t* extra_pos; - sample_t extra_buf [extra_size]; - - int rom_enabled; - uint8_t rom [rom_size]; - uint8_t hi_ram [rom_size]; - - unsigned char cycle_table [256]; - - struct - { - // padding to neutralize address overflow -- but this is - // still undefined behavior! TODO: remove and instead properly - // guard usage of emulated memory - uint8_t padding1 [0x100]; - alignas(uint16_t) uint8_t ram [0x10000 + 0x100]; - } ram; - }; - state_t m; - - enum { rom_addr = 0xFFC0 }; - - enum { skipping_time = 127 }; - - // Value that padding should be filled with - enum { cpu_pad_fill = 0xFF }; - - enum { - r_test = 0x0, r_control = 0x1, - r_dspaddr = 0x2, r_dspdata = 0x3, - r_cpuio0 = 0x4, r_cpuio1 = 0x5, - r_cpuio2 = 0x6, r_cpuio3 = 0x7, - r_f8 = 0x8, r_f9 = 0x9, - r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, - r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF - }; - - void timers_loaded(); - void enable_rom( int enable ); - void reset_buf(); - void save_extra(); - void load_regs( uint8_t const in [reg_count] ); - void ram_loaded(); - void regs_loaded(); - void reset_time_regs(); - void reset_common( int timer_counter_init ); - - Timer* run_timer_ ( Timer* t, rel_time_t ); - Timer* run_timer ( Timer* t, rel_time_t ); - int dsp_read ( rel_time_t ); - void dsp_write ( int data, rel_time_t ); - void cpu_write_smp_reg_( int data, rel_time_t, uint16_t addr ); - void cpu_write_smp_reg ( int data, rel_time_t, uint16_t addr ); - void cpu_write_high ( int data, uint8_t i ); - void cpu_write ( int data, uint16_t addr, rel_time_t ); - int cpu_read_smp_reg ( int i, rel_time_t ); - int cpu_read ( uint16_t addr, rel_time_t ); - unsigned CPU_mem_bit ( uint16_t pc, rel_time_t ); - - bool check_echo_access ( int addr ); - uint8_t* run_until_( time_t end_time ); - - struct spc_file_t - { - char signature [signature_size]; - uint8_t has_id666; - uint8_t version; - uint8_t pcl, pch; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t psw; - uint8_t sp; - char text [212]; - uint8_t ram [0x10000]; - uint8_t dsp [128]; - uint8_t unused [0x40]; - uint8_t ipl_rom [0x40]; - }; - - static char const signature [signature_size + 1]; - - void save_regs( uint8_t out [reg_count] ); -}; - -#include - -inline int Snes_Spc::sample_count() const { return (m.extra_clocks >> 5) * 2; } - -inline int Snes_Spc::read_port( time_t t, int port ) -{ - assert( (unsigned) port < port_count ); - return run_until_( t ) [port]; -} - -inline void Snes_Spc::write_port( time_t t, int port, int data ) -{ - assert( (unsigned) port < port_count ); - run_until_( t ) [0x10 + port] = data; -} - -inline void Snes_Spc::mute_voices( int mask ) { dsp.mute_voices( mask ); } - -inline void Snes_Spc::disable_surround( bool disable ) { dsp.disable_surround( disable ); } - -#if !SPC_NO_COPY_STATE_FUNCS -inline bool Snes_Spc::check_kon() { return dsp.check_kon(); } -#endif - -#endif diff --git a/libraries/game-music-emu/gme/Spc_Cpu.cpp b/libraries/game-music-emu/gme/Spc_Cpu.cpp deleted file mode 100644 index 998fe121b..000000000 --- a/libraries/game-music-emu/gme/Spc_Cpu.cpp +++ /dev/null @@ -1,549 +0,0 @@ -// Core SPC emulation: CPU, timers, SMP registers, memory - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Snes_Spc.h" - -#include - -/* 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 -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" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - -// Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which -// do crazy echo buffer accesses. -#ifndef SPC_MORE_ACCURACY - #define SPC_MORE_ACCURACY 0 -#endif - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - - -//// Timers - -#if SPC_DISABLE_TEMPO - #define TIMER_DIV( t, n ) ((n) >> t->prescaler) - #define TIMER_MUL( t, n ) ((n) << t->prescaler) -#else - #define TIMER_DIV( t, n ) ((n) / t->prescaler) - #define TIMER_MUL( t, n ) ((n) * t->prescaler) -#endif - -Snes_Spc::Timer* Snes_Spc::run_timer_( Timer* t, rel_time_t time ) -{ - int elapsed = TIMER_DIV( t, time - t->next_time ) + 1; - t->next_time += TIMER_MUL( t, elapsed ); - - if ( t->enabled ) - { - int remain = IF_0_THEN_256( t->period - t->divider ); - int divider = t->divider + elapsed; - int over = elapsed - remain; - if ( over >= 0 ) - { - int n = over / t->period; - t->counter = (t->counter + 1 + n) & 0x0F; - divider = over - n * t->period; - } - t->divider = (uint8_t) divider; - } - return t; -} - -inline Snes_Spc::Timer* Snes_Spc::run_timer( Timer* t, rel_time_t time ) -{ - if ( time >= t->next_time ) - t = run_timer_( t, time ); - return t; -} - - -//// ROM - -void Snes_Spc::enable_rom( int enable ) -{ - if ( m.rom_enabled != enable ) - { - m.rom_enabled = enable; - if ( enable ) - memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram ); - memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size ); - // TODO: ROM can still get overwritten when DSP writes to echo buffer - } -} - - -//// DSP - -#if SPC_LESS_ACCURATE - int const max_reg_time = 29; - - signed char const Snes_Spc::reg_times_ [256] = - { - -1, 0,-11,-10,-15,-11, -2, -2, 4, 3, 14, 14, 26, 26, 14, 22, - 2, 3, 0, 1,-12, 0, 1, 1, 7, 6, 14, 14, 27, 14, 14, 23, - 5, 6, 3, 4, -1, 3, 4, 4, 10, 9, 14, 14, 26, -5, 14, 23, - 8, 9, 6, 7, 2, 6, 7, 7, 13, 12, 14, 14, 27, -4, 14, 24, - 11, 12, 9, 10, 5, 9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24, - 14, 15, 12, 13, 8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24, - 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25, - 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25, - - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - }; - - #define RUN_DSP( time, offset ) \ - int count = (time) - (offset) - m.dsp_time;\ - if ( count >= 0 )\ - {\ - int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\ - m.dsp_time += clock_count;\ - dsp.run( clock_count );\ - } -#else - #define RUN_DSP( time, offset ) \ - {\ - int count = (time) - m.dsp_time;\ - if ( !SPC_MORE_ACCURACY || count )\ - {\ - assert( count > 0 );\ - m.dsp_time = (time);\ - dsp.run( count );\ - }\ - } -#endif - -int Snes_Spc::dsp_read( rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] ); - - int result = dsp.read( REGS [r_dspaddr] & 0x7F ); - - #ifdef SPC_DSP_READ_HOOK - SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result ); - #endif - - return result; -} - -inline void Snes_Spc::dsp_write( int data, rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr]] ) - #if SPC_LESS_ACCURATE - else if ( m.dsp_time == skipping_time ) - { - int r = REGS [r_dspaddr]; - if ( r == Spc_Dsp::r_kon ) - m.skipped_kon |= data & ~dsp.read( Spc_Dsp::r_koff ); - - if ( r == Spc_Dsp::r_koff ) - { - m.skipped_koff |= data; - m.skipped_kon &= ~data; - } - } - #endif - - #ifdef SPC_DSP_WRITE_HOOK - SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data ); - #endif - - if ( REGS [r_dspaddr] <= 0x7F ) - dsp.write( REGS [r_dspaddr], data ); - else if ( !SPC_MORE_ACCURACY ) - debug_printf( "SPC wrote to DSP register > $7F\n" ); -} - - -//// Memory access extras - -#if SPC_MORE_ACCURACY - #define MEM_ACCESS( time, addr ) \ - {\ - if ( time >= m.dsp_time )\ - {\ - RUN_DSP( time, max_reg_time );\ - }\ - } -#elif !defined (NDEBUG) - // Debug-only check for read/write within echo buffer, since this might result in - // inaccurate emulation due to the DSP not being caught up to the present. - - bool Snes_Spc::check_echo_access( int addr ) - { - if ( !(dsp.read( Spc_Dsp::r_flg ) & 0x20) ) - { - int start = 0x100 * dsp.read( Spc_Dsp::r_esa ); - int size = 0x800 * (dsp.read( Spc_Dsp::r_edl ) & 0x0F); - int end = start + (size ? size : 4); - if ( start <= addr && addr < end ) - { - if ( !m.echo_accessed ) - { - m.echo_accessed = 1; - return true; - } - } - } - return false; - } - - #define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) ); -#else - #define MEM_ACCESS( time, addr ) -#endif - - -//// CPU write - -#if SPC_MORE_ACCURACY -static unsigned char const glitch_probs [3] [256] = -{ - 0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B, - 0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08, - 0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09, - 0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01, - 0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05, - 0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07, - 0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07, - 0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01, - 0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09, - 0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08, - 0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03, - 0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03, - 0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07, - 0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02, - 0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02, - 0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01, - - 0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07, - 0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06, - 0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09, - 0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03, - 0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07, - 0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03, - 0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06, - 0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03, - 0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05, - 0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04, - 0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05, - 0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01, - 0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05, - 0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01, - 0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03, - 0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01, - - 0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A, - 0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A, - 0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A, - 0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09, - 0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09, - 0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02, - 0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07, - 0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04, - 0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A, - 0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07, - 0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04, - 0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02, - 0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06, - 0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03, - 0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02, - 0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03, -}; -#endif - -// Read/write handlers are divided into multiple functions to keep rarely-used -// 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 -int const no_read_before_write = 0x2000; - -void Snes_Spc::cpu_write_smp_reg_( int data, rel_time_t time, uint16_t addr ) -{ - switch ( addr ) - { - case r_t0target: - case r_t1target: - case r_t2target: { - Timer* t = &m.timers [addr - r_t0target]; - int period = IF_0_THEN_256( data ); - if ( t->period != period ) - { - t = run_timer( t, time ); - #if SPC_MORE_ACCURACY - // Insane behavior when target is written just after counter is - // clocked and counter matches new period and new period isn't 1, 2, 4, or 8 - if ( t->divider == (period & 0xFF) && - t->next_time == time + TIMER_MUL( t, 1 ) && - ((period - 1) | ~0x0F) & period ) - { - //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, - // based on the previous period - int prob = 0xFF; - int old_period = t->period & 0xFF; - if ( period == 3 ) prob = glitch_probs [0] [old_period]; - if ( period == 5 ) prob = glitch_probs [1] [old_period]; - if ( period == 9 ) prob = glitch_probs [2] [old_period]; - - // The glitch suppresses incrementing of one of the counter bits, based on - // the lowest set bit in the new period - int b = 1; - while ( !(period & b) ) - b <<= 1; - - if ( (rand() >> 4 & 0xFF) <= prob ) - t->divider = (t->divider - b) & 0xFF; - } - #endif - t->period = period; - } - break; - } - - case r_t0out: - case r_t1out: - case r_t2out: - if ( !SPC_MORE_ACCURACY ) - debug_printf( "SPC wrote to counter %d\n", (int) addr - r_t0out ); - - if ( data < no_read_before_write / 2 ) - run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0; - break; - - // Registers that act like RAM - case 0x8: - case 0x9: - REGS_IN [addr] = (uint8_t) data; - break; - - case r_test: - if ( (uint8_t) data != 0x0A ) - debug_printf( "SPC wrote to test register\n" ); - break; - - case r_control: - // port clears - if ( data & 0x10 ) - { - REGS_IN [r_cpuio0] = 0; - REGS_IN [r_cpuio1] = 0; - } - if ( data & 0x20 ) - { - REGS_IN [r_cpuio2] = 0; - REGS_IN [r_cpuio3] = 0; - } - - // timers - { - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - int enabled = data >> i & 1; - if ( t->enabled != enabled ) - { - t = run_timer( t, time ); - t->enabled = enabled; - if ( enabled ) - { - t->divider = 0; - t->counter = 0; - } - } - } - } - enable_rom( data & 0x80 ); - break; - } -} - -void Snes_Spc::cpu_write_smp_reg( int data, rel_time_t time, uint16_t addr ) -{ - if ( addr == r_dspdata ) // 99% - dsp_write( data, time ); - else - cpu_write_smp_reg_( data, time, addr ); -} - -void Snes_Spc::cpu_write_high( int data, uint8_t i ) -{ - assert ( i < rom_size ); - m.hi_ram [i] = (uint8_t) data; - if ( m.rom_enabled ) - RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM -} - -void Snes_Spc::cpu_write( int data, uint16_t addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - RAM [addr] = (uint8_t) data; - if ( addr >= 0xF0 ) // 64% - { - const uint16_t reg = addr - 0xF0; - // $F0-$FF - if ( reg < reg_count ) // 87% - { - REGS [reg] = (uint8_t) data; - - // Ports - #ifdef SPC_PORT_WRITE_HOOK - if ( (unsigned) (reg - r_cpuio0) < port_count ) - SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0), - (uint8_t) data, ®S [r_cpuio0] ); - #endif - - // Registers other than $F2 and $F4-$F7 - if ( reg != 2 && (reg < 4 || reg > 7) ) // 36% - cpu_write_smp_reg( data, time, reg ); - } - // High mem/address wrap-around - else if ( addr >= rom_addr ) // 1% in IPL ROM area or address wrapped around - cpu_write_high( data, addr - rom_addr ); - } -} - - -//// CPU read - -inline int Snes_Spc::cpu_read_smp_reg( int reg, rel_time_t time ) -{ - int result = REGS_IN [reg]; - reg -= r_dspaddr; - // DSP addr and data - if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3 - { - result = REGS [r_dspaddr]; - if ( (unsigned) reg == 1 ) - result = dsp_read( time ); // 0xF3 - } - return result; -} - -int Snes_Spc::cpu_read( uint16_t addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - int result = RAM [addr]; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 40% - { - reg -= 0x10; - if ( (unsigned) reg >= 0xFF00 ) // 21% - { - reg += 0x10 - r_t0out; - - // Timers - if ( (unsigned) reg < timer_count ) // 90% - { - Timer* t = &m.timers [reg]; - if ( time >= t->next_time ) - t = run_timer_( t, time ); - result = t->counter; - t->counter = 0; - } - // Other registers - else if ( reg < 0 ) // 10% - { - result = cpu_read_smp_reg( reg + r_t0out, time ); - } - else // 1% - { - assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 ); - result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time ); - } - } - } - - return result; -} - - -//// Run - -// Prefix and suffix for CPU emulator function -#define SPC_CPU_RUN_FUNC \ -uint8_t* Snes_Spc::run_until_( time_t end_time )\ -{\ - rel_time_t rel_time = m.spc_time - end_time;\ - assert( rel_time <= 0 );\ - m.spc_time = end_time;\ - m.dsp_time += rel_time;\ - m.timers [0].next_time += rel_time;\ - m.timers [1].next_time += rel_time;\ - m.timers [2].next_time += rel_time; - -#define SPC_CPU_RUN_FUNC_END \ - m.spc_time += rel_time;\ - m.dsp_time -= rel_time;\ - m.timers [0].next_time -= rel_time;\ - m.timers [1].next_time -= rel_time;\ - m.timers [2].next_time -= rel_time;\ - assert( m.spc_time <= end_time );\ - return ®S [r_cpuio0];\ -} - -int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks - -void Snes_Spc::end_frame( time_t end_time ) -{ - // Catch CPU up to as close to end as possible. If final instruction - // would exceed end, does NOT execute it and leaves m.spc_time < end. - if ( end_time > m.spc_time ) - run_until_( end_time ); - - m.spc_time -= end_time; - m.extra_clocks += end_time; - - // Greatest number of clocks early that emulation can stop early due to - // not being able to execute current instruction without going over - // allowed time. - assert( -cpu_lag_max <= m.spc_time && m.spc_time <= 0 ); - - // Catch timers up to CPU - for ( int i = 0; i < timer_count; i++ ) - run_timer( &m.timers [i], 0 ); - - // Catch DSP up to CPU - if ( m.dsp_time < 0 ) - { - RUN_DSP( 0, max_reg_time ); - } - - // Save any extra samples beyond what should be generated - if ( m.buf_begin ) - save_extra(); -} - -// Inclusion here allows static memory access functions and better optimization -#include "Spc_Cpu.h" diff --git a/libraries/game-music-emu/gme/Spc_Cpu.h b/libraries/game-music-emu/gme/Spc_Cpu.h deleted file mode 100644 index 2dd3e63c2..000000000 --- a/libraries/game-music-emu/gme/Spc_Cpu.h +++ /dev/null @@ -1,1182 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -/* Copyright (C) 2004-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -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 */ - -//// Memory access - -#if SPC_MORE_ACCURACY - #define SUSPICIOUS_OPCODE( name ) ((void) 0) -#else - #define SUSPICIOUS_OPCODE( name ) debug_printf( "SPC: suspicious opcode: " name "\n" ) -#endif - -#define CPU_READ( time, offset, addr )\ - cpu_read( addr, time + offset ) - -#define CPU_WRITE( time, offset, addr, data )\ - cpu_write( data, addr, time + offset ) - -#if SPC_MORE_ACCURACY - #define CPU_READ_TIMER( time, offset, addr, out )\ - { out = CPU_READ( time, offset, addr ); } - -#else - // timers are by far the most common thing read from dp - #define CPU_READ_TIMER( time, offset, addr_, out )\ - {\ - rel_time_t adj_time = time + offset;\ - int dp_addr = addr_;\ - int ti = dp_addr - (r_t0out + 0xF0);\ - if ( (unsigned) ti < timer_count )\ - {\ - Timer* t = &m.timers [ti];\ - if ( adj_time >= t->next_time )\ - t = run_timer_( t, adj_time );\ - out = t->counter;\ - t->counter = 0;\ - }\ - else\ - {\ - out = ram [dp_addr];\ - int i = dp_addr - 0xF0;\ - if ( (unsigned) i < 0x10 )\ - out = cpu_read_smp_reg( i, adj_time );\ - }\ - } -#endif - -#define TIME_ADJ( n ) (n) - -#define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out ) -#define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) ) -#define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) ) - -#define DP_ADDR( addr ) (dp + (addr)) - -#define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out ) -#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) ) -#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data ) - -#define READ_PROG16( addr ) (RAM [(addr) & 0xffff] | (RAM [((addr) + 1) & 0xffff] << 8)) - -#define SET_PC( n ) (pc = n) -#define GET_PC() (pc) -#define READ_PC( pc ) (ram [pc]) -#define READ_PC16( pc ) READ_PROG16( pc ) - -#define SET_SP( v ) (sp = v) -#define GET_SP() ((uint8_t) (sp)) - -#define PUSH16( data )\ -{\ - PUSH( (data & 0xff00) >> 8 );\ - PUSH( data & 0xff );\ -} - -#define PUSH( data )\ -{\ - ram [0x100 + sp] = (uint8_t) (data);\ - --sp;\ -} - -#define POP( out )\ -{\ - ++sp;\ - out = ram [0x100 + sp];\ -} - -#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel ) - -unsigned Snes_Spc::CPU_mem_bit( uint16_t pc, rel_time_t rel_time ) -{ - unsigned addr = READ_PC16( pc ); - unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13); - return t << 8 & 0x100; -} - -//// Status flag handling - -// Hex value in name to clarify code and bit shifting. -// Flag stored in indicated variable during emulation -int const n80 = 0x80; // nz -int const v40 = 0x40; // psw -int const p20 = 0x20; // dp -int const b10 = 0x10; // psw -int const h08 = 0x08; // psw -int const i04 = 0x04; // psw -int const z02 = 0x02; // nz -int const c01 = 0x01; // c - -int const nz_neg_mask = 0x880; // either bit set indicates N flag set - -#define GET_PSW( out )\ -{\ - out = psw & ~(n80 | p20 | z02 | c01);\ - out |= c >> 8 & c01;\ - out |= dp >> 3 & p20;\ - out |= ((nz >> 4) | nz) & n80;\ - if ( !(uint8_t) nz ) out |= z02;\ -} - -#define SET_PSW( in )\ -{\ - psw = in;\ - c = in << 8;\ - dp = in << 3 & 0x100;\ - nz = (in << 4 & 0x800) | (~in & z02);\ -} - -SPC_CPU_RUN_FUNC -{ - uint8_t* const ram = RAM; - uint8_t a = m.cpu_regs.a; - uint8_t x = m.cpu_regs.x; - uint8_t y = m.cpu_regs.y; - uint16_t pc; - uint8_t sp; - int psw; - int c; - int nz; - int dp; - - SET_PC( m.cpu_regs.pc ); - SET_SP( m.cpu_regs.sp ); - SET_PSW( m.cpu_regs.psw ); - - goto loop; - - - // Main loop - -cbranch_taken_loop: - pc += (int8_t) ram [pc]; -inc_pc_loop: - pc++; -loop: -{ - unsigned opcode; - unsigned data; - - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - opcode = ram [pc]; - if ( (rel_time += m.cycle_table [opcode]) > 0 ) - goto out_of_time; - - #ifdef SPC_CPU_OPCODE_HOOK - SPC_CPU_OPCODE_HOOK( GET_PC(), opcode ); - #endif - /* - //SUB_CASE_COUNTER( 1 ); - #define PROFILE_TIMER_LOOP( op, addr, len )\ - if ( opcode == op )\ - {\ - int cond = (unsigned) ((addr) - 0xFD) < 3 &&\ - pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\ - SUB_CASE_COUNTER( op && cond );\ - } - - PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 ); - PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 ); - PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 ); - */ - - // TODO: if PC is at end of memory, this will get wrong operand (very obscure) - pc++; - data = ram [pc]; - switch ( opcode ) - { - -// Common instructions - -#define BRANCH( cond )\ -{\ - pc++;\ - pc += (int8_t) data;\ - if ( cond )\ - goto loop;\ - pc -= (int8_t) data;\ - rel_time -= 2;\ - goto loop;\ -} - - case 0xF0: // BEQ - BRANCH( !(uint8_t) nz ) // 89% taken - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ) - - case 0x3F:{// CALL - int old_addr = GET_PC() + 2; - SET_PC( READ_PC16( pc ) ); - PUSH16( old_addr ); - goto loop; - } - - case 0x6F:// RET - { - uint8_t l, h; - POP( l ); - POP( h ); - SET_PC( l | (h << 8) ); - } - goto loop; - - case 0xE4: // MOV a,dp - ++pc; - // 80% from timer - READ_DP_TIMER( 0, data, a = nz ); - goto loop; - - case 0xFA:{// MOV dp,dp - int temp; - READ_DP_TIMER( -2, data, temp ); - data = temp + no_read_before_write ; - } - // fall through - case 0x8F:{// MOV dp,#imm - int temp = READ_PC( pc + 1 ); - pc += 2; - - #if !SPC_MORE_ACCURACY - { - int i = dp + temp; - ram [i] = (uint8_t) data; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 76% - { - REGS [i] = (uint8_t) data; - - // Registers other than $F2 and $F4-$F7 - if ( i != 2 && (i < 4 || i > 7)) // 12% - cpu_write_smp_reg( data, rel_time, i ); - } - } - #else - WRITE_DP( 0, temp, data ); - #endif - goto loop; - } - - case 0xC4: // MOV dp,a - ++pc; - #if !SPC_MORE_ACCURACY - { - int i = dp + data; - ram [i] = (uint8_t) a; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 39% - { - unsigned sel = i - 2; - REGS [i] = (uint8_t) a; - - if ( sel == 1 ) // 51% $F3 - dsp_write( a, rel_time ); - else if ( sel > 1 ) // 1% not $F2 or $F3 - cpu_write_smp_reg_( a, rel_time, i ); - } - } - #else - WRITE_DP( 0, data, a ); - #endif - goto loop; - -#define CASE( n ) case n: - -// Define common address modes based on opcode for immediate mode. Execution -// ends with data set to the address of the operand. -#define ADDR_MODES_( op )\ - CASE( op - 0x02 ) /* (X) */\ - data = x + dp;\ - pc--;\ - goto end_##op;\ - CASE( op + 0x0F ) /* (dp)+Y */\ - data = READ_PROG16( data + dp ) + y;\ - goto end_##op;\ - CASE( op - 0x01 ) /* (dp+X) */\ - data = READ_PROG16( ((uint8_t) (data + x)) + dp );\ - goto end_##op;\ - CASE( op + 0x0E ) /* abs+Y */\ - data += y;\ - goto abs_##op;\ - CASE( op + 0x0D ) /* abs+X */\ - data += x;\ - CASE( op - 0x03 ) /* abs */\ - abs_##op:\ - data += 0x100 * READ_PC( ++pc );\ - goto end_##op;\ - CASE( op + 0x0C ) /* dp+X */\ - data = (uint8_t) (data + x); - -#define ADDR_MODES_NO_DP( op )\ - ADDR_MODES_( op )\ - data += dp;\ - end_##op: - -#define ADDR_MODES( op )\ - ADDR_MODES_( op )\ - CASE( op - 0x04 ) /* dp */\ - data += dp;\ - end_##op: - -// 1. 8-bit Data Transmission Commands. Group I - - ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr - a = nz = READ( 0, data ); - goto inc_pc_loop; - - case 0xBF:{// MOV A,(X)+ - int temp = x + dp; - x = (uint8_t) (x + 1); - a = nz = READ( -1, temp ); - goto loop; - } - - case 0xE8: // MOV A,imm - a = data; - nz = data; - goto inc_pc_loop; - - case 0xF9: // MOV X,dp+Y - data = (uint8_t) (data + y); - case 0xF8: // MOV X,dp - READ_DP_TIMER( 0, data, x = nz ); - goto inc_pc_loop; - - case 0xE9: // MOV X,abs - data = READ_PC16( pc ); - ++pc; - data = READ( 0, data ); - case 0xCD: // MOV X,imm - x = data; - nz = data; - goto inc_pc_loop; - - case 0xFB: // MOV Y,dp+X - data = (uint8_t) (data + x); - case 0xEB: // MOV Y,dp - // 70% from timer - pc++; - READ_DP_TIMER( 0, data, y = nz ); - goto loop; - - case 0xEC:{// MOV Y,abs - int temp = READ_PC16( pc ); - pc += 2; - READ_TIMER( 0, temp, y = nz ); - //y = nz = READ( 0, temp ); - goto loop; - } - - case 0x8D: // MOV Y,imm - y = data; - nz = data; - goto inc_pc_loop; - -// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 - - ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A - WRITE( 0, data, a ); - goto inc_pc_loop; - - { - int temp; - case 0xCC: // MOV abs,Y - temp = y; - goto mov_abs_temp; - case 0xC9: // MOV abs,X - temp = x; - mov_abs_temp: - WRITE( 0, READ_PC16( pc ), temp ); - pc += 2; - goto loop; - } - - case 0xD9: // MOV dp+Y,X - data = (uint8_t) (data + y); - case 0xD8: // MOV dp,X - WRITE( 0, data + dp, x ); - goto inc_pc_loop; - - case 0xDB: // MOV dp+X,Y - data = (uint8_t) (data + x); - case 0xCB: // MOV dp,Y - WRITE( 0, data + dp, y ); - goto inc_pc_loop; - -// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. - - case 0x7D: // MOV A,X - a = x; - nz = x; - goto loop; - - case 0xDD: // MOV A,Y - a = y; - nz = y; - goto loop; - - case 0x5D: // MOV X,A - x = a; - nz = a; - goto loop; - - case 0xFD: // MOV Y,A - y = a; - nz = a; - goto loop; - - case 0x9D: // MOV X,SP - x = nz = GET_SP(); - goto loop; - - case 0xBD: // MOV SP,X - SET_SP( x ); - goto loop; - - //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2) - - case 0xAF: // MOV (X)+,A - WRITE_DP( 0, x, a + no_read_before_write ); - x = (uint8_t) (x + 1); - goto loop; - -// 5. 8-BIT LOGIC OPERATION COMMANDS - -#define LOGICAL_OP( op, func )\ - ADDR_MODES( op ) /* addr */\ - data = READ( 0, data );\ - case op: /* imm */\ - nz = a func##= data;\ - goto inc_pc_loop;\ - { unsigned addr;\ - case op + 0x11: /* X,Y */\ - data = READ_DP( -2, y );\ - addr = x + dp;\ - goto addr_##op;\ - case op + 0x01: /* dp,dp */\ - data = READ_DP( -3, data );\ - case op + 0x10:{/*dp,imm*/\ - uint16_t addr2 = pc + 1;\ - pc += 2;\ - addr = READ_PC( addr2 ) + dp;\ - }\ - addr_##op:\ - nz = data func READ( -1, addr );\ - WRITE( 0, addr, nz );\ - goto loop;\ - } - - LOGICAL_OP( 0x28, & ); // AND - - LOGICAL_OP( 0x08, | ); // OR - - LOGICAL_OP( 0x48, ^ ); // EOR - -// 4. 8-BIT ARITHMETIC OPERATION COMMANDS - - ADDR_MODES( 0x68 ) // CMP addr - data = READ( 0, data ); - case 0x68: // CMP imm - nz = a - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x79: // CMP (X),(Y) - data = READ_DP( -2, y ); - nz = READ_DP( -1, x ) - data; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x69: // CMP dp,dp - data = READ_DP( -3, data ); - case 0x78: // CMP dp,imm - nz = READ_DP( -1, READ_PC( ++pc ) ) - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x3E: // CMP X,dp - data += dp; - goto cmp_x_addr; - case 0x1E: // CMP X,abs - data = READ_PC16( pc ); - pc++; - cmp_x_addr: - data = READ( 0, data ); - case 0xC8: // CMP X,imm - nz = x - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x7E: // CMP Y,dp - data += dp; - goto cmp_y_addr; - case 0x5E: // CMP Y,abs - data = READ_PC16( pc ); - pc++; - cmp_y_addr: - data = READ( 0, data ); - case 0xAD: // CMP Y,imm - nz = y - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - { - int addr; - case 0xB9: // SBC (x),(y) - case 0x99: // ADC (x),(y) - pc--; // compensate for inc later - data = READ_DP( -2, y ); - addr = x + dp; - goto adc_addr; - case 0xA9: // SBC dp,dp - case 0x89: // ADC dp,dp - data = READ_DP( -3, data ); - case 0xB8: // SBC dp,imm - case 0x98: // ADC dp,imm - addr = READ_PC( ++pc ) + dp; - adc_addr: - nz = READ( -1, addr ); - goto adc_data; - -// catch ADC and SBC together, then decode later based on operand -#undef CASE -#define CASE( n ) case n: case (n) + 0x20: - ADDR_MODES( 0x88 ) // ADC/SBC addr - data = READ( 0, data ); - case 0xA8: // SBC imm - case 0x88: // ADC imm - addr = -1; // A - nz = a; - adc_data: { - int flags; - if ( opcode >= 0xA0 ) // SBC - data ^= 0xFF; - - flags = data ^ nz; - nz += data + (c >> 8 & 1); - flags ^= nz; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = nz; - if ( addr < 0 ) - { - a = (uint8_t) nz; - goto inc_pc_loop; - } - WRITE( 0, addr, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - } - - } - -// 6. ADDITION & SUBTRACTION COMMANDS - -#define INC_DEC_REG( reg, op )\ - nz = reg op;\ - reg = (uint8_t) nz;\ - goto loop; - - case 0xBC: INC_DEC_REG( a, + 1 ) // INC A - case 0x3D: INC_DEC_REG( x, + 1 ) // INC X - case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y - - case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A - case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X - case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y - - case 0x9B: // DEC dp+X - case 0xBB: // INC dp+X - data = (uint8_t) (data + x); - case 0x8B: // DEC dp - case 0xAB: // INC dp - data += dp; - goto inc_abs; - case 0x8C: // DEC abs - case 0xAC: // INC abs - data = READ_PC16( pc ); - pc++; - inc_abs: - nz = (opcode >> 4 & 2) - 1; - nz += READ( -1, data ); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - -// 7. SHIFT, ROTATION COMMANDS - - case 0x5C: // LSR A - c = 0; - case 0x7C:{// ROR A - nz = (c >> 1 & 0x80) | (a >> 1); - c = a << 8; - a = nz; - goto loop; - } - - case 0x1C: // ASL A - c = 0; - case 0x3C:{// ROL A - int temp = c >> 8 & 1; - c = a << 1; - nz = c | temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x0B: // ASL dp - c = 0; - data += dp; - goto rol_mem; - case 0x1B: // ASL dp+X - c = 0; - case 0x3B: // ROL dp+X - data = (uint8_t) (data + x); - case 0x2B: // ROL dp - data += dp; - goto rol_mem; - case 0x0C: // ASL abs - c = 0; - case 0x2C: // ROL abs - data = READ_PC16( pc ); - pc++; - rol_mem: - nz = c >> 8 & 1; - nz |= (c = READ( -1, data ) << 1); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - - case 0x4B: // LSR dp - c = 0; - data += dp; - goto ror_mem; - case 0x5B: // LSR dp+X - c = 0; - case 0x7B: // ROR dp+X - data = (uint8_t) (data + x); - case 0x6B: // ROR dp - data += dp; - goto ror_mem; - case 0x4C: // LSR abs - c = 0; - case 0x6C: // ROR abs - data = READ_PC16( pc ); - pc++; - ror_mem: { - int temp = READ( -1, data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - WRITE( 0, data, nz ); - goto inc_pc_loop; - } - - case 0x9F: // XCN - nz = a = (a >> 4) | (uint8_t) (a << 4); - goto loop; - -// 8. 16-BIT TRANSMISION COMMANDS - - case 0xBA: // MOVW YA,dp - a = READ_DP( -2, data ); - nz = (a & 0x7F) | (a >> 1); - y = READ_DP( 0, (uint8_t) (data + 1) ); - nz |= y; - goto inc_pc_loop; - - case 0xDA: // MOVW dp,YA - WRITE_DP( -1, data, a ); - WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write ); - goto inc_pc_loop; - -// 9. 16-BIT OPERATION COMMANDS - - case 0x3A: // INCW dp - case 0x1A:{// DECW dp - int temp; - // low byte - data += dp; - temp = READ( -3, data ); - temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW - nz = ((temp >> 1) | temp) & 0x7F; - WRITE( -2, data, /*(uint8_t)*/ temp ); - - // high byte - data = (uint8_t) (data + 1) + dp; - temp = (uint8_t) ((temp >> 8) + READ( -1, data )); - nz |= temp; - WRITE( 0, data, temp ); - - goto inc_pc_loop; - } - - case 0x7A: // ADDW YA,dp - case 0x9A:{// SUBW YA,dp - int lo = READ_DP( -2, data ); - int hi = READ_DP( 0, (uint8_t) (data + 1) ); - int result; - int flags; - - if ( opcode == 0x9A ) // SUBW - { - lo = (lo ^ 0xFF) + 1; - hi ^= 0xFF; - } - - lo += a; - result = y + hi + (lo >> 8); - flags = hi ^ y ^ result; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = result; - a = (uint8_t) lo; - result = (uint8_t) result; - y = result; - nz = (((lo >> 1) | lo) & 0x7F) | result; - - goto inc_pc_loop; - } - - case 0x5A: { // CMPW YA,dp - int temp = a - READ_DP( -1, data ); - nz = ((temp >> 1) | temp) & 0x7F; - temp = y + (temp >> 8); - temp -= READ_DP( 0, (uint8_t) (data + 1) ); - nz |= temp; - c = ~temp; - nz &= 0xFF; - goto inc_pc_loop; - } - -// 10. MULTIPLICATION & DIVISON COMMANDS - - case 0xCF: { // MUL YA - unsigned temp = y * a; - a = (uint8_t) temp; - nz = ((temp >> 1) | temp) & 0x7F; - y = (uint8_t) (temp >> 8); - nz |= y; - goto loop; - } - - case 0x9E: // DIV YA,X - { - unsigned ya = y * 0x100 + a; - - psw &= ~(h08 | v40); - - if ( y >= x ) - psw |= v40; - - if ( (y & 15) >= (x & 15) ) - psw |= h08; - - if ( y < x * 2 ) - { - a = ya / x; - y = ya - a * x; - } - else - { - a = 255 - (ya - x * 0x200) / (256 - x); - y = x + (ya - x * 0x200) % (256 - x); - } - - nz = (uint8_t) a; - a = (uint8_t) a; - y = (uint8_t) y; - - goto loop; - } - -// 11. DECIMAL COMPENSATION COMMANDS - - case 0xDF: // DAA - SUSPICIOUS_OPCODE( "DAA" ); - if ( a > 0x99 || c & 0x100 ) - { - a += 0x60; - c = 0x100; - } - - if ( (a & 0x0F) > 9 || psw & h08 ) - a += 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - - case 0xBE: // DAS - SUSPICIOUS_OPCODE( "DAS" ); - if ( a > 0x99 || !(c & 0x100) ) - { - a -= 0x60; - c = 0; - } - - if ( (a & 0x0F) > 9 || !(psw & h08) ) - a -= 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - -// 12. BRANCHING COMMANDS - - case 0x2F: // BRA rel - pc += (int8_t) data; - goto inc_pc_loop; - - case 0x30: // BMI - BRANCH( (nz & nz_neg_mask) ) - - case 0x10: // BPL - BRANCH( !(nz & nz_neg_mask) ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - - case 0x70: // BVS - BRANCH( psw & v40 ) - - case 0x50: // BVC - BRANCH( !(psw & v40) ) - - #define CBRANCH( cond )\ - {\ - pc++;\ - if ( cond )\ - goto cbranch_taken_loop;\ - rel_time -= 2;\ - goto inc_pc_loop;\ - } - - case 0x03: // BBS dp.bit,rel - case 0x23: - case 0x43: - case 0x63: - case 0x83: - case 0xA3: - case 0xC3: - case 0xE3: - CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 ) - - case 0x13: // BBC dp.bit,rel - case 0x33: - case 0x53: - case 0x73: - case 0x93: - case 0xB3: - case 0xD3: - case 0xF3: - CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) ) - - case 0xDE: // CBNE dp+X,rel - data = (uint8_t) (data + x); - // fall through - case 0x2E:{// CBNE dp,rel - int temp; - // 61% from timer - READ_DP_TIMER( -4, data, temp ); - CBRANCH( temp != a ) - } - - case 0x6E: { // DBNZ dp,rel - unsigned temp = READ_DP( -4, data ) - 1; - WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write ); - CBRANCH( temp ) - } - - case 0xFE: // DBNZ Y,rel - y = (uint8_t) (y - 1); - BRANCH( y ) - - case 0x1F: // JMP [abs+X] - SET_PC( READ_PC16( pc ) + x ); - // fall through - case 0x5F: // JMP abs - SET_PC( READ_PC16( pc ) ); - goto loop; - -// 13. SUB-ROUTINE CALL RETURN COMMANDS - - case 0x0F:{// BRK - int temp; - int ret_addr = GET_PC(); - SUSPICIOUS_OPCODE( "BRK" ); - SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified - PUSH16( ret_addr ); - GET_PSW( temp ); - psw = (psw | b10) & ~i04; - PUSH( temp ); - goto loop; - } - - case 0x4F:{// PCALL offset - int ret_addr = GET_PC() + 1; - SET_PC( 0xFF00 | data ); - PUSH16( ret_addr ); - goto loop; - } - - case 0x01: // TCALL n - case 0x11: - case 0x21: - case 0x31: - case 0x41: - case 0x51: - case 0x61: - case 0x71: - case 0x81: - case 0x91: - case 0xA1: - case 0xB1: - case 0xC1: - case 0xD1: - case 0xE1: - case 0xF1: { - int ret_addr = GET_PC(); - SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) ); - PUSH16( ret_addr ); - goto loop; - } - -// 14. STACK OPERATION COMMANDS - - { - int temp; - uint8_t l, h; - case 0x7F: // RET1 - POP (temp); - POP (l); - POP (h); - SET_PC( l | (h << 8) ); - goto set_psw; - case 0x8E: // POP PSW - POP( temp ); - set_psw: - SET_PSW( temp ); - goto loop; - } - - case 0x0D: { // PUSH PSW - int temp; - GET_PSW( temp ); - PUSH( temp ); - goto loop; - } - - case 0x2D: // PUSH A - PUSH( a ); - goto loop; - - case 0x4D: // PUSH X - PUSH( x ); - goto loop; - - case 0x6D: // PUSH Y - PUSH( y ); - goto loop; - - case 0xAE: // POP A - POP( a ); - goto loop; - - case 0xCE: // POP X - POP( x ); - goto loop; - - case 0xEE: // POP Y - POP( y ); - goto loop; - -// 15. BIT OPERATION COMMANDS - - case 0x02: // SET1 - case 0x22: - case 0x42: - case 0x62: - case 0x82: - case 0xA2: - case 0xC2: - case 0xE2: - case 0x12: // CLR1 - case 0x32: - case 0x52: - case 0x72: - case 0x92: - case 0xB2: - case 0xD2: - case 0xF2: { - int bit = 1 << (opcode >> 5); - int mask = ~bit; - if ( opcode & 0x10 ) - bit = 0; - data += dp; - WRITE( 0, data, (READ( -1, data ) & mask) | bit ); - goto inc_pc_loop; - } - - case 0x0E: // TSET1 abs - case 0x4E: // TCLR1 abs - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data ); - nz = (uint8_t) (a - temp); - temp &= ~a; - if ( opcode == 0x0E ) - temp |= a; - WRITE( 0, data, temp ); - } - goto loop; - - case 0x4A: // AND1 C,mem.bit - c &= MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x6A: // AND1 C,/mem.bit - c &= ~MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x0A: // OR1 C,mem.bit - c |= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x2A: // OR1 C,/mem.bit - c |= ~MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x8A: // EOR1 C,mem.bit - c ^= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0xEA: // NOT1 mem.bit - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -1, data & 0x1FFF ); - temp ^= 1 << (data >> 13); - WRITE( 0, data & 0x1FFF, temp ); - } - goto loop; - - case 0xCA: // MOV1 mem.bit,C - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data & 0x1FFF ); - unsigned bit = data >> 13; - temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit); - WRITE( 0, data & 0x1FFF, temp + no_read_before_write ); - } - goto loop; - - case 0xAA: // MOV1 C,mem.bit - c = MEM_BIT( 0 ); - pc += 2; - goto loop; - -// 16. PROGRAM PSW FLAG OPERATION COMMANDS - - case 0x60: // CLRC - c = 0; - goto loop; - - case 0x80: // SETC - c = ~0; - goto loop; - - case 0xED: // NOTC - c ^= 0x100; - goto loop; - - case 0xE0: // CLRV - psw &= ~(v40 | h08); - goto loop; - - case 0x20: // CLRP - dp = 0; - goto loop; - - case 0x40: // SETP - dp = 0x100; - goto loop; - - case 0xA0: // EI - SUSPICIOUS_OPCODE( "EI" ); - psw |= i04; - goto loop; - - case 0xC0: // DI - SUSPICIOUS_OPCODE( "DI" ); - psw &= ~i04; - goto loop; - -// 17. OTHER COMMANDS - - case 0x00: // NOP - goto loop; - - case 0xFF:{// STOP - // handle PC wrap-around - if ( pc == 0x0000 ) - { - debug_printf( "SPC: PC wrapped around\n" ); - goto loop; - } - } - // fall through - case 0xEF: // SLEEP - SUSPICIOUS_OPCODE( "STOP/SLEEP" ); - --pc; - rel_time = 0; - m.cpu_error = "SPC emulation error"; - goto stop; - } // switch - - assert( 0 ); // catch any unhandled instructions -} -out_of_time: - rel_time -= m.cycle_table [ ram [pc] ]; // undo partial execution of opcode -stop: - - // Uncache registers - m.cpu_regs.pc = (uint16_t) GET_PC(); - m.cpu_regs.sp = ( uint8_t) GET_SP(); - m.cpu_regs.a = ( uint8_t) a; - m.cpu_regs.x = ( uint8_t) x; - m.cpu_regs.y = ( uint8_t) y; - { - int temp; - GET_PSW( temp ); - m.cpu_regs.psw = (uint8_t) temp; - } -} -SPC_CPU_RUN_FUNC_END diff --git a/libraries/game-music-emu/gme/Spc_Dsp.cpp b/libraries/game-music-emu/gme/Spc_Dsp.cpp deleted file mode 100644 index 51556434d..000000000 --- a/libraries/game-music-emu/gme/Spc_Dsp.cpp +++ /dev/null @@ -1,704 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Spc_Dsp.h" - -#include "blargg_endian.h" -#include - -/* 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" - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -#if INT_MAX < 0x7FFFFFFF - #error "Requires that int type have at least 32 bits" -#endif - - -// TODO: add to blargg_endian.h -#define GET_LE16SA( addr ) ((int16_t) GET_LE16( addr )) -#define GET_LE16A( addr ) GET_LE16( addr ) -#define SET_LE16A( addr, data ) SET_LE16( addr, data ) - -static uint8_t const initial_regs [Spc_Dsp::register_count] = -{ - 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, - 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, - 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, - 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, - 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, - 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, - 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, - 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF -}; - -// if ( io < -32768 ) io = -32768; -// if ( io > 32767 ) io = 32767; -#define CLAMP16( io )\ -{\ - if ( (int16_t) io != io )\ - io = (io >> 31) ^ 0x7FFF;\ -} - -// Access global DSP register -#define REG(n) m.regs [r_##n] - -// Access voice DSP register -#define VREG(r,n) r [v_##n] - -#define WRITE_SAMPLES( l, r, out ) \ -{\ - out [0] = l;\ - out [1] = r;\ - out += 2;\ - if ( out >= m.out_end )\ - {\ - check( out == m.out_end );\ - check( m.out_end != &m.extra [extra_size] || \ - (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ - out = m.extra;\ - m.out_end = &m.extra [extra_size];\ - }\ -}\ - -void Spc_Dsp::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // must be even - if ( !out ) - { - out = m.extra; - size = extra_size; - } - m.out_begin = out; - m.out = out; - m.out_end = out + size; -} - -// Volume registers and efb are signed! Easy to forget int8_t cast. -// Prefixes are to avoid accidental use of locals with same names. - -// Interleved gauss table (to improve cache coherency) -// interleved_gauss [i] = gauss [(i & 1) * 256 + 255 - (i >> 1 & 0xFF)] -static short const interleved_gauss [512] = -{ - 370,1305, 366,1305, 362,1304, 358,1304, 354,1304, 351,1304, 347,1304, 343,1303, - 339,1303, 336,1303, 332,1302, 328,1302, 325,1301, 321,1300, 318,1300, 314,1299, - 311,1298, 307,1297, 304,1297, 300,1296, 297,1295, 293,1294, 290,1293, 286,1292, - 283,1291, 280,1290, 276,1288, 273,1287, 270,1286, 267,1284, 263,1283, 260,1282, - 257,1280, 254,1279, 251,1277, 248,1275, 245,1274, 242,1272, 239,1270, 236,1269, - 233,1267, 230,1265, 227,1263, 224,1261, 221,1259, 218,1257, 215,1255, 212,1253, - 210,1251, 207,1248, 204,1246, 201,1244, 199,1241, 196,1239, 193,1237, 191,1234, - 188,1232, 186,1229, 183,1227, 180,1224, 178,1221, 175,1219, 173,1216, 171,1213, - 168,1210, 166,1207, 163,1205, 161,1202, 159,1199, 156,1196, 154,1193, 152,1190, - 150,1186, 147,1183, 145,1180, 143,1177, 141,1174, 139,1170, 137,1167, 134,1164, - 132,1160, 130,1157, 128,1153, 126,1150, 124,1146, 122,1143, 120,1139, 118,1136, - 117,1132, 115,1128, 113,1125, 111,1121, 109,1117, 107,1113, 106,1109, 104,1106, - 102,1102, 100,1098, 99,1094, 97,1090, 95,1086, 94,1082, 92,1078, 90,1074, - 89,1070, 87,1066, 86,1061, 84,1057, 83,1053, 81,1049, 80,1045, 78,1040, - 77,1036, 76,1032, 74,1027, 73,1023, 71,1019, 70,1014, 69,1010, 67,1005, - 66,1001, 65, 997, 64, 992, 62, 988, 61, 983, 60, 978, 59, 974, 58, 969, - 56, 965, 55, 960, 54, 955, 53, 951, 52, 946, 51, 941, 50, 937, 49, 932, - 48, 927, 47, 923, 46, 918, 45, 913, 44, 908, 43, 904, 42, 899, 41, 894, - 40, 889, 39, 884, 38, 880, 37, 875, 36, 870, 36, 865, 35, 860, 34, 855, - 33, 851, 32, 846, 32, 841, 31, 836, 30, 831, 29, 826, 29, 821, 28, 816, - 27, 811, 27, 806, 26, 802, 25, 797, 24, 792, 24, 787, 23, 782, 23, 777, - 22, 772, 21, 767, 21, 762, 20, 757, 20, 752, 19, 747, 19, 742, 18, 737, - 17, 732, 17, 728, 16, 723, 16, 718, 15, 713, 15, 708, 15, 703, 14, 698, - 14, 693, 13, 688, 13, 683, 12, 678, 12, 674, 11, 669, 11, 664, 11, 659, - 10, 654, 10, 649, 10, 644, 9, 640, 9, 635, 9, 630, 8, 625, 8, 620, - 8, 615, 7, 611, 7, 606, 7, 601, 6, 596, 6, 592, 6, 587, 6, 582, - 5, 577, 5, 573, 5, 568, 5, 563, 4, 559, 4, 554, 4, 550, 4, 545, - 4, 540, 3, 536, 3, 531, 3, 527, 3, 522, 3, 517, 2, 513, 2, 508, - 2, 504, 2, 499, 2, 495, 2, 491, 2, 486, 1, 482, 1, 477, 1, 473, - 1, 469, 1, 464, 1, 460, 1, 456, 1, 451, 1, 447, 1, 443, 1, 439, - 0, 434, 0, 430, 0, 426, 0, 422, 0, 418, 0, 414, 0, 410, 0, 405, - 0, 401, 0, 397, 0, 393, 0, 389, 0, 385, 0, 381, 0, 378, 0, 374, -}; - - -//// Counters - -#define RATE( rate, div )\ - (rate >= div ? rate / div * 8 - 1 : rate - 1) - -static unsigned const counter_mask [32] = -{ - RATE( 2,2), RATE(2048,4), RATE(1536,3), - RATE(1280,5), RATE(1024,4), RATE( 768,3), - RATE( 640,5), RATE( 512,4), RATE( 384,3), - RATE( 320,5), RATE( 256,4), RATE( 192,3), - RATE( 160,5), RATE( 128,4), RATE( 96,3), - RATE( 80,5), RATE( 64,4), RATE( 48,3), - RATE( 40,5), RATE( 32,4), RATE( 24,3), - RATE( 20,5), RATE( 16,4), RATE( 12,3), - RATE( 10,5), RATE( 8,4), RATE( 6,3), - RATE( 5,5), RATE( 4,4), RATE( 3,3), - RATE( 2,4), - RATE( 1,4) -}; -#undef RATE - -inline void Spc_Dsp::init_counter() -{ - // counters start out with this synchronization - m.counters [0] = 1; - m.counters [1] = 0; - m.counters [2] = -0x20u; - m.counters [3] = 0x0B; - - int n = 2; - for ( int i = 1; i < 32; i++ ) - { - m.counter_select [i] = &m.counters [n]; - if ( !--n ) - n = 3; - } - m.counter_select [ 0] = &m.counters [0]; - m.counter_select [30] = &m.counters [2]; -} - -inline void Spc_Dsp::run_counter( int i ) -{ - int n = m.counters [i]; - if ( !(n-- & 7) ) - n -= 6 - i; - m.counters [i] = n; -} - -#define READ_COUNTER( rate )\ - (*m.counter_select [rate] & counter_mask [rate]) - - -//// Emulation - -void Spc_Dsp::run( int clock_count ) -{ - int new_phase = m.phase + clock_count; - int count = new_phase >> 5; - m.phase = new_phase & 31; - if ( !count ) - return; - - uint8_t* const ram = m.ram; - uint8_t const* const dir = &ram [REG(dir) * 0x100]; - int const slow_gaussian = (REG(pmon) >> 1) | REG(non); - int const noise_rate = REG(flg) & 0x1F; - - // Global volume - int mvoll = (int8_t) REG(mvoll); - int mvolr = (int8_t) REG(mvolr); - if ( mvoll * mvolr < m.surround_threshold ) - mvoll = -mvoll; // eliminate surround - - do - { - // KON/KOFF reading - if ( (m.every_other_sample ^= 1) != 0 ) - { - m.new_kon &= ~m.kon; - m.kon = m.new_kon; - m.t_koff = REG(koff); - } - - run_counter( 1 ); - run_counter( 2 ); - run_counter( 3 ); - - // Noise - if ( !READ_COUNTER( noise_rate ) ) - { - int feedback = (m.noise << 13) ^ (m.noise << 14); - m.noise = (feedback & 0x4000) ^ (m.noise >> 1); - } - - // Voices - int pmon_input = 0; - int main_out_l = 0; - int main_out_r = 0; - int echo_out_l = 0; - int echo_out_r = 0; - voice_t* v = m.voices; - uint8_t* v_regs = m.regs; - int vbit = 1; - do - { - #define SAMPLE_PTR(i) GET_LE16A( &dir [VREG(v_regs,srcn) * 4 + i * 2] ) - - int brr_header = ram [v->brr_addr]; - int kon_delay = v->kon_delay; - - // Pitch - int pitch = GET_LE16A( &VREG(v_regs,pitchl) ) & 0x3FFF; - if ( REG(pmon) & vbit ) - pitch += ((pmon_input >> 5) * pitch) >> 10; - - // KON phases - if ( --kon_delay >= 0 ) - { - v->kon_delay = kon_delay; - - // Get ready to start BRR decoding on next sample - if ( kon_delay == 4 ) - { - v->brr_addr = SAMPLE_PTR( 0 ); - v->brr_offset = 1; - v->buf_pos = v->buf; - brr_header = 0; // header is ignored on this sample - } - - // Envelope is never run during KON - v->env = 0; - v->hidden_env = 0; - - // Disable BRR decoding until last three samples - v->interp_pos = (kon_delay & 3 ? 0x4000 : 0); - - // Pitch is never added during KON - pitch = 0; - } - - int env = v->env; - - // Gaussian interpolation - { - int output = 0; - VREG(v_regs,envx) = (uint8_t) (env >> 4); - if ( env ) - { - // Make pointers into gaussian based on fractional position between samples - int offset = (unsigned) v->interp_pos >> 3 & 0x1FE; - short const* fwd = interleved_gauss + offset; - short const* rev = interleved_gauss + 510 - offset; // mirror left half of gaussian - - int const* in = &v->buf_pos [(unsigned) v->interp_pos >> 12]; - - if ( !(slow_gaussian & vbit) ) // 99% - { - // Faster approximation when exact sample value isn't necessary for pitch mod - output = (fwd [0] * in [0] + - fwd [1] * in [1] + - rev [1] * in [2] + - rev [0] * in [3]) >> 11; - output = (output * env) >> 11; - } - else - { - output = (int16_t) (m.noise * 2); - if ( !(REG(non) & vbit) ) - { - output = (fwd [0] * in [0]) >> 11; - output += (fwd [1] * in [1]) >> 11; - output += (rev [1] * in [2]) >> 11; - output = (int16_t) output; - output += (rev [0] * in [3]) >> 11; - - CLAMP16( output ); - output &= ~1; - } - output = (output * env) >> 11 & ~1; - } - - // Output - int l = output * v->volume [0]; - int r = output * v->volume [1]; - - main_out_l += l; - main_out_r += r; - - if ( REG(eon) & vbit ) - { - echo_out_l += l; - echo_out_r += r; - } - } - - pmon_input = output; - VREG(v_regs,outx) = (uint8_t) (output >> 8); - } - - // Soft reset or end of sample - if ( REG(flg) & 0x80 || (brr_header & 3) == 1 ) - { - v->env_mode = env_release; - env = 0; - } - - if ( m.every_other_sample ) - { - // KOFF - if ( m.t_koff & vbit ) - v->env_mode = env_release; - - // KON - if ( m.kon & vbit ) - { - v->kon_delay = 5; - v->env_mode = env_attack; - REG(endx) &= ~vbit; - } - } - - // Envelope - if ( !v->kon_delay ) - { - if ( v->env_mode == env_release ) // 97% - { - env -= 0x8; - v->env = env; - if ( env <= 0 ) - { - v->env = 0; - goto skip_brr; // no BRR decoding for you! - } - } - else // 3% - { - int rate; - int const adsr0 = VREG(v_regs,adsr0); - int env_data = VREG(v_regs,adsr1); - if ( adsr0 >= 0x80 ) // 97% ADSR - { - if ( v->env_mode > env_decay ) // 89% - { - env--; - env -= env >> 8; - rate = env_data & 0x1F; - - // optimized handling - v->hidden_env = env; - if ( READ_COUNTER( rate ) ) - goto exit_env; - v->env = env; - goto exit_env; - } - else if ( v->env_mode == env_decay ) - { - env--; - env -= env >> 8; - rate = (adsr0 >> 3 & 0x0E) + 0x10; - } - else // env_attack - { - rate = (adsr0 & 0x0F) * 2 + 1; - env += rate < 31 ? 0x20 : 0x400; - } - } - else // GAIN - { - int mode; - env_data = VREG(v_regs,gain); - mode = env_data >> 5; - if ( mode < 4 ) // direct - { - env = env_data * 0x10; - rate = 31; - } - else - { - rate = env_data & 0x1F; - if ( mode == 4 ) // 4: linear decrease - { - env -= 0x20; - } - else if ( mode < 6 ) // 5: exponential decrease - { - env--; - env -= env >> 8; - } - else // 6,7: linear increase - { - env += 0x20; - if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) - env += 0x8 - 0x20; // 7: two-slope linear increase - } - } - } - - // Sustain level - if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) - v->env_mode = env_sustain; - - v->hidden_env = env; - - // unsigned cast because linear decrease going negative also triggers this - if ( (unsigned) env > 0x7FF ) - { - env = (env < 0 ? 0 : 0x7FF); - if ( v->env_mode == env_attack ) - v->env_mode = env_decay; - } - - if ( !READ_COUNTER( rate ) ) - v->env = env; // nothing else is controlled by the counter - } - } - exit_env: - - { - // Apply pitch - int old_pos = v->interp_pos; - int interp_pos = (old_pos & 0x3FFF) + pitch; - if ( interp_pos > 0x7FFF ) - interp_pos = 0x7FFF; - v->interp_pos = interp_pos; - - // BRR decode if necessary - if ( old_pos >= 0x4000 ) - { - // Arrange the four input nybbles in 0xABCD order for easy decoding - int nybbles = ram [(v->brr_addr + v->brr_offset) & 0xFFFF] * 0x100 + - ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; - - // Advance read position - int const brr_block_size = 9; - int brr_offset = v->brr_offset; - if ( (brr_offset += 2) >= brr_block_size ) - { - // Next BRR block - int brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; - assert( brr_offset == brr_block_size ); - if ( brr_header & 1 ) - { - brr_addr = SAMPLE_PTR( 1 ); - if ( !v->kon_delay ) - REG(endx) |= vbit; - } - v->brr_addr = brr_addr; - brr_offset = 1; - } - v->brr_offset = brr_offset; - - // Decode - - // 0: >>1 1: <<0 2: <<1 ... 12: <<11 13-15: >>4 <<11 - static unsigned char const shifts [16 * 2] = { - 13,12,12,12,12,12,12,12,12,12,12, 12, 12, 16, 16, 16, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11 - }; - int const scale = brr_header >> 4; - int const right_shift = shifts [scale]; - int const left_shift = shifts [scale + 16]; - - // Write to next four samples in circular buffer - int* pos = v->buf_pos; - int* end; - - // Decode four samples - for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) - { - // Extract upper nybble and scale appropriately. Every cast is - // necessary to maintain correctness and avoid undef behavior - int s = int16_t(uint16_t((int16_t) nybbles >> right_shift) << left_shift); - - // Apply IIR filter (8 is the most commonly used) - int const filter = brr_header & 0x0C; - int const p1 = pos [brr_buf_size - 1]; - int const p2 = pos [brr_buf_size - 2] >> 1; - if ( filter >= 8 ) - { - s += p1; - s -= p2; - if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 - { - s += p2 >> 4; - s += (p1 * -3) >> 6; - } - else // s += p1 * 0.8984375 - p2 * 0.40625 - { - s += (p1 * -13) >> 7; - s += (p2 * 3) >> 4; - } - } - else if ( filter ) // s += p1 * 0.46875 - { - s += p1 >> 1; - s += (-p1) >> 5; - } - - // Adjust and write sample - CLAMP16( s ); - s = (int16_t) (s * 2); - pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around - } - - if ( pos >= &v->buf [brr_buf_size] ) - pos = v->buf; - v->buf_pos = pos; - } - } -skip_brr: - // Next voice - vbit <<= 1; - v_regs += 0x10; - v++; - } - while ( vbit < 0x100 ); - - // Echo position - int echo_offset = m.echo_offset; - uint8_t* const echo_ptr = &ram [(REG(esa) * 0x100 + echo_offset) & 0xFFFF]; - if ( !echo_offset ) - m.echo_length = (REG(edl) & 0x0F) * 0x800; - echo_offset += 4; - if ( echo_offset >= m.echo_length ) - echo_offset = 0; - m.echo_offset = echo_offset; - - // FIR - int echo_in_l = GET_LE16SA( echo_ptr + 0 ); - int echo_in_r = GET_LE16SA( echo_ptr + 2 ); - - int (*echo_hist_pos) [2] = m.echo_hist_pos; - if ( ++echo_hist_pos >= &m.echo_hist [echo_hist_size] ) - echo_hist_pos = m.echo_hist; - m.echo_hist_pos = echo_hist_pos; - - echo_hist_pos [0] [0] = echo_hist_pos [8] [0] = echo_in_l; - echo_hist_pos [0] [1] = echo_hist_pos [8] [1] = echo_in_r; - - #define CALC_FIR_( i, in ) ((in) * (int8_t) REG(fir + i * 0x10)) - echo_in_l = CALC_FIR_( 7, echo_in_l ); - echo_in_r = CALC_FIR_( 7, echo_in_r ); - - #define CALC_FIR( i, ch ) CALC_FIR_( i, echo_hist_pos [i + 1] [ch] ) - #define DO_FIR( i )\ - echo_in_l += CALC_FIR( i, 0 );\ - echo_in_r += CALC_FIR( i, 1 ); - DO_FIR( 0 ); - DO_FIR( 1 ); - DO_FIR( 2 ); - #if defined (__MWERKS__) && __MWERKS__ < 0x3200 - __eieio(); // keeps compiler from stupidly "caching" things in memory - #endif - DO_FIR( 3 ); - DO_FIR( 4 ); - DO_FIR( 5 ); - DO_FIR( 6 ); - - // Echo out - if ( !(REG(flg) & 0x20) ) - { - int l = (echo_out_l >> 7) + ((echo_in_l * (int8_t) REG(efb)) >> 14); - int r = (echo_out_r >> 7) + ((echo_in_r * (int8_t) REG(efb)) >> 14); - - // just to help pass more validation tests - #if SPC_MORE_ACCURACY - l &= ~1; - r &= ~1; - #endif - - CLAMP16( l ); - CLAMP16( r ); - - SET_LE16A( echo_ptr + 0, l ); - SET_LE16A( echo_ptr + 2, r ); - } - - // Sound out - 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; - - CLAMP16( l ); - CLAMP16( r ); - - if ( (REG(flg) & 0x40) ) - { - l = 0; - r = 0; - } - - sample_t* out = m.out; - WRITE_SAMPLES( l, r, out ); - m.out = out; - } - while ( --count ); -} - - -//// Setup - -void Spc_Dsp::mute_voices( int mask ) -{ - m.mute_mask = mask; - for ( int i = 0; i < voice_count; i++ ) - { - m.voices [i].enabled = (mask >> i & 1) - 1; - update_voice_vol( i * 0x10 ); - } -} - -void Spc_Dsp::init( void* ram_64k ) -{ - m.ram = (uint8_t*) ram_64k; - mute_voices( 0 ); - disable_surround( false ); - set_output( 0, 0 ); - reset(); - - #ifndef NDEBUG - // be sure this sign-extends - assert( (int16_t) 0x8000 == -0x8000 ); - - // be sure right shift preserves sign - assert( (-1 >> 1) == -1 ); - - // check clamp macro - int i; - i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); - i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); - - blargg_verify_byte_order(); - #endif -} - -void Spc_Dsp::soft_reset_common() -{ - require( m.ram ); // init() must have been called already - - m.noise = 0x4000; - m.echo_hist_pos = m.echo_hist; - m.every_other_sample = 1; - m.echo_offset = 0; - m.phase = 0; - - init_counter(); -} - -void Spc_Dsp::soft_reset() -{ - REG(flg) = 0xE0; - soft_reset_common(); -} - -void Spc_Dsp::load( uint8_t const regs [register_count] ) -{ - memcpy( m.regs, regs, sizeof m.regs ); - memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); - - // Internal state - int i; - for ( i = voice_count; --i >= 0; ) - { - voice_t& v = m.voices [i]; - v.brr_offset = 1; - v.buf_pos = v.buf; - } - m.new_kon = REG(kon); - - mute_voices( m.mute_mask ); - soft_reset_common(); -} - -void Spc_Dsp::reset() { load( initial_regs ); } diff --git a/libraries/game-music-emu/gme/Spc_Dsp.h b/libraries/game-music-emu/gme/Spc_Dsp.h deleted file mode 100644 index b364f0845..000000000 --- a/libraries/game-music-emu/gme/Spc_Dsp.h +++ /dev/null @@ -1,207 +0,0 @@ -// Fast SNES SPC-700 DSP emulator (about 3x speed of accurate one) - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef SPC_DSP_H -#define SPC_DSP_H - -#include "blargg_common.h" - -struct Spc_Dsp { -public: -// Setup - - // Initializes DSP and has it use the 64K RAM provided - void init( void* ram_64k ); - - // Sets destination for output samples. If out is NULL or out_size is 0, - // doesn't generate any. - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since it was last set, always - // a multiple of 2. Undefined if more samples were generated than - // output buffer could hold. - int sample_count() const; - -// Emulation - - // Resets DSP to power-on state - void reset(); - - // Emulates pressing reset switch on SNES - void soft_reset(); - - // Reads/writes DSP registers. For accuracy, you must first call spc_run_dsp() - // to catch the DSP up to present. - int read ( int addr ) const; - void write( int addr, int data ); - - // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks - // a pair of samples is be generated. - void run( int clock_count ); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (overrides VxVOL with 0). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - - // If true, prevents channels and global volumes from being phase-negated - void disable_surround( bool disable = true ); - -// State - - // Resets DSP and uses supplied values to initialize registers - enum { register_count = 128 }; - void load( uint8_t const regs [register_count] ); - -// DSP register addresses - - // Global registers - enum { - r_mvoll = 0x0C, r_mvolr = 0x1C, - r_evoll = 0x2C, r_evolr = 0x3C, - r_kon = 0x4C, r_koff = 0x5C, - r_flg = 0x6C, r_endx = 0x7C, - r_efb = 0x0D, r_pmon = 0x2D, - r_non = 0x3D, r_eon = 0x4D, - r_dir = 0x5D, r_esa = 0x6D, - r_edl = 0x7D, - r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F - }; - - // Voice registers - enum { - v_voll = 0x00, v_volr = 0x01, - v_pitchl = 0x02, v_pitchh = 0x03, - v_srcn = 0x04, v_adsr0 = 0x05, - v_adsr1 = 0x06, v_gain = 0x07, - v_envx = 0x08, v_outx = 0x09 - }; - -public: - enum { extra_size = 16 }; - sample_t* extra() { return m.extra; } - sample_t const* out_pos() const { return m.out; } -public: - BLARGG_DISABLE_NOTHROW - - enum { echo_hist_size = 8 }; - - enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; - enum { brr_buf_size = 12 }; - struct voice_t - { - int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) - int* buf_pos; // place in buffer where next samples will be decoded - int interp_pos; // relative fractional position in sample (0x1000 = 1.0) - int brr_addr; // address of current BRR block - int brr_offset; // current decoding offset in BRR block - int kon_delay; // KON delay/current setup phase - env_mode_t env_mode; - int env; // current envelope level - int hidden_env; // used by GAIN mode 7, very obscure quirk - int volume [2]; // copy of volume from DSP registers, with surround disabled - int enabled; // -1 if enabled, 0 if muted - }; -private: - struct state_t - { - uint8_t regs [register_count]; - - // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) - int echo_hist [echo_hist_size * 2] [2]; - int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] - - int every_other_sample; // toggles every sample - int kon; // KON value when last checked - int noise; - int echo_offset; // offset from ESA in echo buffer - int echo_length; // number of bytes that echo_offset will stop at - int phase; // next clock cycle to run (0-31) - unsigned counters [4]; - - int new_kon; - int t_koff; - - voice_t voices [voice_count]; - - unsigned* counter_select [32]; - - // non-emulation state - uint8_t* ram; // 64K shared RAM between DSP and SMP - int mute_mask; - int surround_threshold; - sample_t* out; - sample_t* out_end; - sample_t* out_begin; - sample_t extra [extra_size]; - }; - state_t m; - - void init_counter(); - void run_counter( int ); - void soft_reset_common(); - void write_outline( int addr, int data ); - void update_voice_vol( int addr ); -}; - -#include - -inline int Spc_Dsp::sample_count() const { return m.out - m.out_begin; } - -inline int Spc_Dsp::read( int addr ) const -{ - assert( (unsigned) addr < register_count ); - return m.regs [addr]; -} - -inline void Spc_Dsp::update_voice_vol( int addr ) -{ - int l = (int8_t) m.regs [addr + v_voll]; - int r = (int8_t) m.regs [addr + v_volr]; - - if ( l * r < m.surround_threshold ) - { - // signs differ, so negate those that are negative - l ^= l >> 7; - r ^= r >> 7; - } - - voice_t& v = m.voices [addr >> 4]; - int enabled = v.enabled; - v.volume [0] = l & enabled; - v.volume [1] = r & enabled; -} - -inline void Spc_Dsp::write( int addr, int data ) -{ - assert( (unsigned) addr < register_count ); - - m.regs [addr] = (uint8_t) data; - int low = addr & 0x0F; - if ( low < 0x2 ) // voice volumes - { - update_voice_vol( low ^ addr ); - } - else if ( low == 0xC ) - { - if ( addr == r_kon ) - m.new_kon = (uint8_t) data; - - if ( addr == r_endx ) // always cleared, regardless of data written - m.regs [r_endx] = 0; - } -} - -inline void Spc_Dsp::disable_surround( bool disable ) -{ - m.surround_threshold = disable ? 0 : -0x4000; -} - -#define SPC_NO_COPY_STATE_FUNCS 1 - -#define SPC_LESS_ACCURATE 1 - -#endif diff --git a/libraries/game-music-emu/gme/Spc_Emu.cpp b/libraries/game-music-emu/gme/Spc_Emu.cpp deleted file mode 100644 index 0f45d8739..000000000 --- a/libraries/game-music-emu/gme/Spc_Emu.cpp +++ /dev/null @@ -1,358 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Spc_Emu.h" - -#include "blargg_endian.h" -#include -#include - -/* Copyright (C) 2004-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -// TODO: support Spc_Filter's bass - -Spc_Emu::Spc_Emu() -{ - set_type( gme_spc_type ); - - static const char* const names [Snes_Spc::voice_count] = { - "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", "DSP 8" - }; - set_voice_names( names ); - - set_gain( 1.4 ); -} - -Spc_Emu::~Spc_Emu() { } - -// Track info - -long const trailer_offset = 0x10200; - -byte const* Spc_Emu::trailer() const { return &file_data [min( file_size, trailer_offset )]; } - -long Spc_Emu::trailer_size() const { return max( 0L, file_size - trailer_offset ); } - -static void get_spc_xid6( byte const* begin, long size, track_info_t* out ) -{ - // header - byte const* end = begin + size; - if ( size < 8 || memcmp( begin, "xid6", 4 ) ) - { - check( false ); - return; - } - long info_size = get_le32( begin + 4 ); - byte const* in = begin + 8; - if ( end - in > info_size ) - { - debug_printf( "Extra data after SPC xid6 info\n" ); - end = in + info_size; - } - - int year = 0; - char copyright [256 + 5]; - int copyright_len = 0; - int const year_len = 5; - - while ( end - in >= 4 ) - { - // header - int id = in [0]; - int data = in [3] * 0x100 + in [2]; - int type = in [1]; - int len = type ? data : 0; - in += 4; - if ( len > end - in ) - { - check( false ); - break; // block goes past end of data - } - - // handle specific block types - char* field = 0; - switch ( id ) - { - case 0x01: field = out->song; break; - case 0x02: field = out->game; break; - case 0x03: field = out->author; break; - case 0x04: field = out->dumper; break; - case 0x07: field = out->comment; break; - case 0x14: year = data; break; - - //case 0x30: // intro length - // Many SPCs have intro length set wrong for looped tracks, making it useless - /* - case 0x30: - check( len == 4 ); - if ( len >= 4 ) - { - out->intro_length = get_le32( in ) / 64; - if ( out->length > 0 ) - { - long loop = out->length - out->intro_length; - if ( loop >= 2000 ) - out->loop_length = loop; - } - } - break; - */ - - case 0x13: - copyright_len = min( len, (int) sizeof copyright - year_len ); - memcpy( ©right [year_len], in, copyright_len ); - break; - - default: - if ( id < 0x01 || (id > 0x07 && id < 0x10) || - (id > 0x14 && id < 0x30) || id > 0x36 ) - debug_printf( "Unknown SPC xid6 block: %X\n", (int) id ); - break; - } - if ( field ) - { - check( type == 1 ); - Gme_File::copy_field_( field, (char const*) in, len ); - } - - // skip to next block - in += len; - - // blocks are supposed to be 4-byte aligned with zero-padding... - byte const* unaligned = in; - while ( (in - begin) & 3 && in < end ) - { - if ( *in++ != 0 ) - { - // ...but some files have no padding - in = unaligned; - debug_printf( "SPC info tag wasn't properly padded to align\n" ); - break; - } - } - } - - char* p = ©right [year_len]; - if ( year ) - { - *--p = ' '; - for ( int n = 4; n--; ) - { - *--p = char (year % 10 + '0'); - year /= 10; - } - copyright_len += year_len; - } - if ( copyright_len ) - Gme_File::copy_field_( out->copyright, p, copyright_len ); - - check( in == end ); -} - -static void get_spc_info( Spc_Emu::header_t const& h, byte const* xid6, long xid6_size, - track_info_t* out ) -{ - // decode length (can be in text or binary format, sometimes ambiguous ugh) - long len_secs = 0; - for ( int i = 0; i < 3; i++ ) - { - unsigned n = h.len_secs [i] - '0'; - if ( n > 9 ) - { - // ignore single-digit text lengths - // (except if author field is present and begins at offset 1, ugh) - if ( i == 1 && (h.author [0] || !h.author [1]) ) - len_secs = 0; - break; - } - len_secs *= 10; - len_secs += n; - } - if ( !len_secs || len_secs > 0x1FFF ) - len_secs = get_le16( h.len_secs ); - if ( len_secs < 0x1FFF ) - out->length = len_secs * 1000; - - int offset = (h.author [0] < ' ' || unsigned (h.author [0] - '0') <= 9); - Gme_File::copy_field_( out->author, &h.author [offset], sizeof h.author - offset ); - - GME_COPY_FIELD( h, out, song ); - GME_COPY_FIELD( h, out, game ); - GME_COPY_FIELD( h, out, dumper ); - GME_COPY_FIELD( h, out, comment ); - - if ( xid6_size ) - get_spc_xid6( xid6, xid6_size, out ); -} - -blargg_err_t Spc_Emu::track_info_( track_info_t* out, int ) const -{ - get_spc_info( header(), trailer(), trailer_size(), out ); - return 0; -} - -static blargg_err_t check_spc_header( void const* header ) -{ - if ( memcmp( header, "SNES-SPC700 Sound File Data", 27 ) ) - return gme_wrong_file_type; - return 0; -} - -struct Spc_File : Gme_Info_ -{ - Spc_Emu::header_t header; - blargg_vector xid6; - - Spc_File() { set_type( gme_spc_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - long file_size = in.remain(); - if ( file_size < Snes_Spc::spc_min_file_size ) - return gme_wrong_file_type; - RETURN_ERR( in.read( &header, Spc_Emu::header_size ) ); - RETURN_ERR( check_spc_header( header.tag ) ); - long const xid6_offset = 0x10200; - long xid6_size = file_size - xid6_offset; - if ( xid6_size > 0 ) - { - RETURN_ERR( xid6.resize( xid6_size ) ); - RETURN_ERR( in.skip( xid6_offset - Spc_Emu::header_size ) ); - RETURN_ERR( in.read( xid6.begin(), xid6.size() ) ); - } - return 0; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - get_spc_info( header, xid6.begin(), xid6.size(), out ); - return 0; - } -}; - -static Music_Emu* new_spc_emu () { return BLARGG_NEW Spc_Emu ; } -static Music_Emu* new_spc_file() { return BLARGG_NEW Spc_File; } - -static gme_type_t_ const gme_spc_type_ = { "Super Nintendo", 1, &new_spc_emu, &new_spc_file, "SPC", 0 }; -BLARGG_EXPORT extern gme_type_t const gme_spc_type = &gme_spc_type_; - - -// Setup - -blargg_err_t Spc_Emu::set_sample_rate_( long sample_rate ) -{ - RETURN_ERR( apu.init() ); - enable_accuracy( false ); - if ( sample_rate != native_sample_rate ) - { - RETURN_ERR( resampler.buffer_size( native_sample_rate / 20 * 2 ) ); - resampler.time_ratio( (double) native_sample_rate / sample_rate, 0.9965 ); - } - return 0; -} - -void Spc_Emu::enable_accuracy_( bool b ) -{ - Music_Emu::enable_accuracy_( b ); - filter.enable( b ); -} - -void Spc_Emu::mute_voices_( int m ) -{ - Music_Emu::mute_voices_( m ); - apu.mute_voices( m ); -} - -blargg_err_t Spc_Emu::load_mem_( byte const* in, long size ) -{ - assert( offsetof (header_t,unused2 [46]) == header_size ); - file_data = in; - file_size = size; - set_voice_count( Snes_Spc::voice_count ); - if ( size < Snes_Spc::spc_min_file_size ) - return gme_wrong_file_type; - return check_spc_header( in ); -} - -// Emulation - -void Spc_Emu::set_tempo_( double t ) -{ - apu.set_tempo( (int) (t * apu.tempo_unit) ); -} - -blargg_err_t Spc_Emu::start_track_( int track ) -{ - RETURN_ERR( Music_Emu::start_track_( track ) ); - resampler.clear(); - filter.clear(); - RETURN_ERR( apu.load_spc( file_data, file_size ) ); - filter.set_gain( (int) (gain() * SPC_Filter::gain_unit) ); - apu.clear_echo(); - track_info_t spc_info; - RETURN_ERR( track_info_( &spc_info, track ) ); - - // Set a default track length, need a non-zero fadeout - if ( autoload_playback_limit() && ( spc_info.length > 0 ) ) - set_fade ( spc_info.length, 50 ); - 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 ) -{ - if ( sample_rate() != native_sample_rate ) - { - count = long (count * resampler.ratio()) & ~1; - count -= resampler.skip_input( count ); - } - - // TODO: shouldn't skip be adjusted for the 64 samples read afterwards? - - if ( count > 0 ) - { - RETURN_ERR( apu.skip( count ) ); - filter.clear(); - } - - // eliminate pop due to resampler - const int resampler_latency = 64; - sample_t buf [resampler_latency]; - return play_( resampler_latency, buf ); -} - -blargg_err_t Spc_Emu::play_( long count, sample_t* out ) -{ - if ( sample_rate() == native_sample_rate ) - return play_and_filter( count, out ); - - long remain = count; - while ( remain > 0 ) - { - remain -= resampler.read( &out [count - remain], remain ); - if ( remain > 0 ) - { - long n = resampler.max_write(); - RETURN_ERR( play_and_filter( n, resampler.buffer() ) ); - resampler.write( n ); - } - } - check( remain == 0 ); - return 0; -} diff --git a/libraries/game-music-emu/gme/Spc_Emu.h b/libraries/game-music-emu/gme/Spc_Emu.h deleted file mode 100644 index 76e1ac63d..000000000 --- a/libraries/game-music-emu/gme/Spc_Emu.h +++ /dev/null @@ -1,82 +0,0 @@ -// Super Nintendo SPC music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef SPC_EMU_H -#define SPC_EMU_H - -#include "Fir_Resampler.h" -#include "Music_Emu.h" -#include "Snes_Spc.h" -#include "Spc_Filter.h" - -class Spc_Emu : public Music_Emu { -public: - // The Super Nintendo hardware samples at 32kHz. Other sample rates are - // handled by resampling the 32kHz output; emulation accuracy is not affected. - enum { native_sample_rate = 32000 }; - - // SPC file header - enum { header_size = 0x100 }; - struct header_t - { - char tag [35]; - byte format; - byte version; - byte pc [2]; - byte a, x, y, psw, sp; - byte unused [2]; - char song [32]; - char game [32]; - char dumper [16]; - char comment [32]; - byte date [11]; - byte len_secs [3]; - byte fade_msec [4]; - char author [32]; // sometimes first char should be skipped (see official SPC spec) - byte mute_mask; - byte emulator; - byte unused2 [46]; - }; - - // Header for currently loaded file - header_t const& header() const { return *(header_t const*) file_data; } - - // Prevents channels and global volumes from being phase-negated - void disable_surround( bool disable = true ); - - static gme_type_t static_type() { return gme_spc_type; } - -public: - // deprecated - using Music_Emu::load; - blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader - { return load_remaining_( &h, sizeof h, in ); } - byte const* trailer() const; // use track_info() - long trailer_size() const; - -public: - Spc_Emu(); - ~Spc_Emu(); -protected: - blargg_err_t load_mem_( byte const*, long ); - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t set_sample_rate_( long ); - blargg_err_t start_track_( int ); - blargg_err_t play_( long, sample_t* ); - blargg_err_t skip_( long ); - void mute_voices_( int ); - void set_tempo_( double ); - void enable_accuracy_( bool ); -private: - byte const* file_data; - long file_size; - Fir_Resampler<24> resampler; - SPC_Filter filter; - 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 ); } - -#endif diff --git a/libraries/game-music-emu/gme/Spc_Filter.cpp b/libraries/game-music-emu/gme/Spc_Filter.cpp deleted file mode 100644 index 2cc77fc93..000000000 --- a/libraries/game-music-emu/gme/Spc_Filter.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Spc_Filter.h" - -#include - -/* 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; - } - } -} diff --git a/libraries/game-music-emu/gme/Spc_Filter.h b/libraries/game-music-emu/gme/Spc_Filter.h deleted file mode 100644 index d9994af5f..000000000 --- a/libraries/game-music-emu/gme/Spc_Filter.h +++ /dev/null @@ -1,53 +0,0 @@ -// Simple low-pass and high-pass filter to better match sound output of a SNES - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#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 diff --git a/libraries/game-music-emu/gme/Vgm_Emu.cpp b/libraries/game-music-emu/gme/Vgm_Emu.cpp deleted file mode 100644 index 8f19b7de5..000000000 --- a/libraries/game-music-emu/gme/Vgm_Emu.cpp +++ /dev/null @@ -1,434 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Vgm_Emu.h" - -#include "blargg_endian.h" -#include -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -double const fm_gain = 3.0; // FM emulators are internally quieter to avoid 16-bit overflow -double const rolloff = 0.990; -double const oversample_factor = 1.5; - -Vgm_Emu::Vgm_Emu() -{ - disable_oversampling_ = false; - psg_rate = 0; - set_type( gme_vgm_type ); - - static int const types [8] = { - wave_type | 1, wave_type | 0, wave_type | 2, noise_type | 0 - }; - set_voice_types( types ); - - set_silence_lookahead( 1 ); // tracks should already be trimmed - - set_equalizer( make_equalizer( -14.0, 80 ) ); -} - -Vgm_Emu::~Vgm_Emu() { } - -// Track info - -static byte const* skip_gd3_str( byte const* in, byte const* end ) -{ - while ( end - in >= 2 ) - { - in += 2; - if ( !(in [-2] | in [-1]) ) - break; - } - return in; -} - -static byte const* get_gd3_str( byte const* in, byte const* end, char* field ) -{ - byte const* mid = skip_gd3_str( in, end ); - int len = (mid - in) / 2 - 1; - if ( len > 0 ) - { - len = min( len, (int) Gme_File::max_field_ ); - field [len] = 0; - for ( int i = 0; i < len; i++ ) - field [i] = (in [i * 2 + 1] ? '?' : in [i * 2]); // TODO: convert to utf-8 - } - return mid; -} - -static byte const* get_gd3_pair( byte const* in, byte const* end, char* field ) -{ - return skip_gd3_str( get_gd3_str( in, end, field ), end ); -} - -static void parse_gd3( byte const* in, byte const* end, track_info_t* out ) -{ - in = get_gd3_pair( in, end, out->song ); - in = get_gd3_pair( in, end, out->game ); - in = get_gd3_pair( in, end, out->system ); - in = get_gd3_pair( in, end, out->author ); - in = get_gd3_str ( in, end, out->copyright ); - in = get_gd3_pair( in, end, out->dumper ); - in = get_gd3_str ( in, end, out->comment ); -} - -int const gd3_header_size = 12; - -static long check_gd3_header( byte const* h, long remain ) -{ - if ( remain < gd3_header_size ) return 0; - if ( memcmp( h, "Gd3 ", 4 ) ) return 0; - if ( get_le32( h + 4 ) >= 0x200 ) return 0; - - long gd3_size = get_le32( h + 8 ); - if ( gd3_size > remain - gd3_header_size ) return 0; - - return gd3_size; -} - -byte const* Vgm_Emu::gd3_data( int* size ) const -{ - if ( size ) - *size = 0; - - long gd3_offset = get_le32( header().gd3_offset ) - 0x2C; - if ( gd3_offset < 0 ) - return 0; - - byte const* gd3 = data + header_size + gd3_offset; - long gd3_size = check_gd3_header( gd3, data_end - gd3 ); - if ( !gd3_size ) - return 0; - - if ( size ) - *size = gd3_size + gd3_header_size; - - return gd3; -} - -static void get_vgm_length( Vgm_Emu::header_t const& h, track_info_t* out ) -{ - long length = get_le32( h.track_duration ) * 10 / 441; - if ( length > 0 ) - { - long loop = get_le32( h.loop_duration ); - if ( loop > 0 && get_le32( h.loop_offset ) ) - { - out->loop_length = loop * 10 / 441; - out->intro_length = length - out->loop_length; - } - else - { - out->length = length; // 1000 / 44100 (VGM files used 44100 as timebase) - out->intro_length = length; // make it clear that track is no longer than length - out->loop_length = 0; - } - } -} - -blargg_err_t Vgm_Emu::track_info_( track_info_t* out, int ) const -{ - get_vgm_length( header(), out ); - - int size; - byte const* gd3 = gd3_data( &size ); - if ( gd3 ) - parse_gd3( gd3 + gd3_header_size, gd3 + size, out ); - - return 0; -} - -static blargg_err_t check_vgm_header( Vgm_Emu::header_t const& h ) -{ - if ( memcmp( h.tag, "Vgm ", 4 ) ) - return gme_wrong_file_type; - return 0; -} - -struct Vgm_File : Gme_Info_ -{ - Vgm_Emu::header_t h; - blargg_vector gd3; - - Vgm_File() { set_type( gme_vgm_type ); } - - blargg_err_t load_( Data_Reader& in ) - { - long file_size = in.remain(); - if ( file_size <= Vgm_Emu::header_size ) - return gme_wrong_file_type; - - RETURN_ERR( in.read( &h, Vgm_Emu::header_size ) ); - RETURN_ERR( check_vgm_header( h ) ); - - long gd3_offset = get_le32( h.gd3_offset ) - 0x2C; - long remain = file_size - Vgm_Emu::header_size - gd3_offset; - byte gd3_h [gd3_header_size]; - if ( gd3_offset > 0 && remain >= gd3_header_size ) - { - RETURN_ERR( in.skip( gd3_offset ) ); - RETURN_ERR( in.read( gd3_h, sizeof gd3_h ) ); - long gd3_size = check_gd3_header( gd3_h, remain ); - if ( gd3_size ) - { - RETURN_ERR( gd3.resize( gd3_size ) ); - RETURN_ERR( in.read( gd3.begin(), gd3.size() ) ); - } - } - return 0; - } - - blargg_err_t track_info_( track_info_t* out, int ) const - { - get_vgm_length( h, out ); - if ( gd3.size() ) - parse_gd3( gd3.begin(), gd3.end(), out ); - return 0; - } -}; - -static Music_Emu* new_vgm_emu () { return BLARGG_NEW Vgm_Emu ; } -static Music_Emu* new_vgm_file() { return BLARGG_NEW Vgm_File; } - -static gme_type_t_ const gme_vgm_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGM", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_vgm_type = &gme_vgm_type_; - -static gme_type_t_ const gme_vgz_type_ = { "Sega SMS/Genesis", 1, &new_vgm_emu, &new_vgm_file, "VGZ", 1 }; -BLARGG_EXPORT extern gme_type_t const gme_vgz_type = &gme_vgz_type_; - - -// Setup - -void Vgm_Emu::set_tempo_( double t ) -{ - if ( psg_rate ) - { - vgm_rate = (long) (44100 * t + 0.5); - blip_time_factor = (long) floor( double (1L << blip_time_bits) / vgm_rate * psg_rate + 0.5 ); - //debug_printf( "blip_time_factor: %ld\n", blip_time_factor ); - //debug_printf( "vgm_rate: %ld\n", vgm_rate ); - // 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 ); - //vgm_rate = (long) floor( double (1L << blip_time_bits) * psg_rate / blip_time_factor + 0.5 ); - - fm_time_factor = 2 + (long) floor( fm_rate * (1L << fm_time_bits) / vgm_rate + 0.5 ); - } -} - -blargg_err_t Vgm_Emu::set_sample_rate_( long sample_rate ) -{ - RETURN_ERR( blip_buf.set_sample_rate( sample_rate, 1000 / 30 ) ); - return Classic_Emu::set_sample_rate_( sample_rate ); -} - -blargg_err_t Vgm_Emu::set_multi_channel ( bool is_enabled ) -{ - // we acutally should check here whether this is classic emu or not - // however set_multi_channel() is called before setup_fm() resulting in uninited is_classic_emu() - // hard code it to unsupported -#if 0 - if ( is_classic_emu() ) - { - RETURN_ERR( Music_Emu::set_multi_channel_( is_enabled ) ); - return 0; - } - else -#endif - { - (void) is_enabled; - return "multichannel rendering not supported for YM2*** FM sound chip emulators"; - } -} - -void Vgm_Emu::update_eq( blip_eq_t const& eq ) -{ - psg.treble_eq( eq ); - dac_synth.treble_eq( eq ); -} - -void Vgm_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) -{ - if ( i < psg.osc_count ) - psg.osc_output( i, c, l, r ); -} - -void Vgm_Emu::mute_voices_( int mask ) -{ - Classic_Emu::mute_voices_( mask ); - dac_synth.output( &blip_buf ); - if ( uses_fm ) - { - psg.output( (mask & 0x80) ? 0 : &blip_buf ); - if ( ym2612.enabled() ) - { - dac_synth.volume( (mask & 0x40) ? 0.0 : 0.1115 / 256 * fm_gain * gain() ); - ym2612.mute_voices( mask ); - } - - if ( ym2413.enabled() ) - { - int m = mask & 0x3F; - if ( mask & 0x20 ) - m |= 0x01E0; // channels 5-8 - if ( mask & 0x40 ) - m |= 0x3E00; - ym2413.mute_voices( m ); - } - } -} - -blargg_err_t Vgm_Emu::load_mem_( byte const* new_data, long new_size ) -{ - assert( offsetof (header_t,unused2 [8]) == header_size ); - - if ( new_size <= header_size ) - return gme_wrong_file_type; - - header_t const& h = *(header_t const*) new_data; - - RETURN_ERR( check_vgm_header( h ) ); - - check( get_le32( h.version ) <= 0x150 ); - - // psg rate - psg_rate = get_le32( h.psg_rate ); - if ( !psg_rate ) - psg_rate = 3579545; - blip_buf.clock_rate( psg_rate ); - - data = new_data; - data_end = new_data + new_size; - - // get loop - loop_begin = data_end; - if ( get_le32( h.loop_offset ) ) - loop_begin = &data [get_le32( h.loop_offset ) + offsetof (header_t,loop_offset)]; - - set_voice_count( psg.osc_count ); - - RETURN_ERR( setup_fm() ); - - static const char* const fm_names [] = { - "FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PCM", "PSG" - }; - static const char* const psg_names [] = { "Square 1", "Square 2", "Square 3", "Noise" }; - set_voice_names( uses_fm ? fm_names : psg_names ); - - // do after FM in case output buffer is changed - return Classic_Emu::setup_buffer( psg_rate ); -} - -blargg_err_t Vgm_Emu::setup_fm() -{ - long ym2612_rate = get_le32( header().ym2612_rate ); - long ym2413_rate = get_le32( header().ym2413_rate ); - if ( ym2413_rate && get_le32( header().version ) < 0x110 ) - update_fm_rates( &ym2413_rate, &ym2612_rate ); - - uses_fm = false; - - fm_rate = blip_buf.sample_rate() * oversample_factor; - - if ( ym2612_rate ) - { - uses_fm = true; - if ( disable_oversampling_ ) - fm_rate = ym2612_rate / 144.0; - Dual_Resampler::setup( fm_rate / blip_buf.sample_rate(), rolloff, fm_gain * gain() ); - RETURN_ERR( ym2612.set_rate( fm_rate, ym2612_rate ) ); - ym2612.enable( true ); - set_voice_count( 8 ); - } - - if ( !uses_fm && ym2413_rate ) - { - uses_fm = true; - if ( disable_oversampling_ ) - fm_rate = ym2413_rate / 72.0; - Dual_Resampler::setup( fm_rate / blip_buf.sample_rate(), rolloff, fm_gain * gain() ); - int result = ym2413.set_rate( fm_rate, ym2413_rate ); - if ( result == 2 ) - return "YM2413 FM sound isn't supported"; - CHECK_ALLOC( !result ); - ym2413.enable( true ); - set_voice_count( 8 ); - } - - if ( uses_fm ) - { - RETURN_ERR( Dual_Resampler::reset( blip_buf.length() * blip_buf.sample_rate() / 1000 ) ); - psg.volume( 0.135 * fm_gain * gain() ); - } - else - { - ym2612.enable( false ); - ym2413.enable( false ); - psg.volume( gain() ); - } - - return 0; -} - -// Emulation - -blargg_err_t Vgm_Emu::start_track_( int track ) -{ - RETURN_ERR( Classic_Emu::start_track_( track ) ); - psg.reset( get_le16( header().noise_feedback ), header().noise_width ); - - dac_disabled = -1; - pos = data + header_size; - pcm_data = pos; - pcm_pos = pos; - dac_amp = -1; - vgm_time = 0; - if ( get_le32( header().version ) >= 0x150 ) - { - long data_offset = get_le32( header().data_offset ); - check( data_offset ); - if ( data_offset ) - pos += data_offset + offsetof (header_t,data_offset) - 0x40; - } - - if ( uses_fm ) - { - if ( ym2413.enabled() ) - ym2413.reset(); - - if ( ym2612.enabled() ) - ym2612.reset(); - - fm_time_offset = 0; - blip_buf.clear(); - Dual_Resampler::clear(); - } - return 0; -} - -blargg_err_t Vgm_Emu::run_clocks( blip_time_t& time_io, int msec ) -{ - time_io = run_commands( msec * vgm_rate / 1000 ); - psg.end_frame( time_io ); - return 0; -} - -blargg_err_t Vgm_Emu::play_( long count, sample_t* out ) -{ - if ( !uses_fm ) - return Classic_Emu::play_( count, out ); - - Dual_Resampler::dual_play( count, out, blip_buf ); - return 0; -} diff --git a/libraries/game-music-emu/gme/Vgm_Emu.h b/libraries/game-music-emu/gme/Vgm_Emu.h deleted file mode 100644 index 40cfb7102..000000000 --- a/libraries/game-music-emu/gme/Vgm_Emu.h +++ /dev/null @@ -1,86 +0,0 @@ -// Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef VGM_EMU_H -#define VGM_EMU_H - -#include "Vgm_Emu_Impl.h" - -// Emulates VGM music using SN76489/SN76496 PSG, YM2612, and YM2413 FM sound chips. -// Supports custom sound buffer and frequency equalization when VGM uses just the PSG. -// FM sound chips can be run at their proper rates, or slightly higher to reduce -// aliasing on high notes. Currently YM2413 support requires that you supply a -// YM2413 sound chip emulator. I can provide one I've modified to work with the library. -class Vgm_Emu : public Vgm_Emu_Impl { -public: - // True if custom buffer and custom equalization are supported - // TODO: move into Music_Emu and rename to something like supports_custom_buffer() - bool is_classic_emu() const { return !uses_fm; } - - blargg_err_t set_multi_channel ( bool is_enabled ) override; - - // Disable running FM chips at higher than normal rate. Will result in slightly - // more aliasing of high notes. - void disable_oversampling( bool disable = true ) { disable_oversampling_ = disable; } - - // VGM header format - enum { header_size = 0x40 }; - struct header_t - { - char tag [4]; - byte data_size [4]; - byte version [4]; - byte psg_rate [4]; - byte ym2413_rate [4]; - byte gd3_offset [4]; - byte track_duration [4]; - byte loop_offset [4]; - byte loop_duration [4]; - byte frame_rate [4]; - byte noise_feedback [2]; - byte noise_width; - byte unused1; - byte ym2612_rate [4]; - byte ym2151_rate [4]; - byte data_offset [4]; - byte unused2 [8]; - }; - - // Header for currently loaded file - header_t const& header() const { return *(header_t const*) data; } - - static gme_type_t static_type() { return gme_vgm_type; } - -public: - // deprecated - using Music_Emu::load; - blargg_err_t load( header_t const& h, Data_Reader& in ) // use Remaining_Reader - { return load_remaining_( &h, sizeof h, in ); } - byte const* gd3_data( int* size_out = 0 ) const; // use track_info() - -public: - Vgm_Emu(); - ~Vgm_Emu(); -protected: - blargg_err_t track_info_( track_info_t*, int track ) const; - blargg_err_t load_mem_( byte const*, long ); - blargg_err_t set_sample_rate_( long sample_rate ); - blargg_err_t start_track_( int ); - blargg_err_t play_( long count, sample_t* ); - blargg_err_t run_clocks( blip_time_t&, int ); - void set_tempo_( double ); - void mute_voices_( int mask ); - void set_voice( int, Blip_Buffer*, Blip_Buffer*, Blip_Buffer* ); - void update_eq( blip_eq_t const& ); -private: - // removed; use disable_oversampling() and set_tempo() instead - Vgm_Emu( bool oversample, double tempo = 1.0 ); - double fm_rate; - long psg_rate; - long vgm_rate; - bool disable_oversampling_; - bool uses_fm; - blargg_err_t setup_fm(); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Vgm_Emu_Impl.cpp b/libraries/game-music-emu/gme/Vgm_Emu_Impl.cpp deleted file mode 100644 index 0d400254d..000000000 --- a/libraries/game-music-emu/gme/Vgm_Emu_Impl.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Vgm_Emu.h" - -#include -#include -#include "blargg_endian.h" - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -enum { - cmd_gg_stereo = 0x4F, - cmd_psg = 0x50, - cmd_ym2413 = 0x51, - cmd_ym2612_port0 = 0x52, - cmd_ym2612_port1 = 0x53, - cmd_ym2151 = 0x54, - cmd_delay = 0x61, - cmd_delay_735 = 0x62, - cmd_delay_882 = 0x63, - cmd_byte_delay = 0x64, - cmd_end = 0x66, - cmd_data_block = 0x67, - cmd_short_delay = 0x70, - cmd_pcm_delay = 0x80, - cmd_pcm_seek = 0xE0, - - pcm_block_type = 0x00, - ym2612_dac_port = 0x2A -}; - -inline int command_len( int command ) -{ - switch ( command >> 4 ) - { - case 0x03: - case 0x04: - return 2; - - case 0x05: - case 0x0A: - case 0x0B: - return 3; - - case 0x0C: - case 0x0D: - return 4; - - case 0x0E: - case 0x0F: - return 5; - } - - check( false ); - return 1; -} - -template -inline void Ym_Emu::begin_frame( short* p ) -{ - require( enabled() ); - out = p; - last_time = 0; -} - -template -inline int Ym_Emu::run_until( int time ) -{ - int count = time - last_time; - if ( count > 0 ) - { - if ( last_time < 0 ) - return false; - last_time = time; - short* p = out; - out += count * Emu::out_chan_count; - Emu::run( count, p ); - } - return true; -} - -inline Vgm_Emu_Impl::fm_time_t Vgm_Emu_Impl::to_fm_time( vgm_time_t t ) const -{ - return (t * fm_time_factor + fm_time_offset) >> fm_time_bits; -} - -inline blip_time_t Vgm_Emu_Impl::to_blip_time( vgm_time_t t ) const -{ - return (t * blip_time_factor) >> blip_time_bits; -} - -void Vgm_Emu_Impl::write_pcm( vgm_time_t vgm_time, int amp ) -{ - blip_time_t blip_time = to_blip_time( vgm_time ); - int old = dac_amp; - int delta = amp - old; - dac_amp = amp; - if ( old >= 0 ) - dac_synth.offset_inline( blip_time, delta, &blip_buf ); - else - dac_amp |= dac_disabled; -} - -blip_time_t Vgm_Emu_Impl::run_commands( vgm_time_t end_time ) -{ - vgm_time_t vgm_time = this->vgm_time; - byte const* pos = this->pos; - if ( pos >= data_end ) - { - set_track_ended(); - if ( pos > data_end ) - set_warning( "Stream lacked end event" ); - } - - while ( vgm_time < end_time && pos < data_end ) - { - // TODO: be sure there are enough bytes left in stream for particular command - // so we don't read past end - switch ( *pos++ ) - { - case cmd_end: - pos = loop_begin; // if not looped, loop_begin == data_end - break; - - case cmd_delay_735: - vgm_time += 735; - break; - - case cmd_delay_882: - vgm_time += 882; - break; - - case cmd_gg_stereo: - psg.write_ggstereo( to_blip_time( vgm_time ), *pos++ ); - break; - - case cmd_psg: - psg.write_data( to_blip_time( vgm_time ), *pos++ ); - break; - - case cmd_delay: - vgm_time += pos [1] * 0x100L + pos [0]; - pos += 2; - break; - - case cmd_byte_delay: - vgm_time += *pos++; - break; - - case cmd_ym2413: - if ( ym2413.run_until( to_fm_time( vgm_time ) ) ) - ym2413.write( pos [0], pos [1] ); - pos += 2; - break; - - case cmd_ym2612_port0: - if ( pos [0] == ym2612_dac_port ) - { - write_pcm( vgm_time, pos [1] ); - } - else if ( ym2612.run_until( to_fm_time( vgm_time ) ) ) - { - if ( pos [0] == 0x2B ) - { - dac_disabled = (pos [1] >> 7 & 1) - 1; - dac_amp |= dac_disabled; - } - ym2612.write0( pos [0], pos [1] ); - } - pos += 2; - break; - - case cmd_ym2612_port1: - if ( ym2612.run_until( to_fm_time( vgm_time ) ) ) - ym2612.write1( pos [0], pos [1] ); - pos += 2; - break; - - case cmd_data_block: { - check( *pos == cmd_end ); - int type = pos [1]; - long size = get_le32( pos + 2 ); - pos += 6; - if ( type == pcm_block_type ) - pcm_data = pos; - pos += size; - break; - } - - case cmd_pcm_seek: - pcm_pos = pcm_data + pos [3] * 0x1000000L + pos [2] * 0x10000L + - pos [1] * 0x100L + pos [0]; - pos += 4; - break; - - default: - int cmd = pos [-1]; - switch ( cmd & 0xF0 ) - { - case cmd_pcm_delay: - write_pcm( vgm_time, *pcm_pos++ ); - vgm_time += cmd & 0x0F; - break; - - case cmd_short_delay: - vgm_time += (cmd & 0x0F) + 1; - break; - - case 0x50: - pos += 2; - break; - - default: - pos += command_len( cmd ) - 1; - set_warning( "Unknown stream event" ); - } - } - } - vgm_time -= end_time; - this->pos = pos; - this->vgm_time = vgm_time; - - return to_blip_time( end_time ); -} - -int Vgm_Emu_Impl::play_frame( blip_time_t blip_time, int sample_count, sample_t* buf ) -{ - // to do: timing is working mostly by luck - - int min_pairs = sample_count >> 1; - int vgm_time = ((long) min_pairs << fm_time_bits) / fm_time_factor - 1; - assert( to_fm_time( vgm_time ) <= min_pairs ); - int pairs = min_pairs; - while ( (pairs = to_fm_time( vgm_time )) < min_pairs ) - vgm_time++; - //debug_printf( "pairs: %d, min_pairs: %d\n", pairs, min_pairs ); - - if ( ym2612.enabled() ) - { - ym2612.begin_frame( buf ); - memset( buf, 0, pairs * stereo * sizeof *buf ); - } - else if ( ym2413.enabled() ) - { - ym2413.begin_frame( buf ); - } - - run_commands( vgm_time ); - ym2612.run_until( pairs ); - ym2413.run_until( pairs ); - - fm_time_offset = (vgm_time * fm_time_factor + fm_time_offset) - - ((long) pairs << fm_time_bits); - - psg.end_frame( blip_time ); - - return pairs * stereo; -} - -// Update pre-1.10 header FM rates by scanning commands -void Vgm_Emu_Impl::update_fm_rates( long* ym2413_rate, long* ym2612_rate ) const -{ - byte const* p = data + 0x40; - while ( p < data_end ) - { - switch ( *p ) - { - case cmd_end: - return; - - case cmd_psg: - case cmd_byte_delay: - p += 2; - break; - - case cmd_delay: - p += 3; - break; - - case cmd_data_block: - p += 7 + get_le32( p + 3 ); - break; - - case cmd_ym2413: - *ym2612_rate = 0; - return; - - case cmd_ym2612_port0: - case cmd_ym2612_port1: - *ym2612_rate = *ym2413_rate; - *ym2413_rate = 0; - return; - - case cmd_ym2151: - *ym2413_rate = 0; - *ym2612_rate = 0; - return; - - default: - p += command_len( *p ); - } - } -} diff --git a/libraries/game-music-emu/gme/Vgm_Emu_Impl.h b/libraries/game-music-emu/gme/Vgm_Emu_Impl.h deleted file mode 100644 index dadbb9207..000000000 --- a/libraries/game-music-emu/gme/Vgm_Emu_Impl.h +++ /dev/null @@ -1,71 +0,0 @@ -// Low-level parts of Vgm_Emu - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef VGM_EMU_IMPL_H -#define VGM_EMU_IMPL_H - -#include "Dual_Resampler.h" -#include "Classic_Emu.h" -#include "Ym2413_Emu.h" -#include "Ym2612_Emu.h" -#include "Sms_Apu.h" - -template -class Ym_Emu : public Emu { -protected: - int last_time; - short* out; - enum { disabled_time = -1 }; -public: - Ym_Emu() : last_time( disabled_time ), out( NULL ) { } - void enable( bool b ) { last_time = b ? 0 : disabled_time; } - bool enabled() const { return last_time != disabled_time; } - void begin_frame( short* p ); - int run_until( int time ); -}; - -class Vgm_Emu_Impl : public Classic_Emu, private Dual_Resampler { -public: - typedef Classic_Emu::sample_t sample_t; -protected: - enum { stereo = 2 }; - - typedef int vgm_time_t; - - enum { fm_time_bits = 12 }; - typedef int fm_time_t; - long fm_time_offset; - int fm_time_factor; - fm_time_t to_fm_time( vgm_time_t ) const; - - enum { blip_time_bits = 12 }; - int blip_time_factor; - blip_time_t to_blip_time( vgm_time_t ) const; - - byte const* data; - byte const* loop_begin; - byte const* data_end; - void update_fm_rates( long* ym2413_rate, long* ym2612_rate ) const; - - vgm_time_t vgm_time; - byte const* pos; - blip_time_t run_commands( vgm_time_t ); - int play_frame( blip_time_t blip_time, int sample_count, sample_t* buf ); - - byte const* pcm_data; - byte const* pcm_pos; - int dac_amp; - int dac_disabled; // -1 if disabled - void write_pcm( vgm_time_t, int amp ); - - Ym_Emu ym2612; - Ym_Emu ym2413; - - Blip_Buffer blip_buf; - Sms_Apu psg; - Blip_Synth dac_synth; - - friend class Vgm_Emu; -}; - -#endif diff --git a/libraries/game-music-emu/gme/Ym2413_Emu.cpp b/libraries/game-music-emu/gme/Ym2413_Emu.cpp deleted file mode 100644 index 01e796d95..000000000 --- a/libraries/game-music-emu/gme/Ym2413_Emu.cpp +++ /dev/null @@ -1,21 +0,0 @@ - -// Use in place of Ym2413_Emu.cpp and ym2413.c to disable support for this chip - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Ym2413_Emu.h" - -Ym2413_Emu::Ym2413_Emu() { } - -Ym2413_Emu::~Ym2413_Emu() { } - -int Ym2413_Emu::set_rate( double, double ) { return 2; } - -void Ym2413_Emu::reset() { } - -void Ym2413_Emu::write( int, int ) { } - -void Ym2413_Emu::mute_voices( int ) { } - -void Ym2413_Emu::run( int, sample_t* ) { } - diff --git a/libraries/game-music-emu/gme/Ym2413_Emu.h b/libraries/game-music-emu/gme/Ym2413_Emu.h deleted file mode 100644 index ed4fd11df..000000000 --- a/libraries/game-music-emu/gme/Ym2413_Emu.h +++ /dev/null @@ -1,33 +0,0 @@ -// YM2413 FM sound chip emulator interface - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef YM2413_EMU_H -#define YM2413_EMU_H - -class Ym2413_Emu { - struct OPLL* opll; -public: - Ym2413_Emu(); - ~Ym2413_Emu(); - - // Set output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - int set_rate( double sample_rate, double clock_rate ); - - // Reset to power-up state - void reset(); - - // Mute voice n if bit n (1 << n) of mask is set - enum { channel_count = 14 }; - void mute_voices( int mask ); - - // Write 'data' to 'addr' - void write( int addr, int data ); - - // Run and write pair_count samples to output - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Ym2612_Emu.h b/libraries/game-music-emu/gme/Ym2612_Emu.h deleted file mode 100644 index f62209a07..000000000 --- a/libraries/game-music-emu/gme/Ym2612_Emu.h +++ /dev/null @@ -1,19 +0,0 @@ -// YM2612 FM sound chip emulator interface - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#ifdef VGM_YM2612_GENS // LGPL v2.1+ license -#include "Ym2612_GENS.h" -typedef Ym2612_GENS_Emu Ym2612_Emu; -#endif - -#ifdef VGM_YM2612_NUKED // LGPL v2.1+ license -#include "Ym2612_Nuked.h" -typedef Ym2612_Nuked_Emu Ym2612_Emu; -#endif - -#ifdef VGM_YM2612_MAME // GPL v2+ license -#include "Ym2612_MAME.h" -typedef Ym2612_MAME_Emu Ym2612_Emu; -#endif - diff --git a/libraries/game-music-emu/gme/Ym2612_GENS.cpp b/libraries/game-music-emu/gme/Ym2612_GENS.cpp deleted file mode 100644 index d9930d62b..000000000 --- a/libraries/game-music-emu/gme/Ym2612_GENS.cpp +++ /dev/null @@ -1,1319 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -// Based on Gens 2.10 ym2612.c - -#include "Ym2612_GENS.h" - -#include -#include -#include -#include -#include -#include - -/* Copyright (C) 2002 StĂ©phane Dallongeville (gens AT consolemul.com) */ -/* Copyright (C) 2004-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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 */ - -// This is mostly the original source in its C style and all. -// -// Somewhat optimized and simplified. Uses a template to generate the many -// variants of Update_Chan. Rewrote header file. In need of full rewrite by -// someone more familiar with FM sound and the YM2612. Has some inaccuracies -// compared to the Sega Genesis sound, particularly being mixed at such a -// high sample accuracy (the Genesis sounds like it has only 8 bit samples). -// - Shay - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - -const int output_bits = 14; - -struct slot_t -{ - const int *DT; // parametre detune - int MUL; // parametre "multiple de frequence" - int TL; // Total Level = volume lorsque l'enveloppe est au plus haut - int TLL; // Total Level ajusted - int SLL; // Sustin Level (ajusted) = volume oĂą l'enveloppe termine sa premiere phase de regression - int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe - int KSR; // Key Scale Rate = cette valeur est calculee par rapport Ă  la frequence actuelle, elle va influer - // sur les differents parametres de l'enveloppe comme l'attaque, le decay ... comme dans la realite ! - int SEG; // Type enveloppe SSG - int env_xor; - int env_max; - - const int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR[KSR]) - const int *DR; // Decay Rate (table pointeur) = Taux pour la regression (DR[KSR]) - const int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR[KSR]) - const int *RR; // Release Rate (table pointeur) = Taux pour le rel'chement (RR[KSR]) - int Fcnt; // Frequency Count = compteur-frequence pour determiner l'amplitude actuelle (SIN[Finc >> 16]) - int Finc; // frequency step = pas d'incrementation du compteur-frequence - // plus le pas est grand, plus la frequence est aĂŻgu (ou haute) - int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase - // de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ... - // en fonction de la valeur de cette variable, on va appeler une fonction permettant - // de mettre Ă  jour l'enveloppe courante. - int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir oĂą l'on se trouve dans l'enveloppe - int Einc; // Envelope step courant - int Ecmp; // Envelope counter limite pour la prochaine phase - int EincA; // Envelope step for Attack = pas d'incrementation du compteur durant la phase d'attaque - // cette valeur est egal Ă  AR[KSR] - int EincD; // Envelope step for Decay = pas d'incrementation du compteur durant la phase de regression - // cette valeur est egal Ă  DR[KSR] - int EincS; // Envelope step for Sustain = pas d'incrementation du compteur durant la phase de maintenue - // cette valeur est egal Ă  SR[KSR] - int EincR; // Envelope step for Release = pas d'incrementation du compteur durant la phase de rel'chement - // cette valeur est egal Ă  RR[KSR] - int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot Ă  l'entree - // d'un autre ou carrement Ă  la sortie de la voie - int INd; // input data of the slot = donnees en entree du slot - int ChgEnM; // Change envelop mask. - int AMS; // AMS depth level of this SLOT = degre de modulation de l'amplitude par le LFO - int AMSon; // AMS enable flag = drapeau d'activation de l'AMS -}; - -struct channel_t -{ - int S0_OUT[4]; // anciennes sorties slot 0 (pour le feed back) - int LEFT; // LEFT enable flag - int RIGHT; // RIGHT enable flag - int ALGO; // Algorythm = determine les connections entre les operateurs - int FB; // shift count of self feed back = degre de "Feed-Back" du SLOT 1 (il est son unique entree) - int FMS; // Frequency Modulation Sensitivity of channel = degre de modulation de la frequence sur la voie par le LFO - int AMS; // Amplitude Modulation Sensitivity of channel = degre de modulation de l'amplitude sur la voie par le LFO - int FNUM[4]; // hauteur frequence de la voie (+ 3 pour le mode special) - int FOCT[4]; // octave de la voie (+ 3 pour le mode special) - int KC[4]; // Key Code = valeur fonction de la frequence (voir KSR pour les slots, KSR = KC >> KSR_S) - slot_t SLOT[4]; // four slot.operators = les 4 slots de la voie - int FFlag; // Frequency step recalculation flag -}; - -struct state_t -{ - int TimerBase; // TimerBase calculation - int Status; // YM2612 Status (timer overflow) - int TimerA; // timerA limit = valeur jusqu'Ă  laquelle le timer A doit compter - int TimerAL; - int TimerAcnt; // timerA counter = valeur courante du Timer A - int TimerB; // timerB limit = valeur jusqu'Ă  laquelle le timer B doit compter - int TimerBL; - int TimerBcnt; // timerB counter = valeur courante du Timer B - int Mode; // Mode actuel des voie 3 et 6 (normal / special) - int DAC; // DAC enabled flag - channel_t CHANNEL[Ym2612_GENS_Emu::channel_count]; // Les 6 voies du YM2612 - int REG[2][0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif - // cela nous rend le debuggage plus facile -}; - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -#define ATTACK 0 -#define DECAY 1 -#define SUBSTAIN 2 -#define RELEASE 3 - -// SIN_LBITS <= 16 -// LFO_HBITS <= 16 -// (SIN_LBITS + SIN_HBITS) <= 26 -// (ENV_LBITS + ENV_HBITS) <= 28 -// (LFO_LBITS + LFO_HBITS) <= 28 - -#define SIN_HBITS 12 // Sinus phase counter int part -#define SIN_LBITS (26 - SIN_HBITS) // Sinus phase counter float part (best setting) - -#if (SIN_LBITS > 16) -#define SIN_LBITS 16 // Can't be greater than 16 bits -#endif - -#define ENV_HBITS 12 // Env phase counter int part -#define ENV_LBITS (28 - ENV_HBITS) // Env phase counter float part (best setting) - -#define LFO_HBITS 10 // LFO phase counter int part -#define LFO_LBITS (28 - LFO_HBITS) // LFO phase counter float part (best setting) - -#define SIN_LENGHT (1 << SIN_HBITS) -#define ENV_LENGHT (1 << ENV_HBITS) -#define LFO_LENGHT (1 << LFO_HBITS) - -#define TL_LENGHT (ENV_LENGHT * 3) // Env + TL scaling + LFO - -#define SIN_MASK (SIN_LENGHT - 1) -#define ENV_MASK (ENV_LENGHT - 1) -#define LFO_MASK (LFO_LENGHT - 1) - -#define ENV_STEP (96.0 / ENV_LENGHT) // ENV_MAX = 96 dB - -#define ENV_ATTACK ((ENV_LENGHT * 0) << ENV_LBITS) -#define ENV_DECAY ((ENV_LENGHT * 1) << ENV_LBITS) -#define ENV_END ((ENV_LENGHT * 2) << ENV_LBITS) - -#define MAX_OUT_BITS (SIN_HBITS + SIN_LBITS + 2) // Modulation = -4 <--> +4 -#define MAX_OUT ((1 << MAX_OUT_BITS) - 1) - -#define PG_CUT_OFF ((int) (78.0 / ENV_STEP)) -#define ENV_CUT_OFF ((int) (68.0 / ENV_STEP)) - -#define AR_RATE 399128 -#define DR_RATE 5514396 - -//#define AR_RATE 426136 -//#define DR_RATE (AR_RATE * 12) - -#define LFO_FMS_LBITS 9 // FIXED (LFO_FMS_BASE gives somethink as 1) -#define LFO_FMS_BASE ((int) (0.05946309436 * 0.0338 * (double) (1 << LFO_FMS_LBITS))) - -#define S0 0 // Stupid typo of the YM2612 -#define S1 2 -#define S2 1 -#define S3 3 - -inline void set_seg( slot_t& s, int seg ) -{ - s.env_xor = 0; - s.env_max = INT_MAX; - s.SEG = seg; - if ( seg & 4 ) - { - s.env_xor = ENV_MASK; - s.env_max = ENV_MASK; - } -} - -struct tables_t -{ - short SIN_TAB [SIN_LENGHT]; // SINUS TABLE (offset into TL TABLE) - int LFOcnt; // LFO counter = compteur-frequence pour le LFO - int LFOinc; // LFO step counter = pas d'incrementation du compteur-frequence du LFO - // plus le pas est grand, plus la frequence est grande - unsigned int AR_TAB [128]; // Attack rate table - unsigned int DR_TAB [96]; // Decay rate table - unsigned int DT_TAB [8] [32]; // Detune table - unsigned int SL_TAB [16]; // Substain level table - unsigned int NULL_RATE [32]; // Table for NULL rate - int LFO_INC_TAB [8]; // LFO step table - - short ENV_TAB [2 * ENV_LENGHT + 8]; // ENV CURVE TABLE (attack & decay) - - short LFO_ENV_TAB [LFO_LENGHT]; // LFO AMS TABLE (adjusted for 11.8 dB) - short LFO_FREQ_TAB [LFO_LENGHT]; // LFO FMS TABLE - int TL_TAB [TL_LENGHT * 2]; // TOTAL LEVEL TABLE (positif and minus) - unsigned int DECAY_TO_ATTACK [ENV_LENGHT]; // Conversion from decay to attack phase - unsigned int FINC_TAB [2048]; // Frequency step table -}; - -static const unsigned char DT_DEF_TAB [4 * 32] = -{ -// FD = 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -// FD = 1 - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, - -// FD = 2 - 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, - 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 16, 16, 16, 16, - -// FD = 3 - 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, - 8 , 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 20, 22, 22, 22, 22 -}; - -static const unsigned char FKEY_TAB [16] = -{ - 0, 0, 0, 0, - 0, 0, 0, 1, - 2, 3, 3, 3, - 3, 3, 3, 3 -}; - -static const unsigned char LFO_AMS_TAB [4] = -{ - 31, 4, 1, 0 -}; - -static const unsigned char LFO_FMS_TAB [8] = -{ - LFO_FMS_BASE * 0, LFO_FMS_BASE * 1, - LFO_FMS_BASE * 2, LFO_FMS_BASE * 3, - LFO_FMS_BASE * 4, LFO_FMS_BASE * 6, - LFO_FMS_BASE * 12, LFO_FMS_BASE * 24 -}; - -inline void YM2612_Special_Update() { } - -struct Ym2612_GENS_Impl -{ - enum { channel_count = Ym2612_GENS_Emu::channel_count }; - - state_t YM2612; - int mute_mask; - tables_t g; - - void KEY_ON( channel_t&, int ); - void KEY_OFF( channel_t&, int ); - int SLOT_SET( int, int ); - int CHANNEL_SET( int, int ); - int YM_SET( int, int ); - - void set_rate( double sample_rate, double clock_factor ); - void reset(); - void write0( int addr, int data ); - void write1( int addr, int data ); - void run_timer( int ); - void run( int pair_count, Ym2612_GENS_Emu::sample_t* ); -}; - -void Ym2612_GENS_Impl::KEY_ON( channel_t& ch, int nsl) -{ - slot_t *SL = &(ch.SLOT [nsl]); // on recupere le bon pointeur de slot - - if (SL->Ecurp == RELEASE) // la touche est-elle rel'chee ? - { - SL->Fcnt = 0; - - // Fix Ecco 2 splash sound - - SL->Ecnt = (g.DECAY_TO_ATTACK [g.ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK) & SL->ChgEnM; - SL->ChgEnM = ~0; - -// SL->Ecnt = g.DECAY_TO_ATTACK [g.ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK; -// SL->Ecnt = 0; - - SL->Einc = SL->EincA; - SL->Ecmp = ENV_DECAY; - SL->Ecurp = ATTACK; - } -} - - -void Ym2612_GENS_Impl::KEY_OFF(channel_t& ch, int nsl) -{ - slot_t *SL = &(ch.SLOT [nsl]); // on recupere le bon pointeur de slot - - if (SL->Ecurp != RELEASE) // la touche est-elle appuyee ? - { - if (SL->Ecnt < ENV_DECAY) // attack phase ? - { - SL->Ecnt = (g.ENV_TAB [SL->Ecnt >> ENV_LBITS] << ENV_LBITS) + ENV_DECAY; - } - - SL->Einc = SL->EincR; - SL->Ecmp = ENV_END; - SL->Ecurp = RELEASE; - } -} - - -int Ym2612_GENS_Impl::SLOT_SET( int Adr, int data ) -{ - int nch = Adr & 3; - if ( nch == 3 ) - return 1; - - channel_t& ch = YM2612.CHANNEL [nch + (Adr & 0x100 ? 3 : 0)]; - slot_t& sl = ch.SLOT [(Adr >> 2) & 3]; - - switch ( Adr & 0xF0 ) - { - case 0x30: - if ( (sl.MUL = (data & 0x0F)) != 0 ) sl.MUL <<= 1; - else sl.MUL = 1; - - sl.DT = (int*) g.DT_TAB [(data >> 4) & 7]; - - ch.SLOT [0].Finc = -1; - - break; - - case 0x40: - sl.TL = data & 0x7F; - - // SOR2 do a lot of TL adjustement and this fix R.Shinobi jump sound... - YM2612_Special_Update(); - -#if ((ENV_HBITS - 7) < 0) - sl.TLL = sl.TL >> (7 - ENV_HBITS); -#else - sl.TLL = sl.TL << (ENV_HBITS - 7); -#endif - - break; - - case 0x50: - sl.KSR_S = 3 - (data >> 6); - - ch.SLOT [0].Finc = -1; - - if (data &= 0x1F) sl.AR = (int*) &g.AR_TAB [data << 1]; - else sl.AR = (int*) &g.NULL_RATE [0]; - - sl.EincA = sl.AR [sl.KSR]; - if (sl.Ecurp == ATTACK) sl.Einc = sl.EincA; - break; - - case 0x60: - if ( (sl.AMSon = (data & 0x80)) != 0 ) sl.AMS = ch.AMS; - else sl.AMS = 31; - - if (data &= 0x1F) sl.DR = (int*) &g.DR_TAB [data << 1]; - else sl.DR = (int*) &g.NULL_RATE [0]; - - sl.EincD = sl.DR [sl.KSR]; - if (sl.Ecurp == DECAY) sl.Einc = sl.EincD; - break; - - case 0x70: - if (data &= 0x1F) sl.SR = (int*) &g.DR_TAB [data << 1]; - else sl.SR = (int*) &g.NULL_RATE [0]; - - sl.EincS = sl.SR [sl.KSR]; - if ((sl.Ecurp == SUBSTAIN) && (sl.Ecnt < ENV_END)) sl.Einc = sl.EincS; - break; - - case 0x80: - sl.SLL = g.SL_TAB [data >> 4]; - - sl.RR = (int*) &g.DR_TAB [((data & 0xF) << 2) + 2]; - - sl.EincR = sl.RR [sl.KSR]; - if ((sl.Ecurp == RELEASE) && (sl.Ecnt < ENV_END)) sl.Einc = sl.EincR; - break; - - case 0x90: - // SSG-EG envelope shapes : - /* - E At Al H - - 1 0 0 0 \\\\ - 1 0 0 1 \___ - 1 0 1 0 \/\/ - 1 0 1 1 \ - 1 1 0 0 //// - 1 1 0 1 / - 1 1 1 0 /\/\ - 1 1 1 1 /___ - - E = SSG-EG enable - At = Start negate - Al = Altern - H = Hold */ - - set_seg( sl, (data & 8) ? (data & 0x0F) : 0 ); - break; - } - - return 0; -} - - -int Ym2612_GENS_Impl::CHANNEL_SET( int Adr, int data ) -{ - int num = Adr & 3; - if ( num == 3 ) - return 1; - - channel_t& ch = YM2612.CHANNEL [num + (Adr & 0x100 ? 3 : 0)]; - - switch ( Adr & 0xFC ) - { - case 0xA0: - YM2612_Special_Update(); - - ch.FNUM [0] = (ch.FNUM [0] & 0x700) + data; - ch.KC [0] = (ch.FOCT [0] << 2) | FKEY_TAB [ch.FNUM [0] >> 7]; - - ch.SLOT [0].Finc = -1; - break; - - case 0xA4: - YM2612_Special_Update(); - - ch.FNUM [0] = (ch.FNUM [0] & 0x0FF) + ((data & 0x07) << 8); - ch.FOCT [0] = (data & 0x38) >> 3; - ch.KC [0] = (ch.FOCT [0] << 2) | FKEY_TAB [ch.FNUM [0] >> 7]; - - ch.SLOT [0].Finc = -1; - break; - - case 0xA8: - if ( Adr < 0x100 ) - { - num++; - - YM2612_Special_Update(); - - YM2612.CHANNEL [2].FNUM [num] = (YM2612.CHANNEL [2].FNUM [num] & 0x700) + data; - YM2612.CHANNEL [2].KC [num] = (YM2612.CHANNEL [2].FOCT [num] << 2) | - FKEY_TAB [YM2612.CHANNEL [2].FNUM [num] >> 7]; - - YM2612.CHANNEL [2].SLOT [0].Finc = -1; - } - break; - - case 0xAC: - if ( Adr < 0x100 ) - { - num++; - - YM2612_Special_Update(); - - YM2612.CHANNEL [2].FNUM [num] = (YM2612.CHANNEL [2].FNUM [num] & 0x0FF) + ((data & 0x07) << 8); - YM2612.CHANNEL [2].FOCT [num] = (data & 0x38) >> 3; - YM2612.CHANNEL [2].KC [num] = (YM2612.CHANNEL [2].FOCT [num] << 2) | - FKEY_TAB [YM2612.CHANNEL [2].FNUM [num] >> 7]; - - YM2612.CHANNEL [2].SLOT [0].Finc = -1; - } - break; - - case 0xB0: - if ( ch.ALGO != (data & 7) ) - { - // Fix VectorMan 2 heli sound (level 1) - YM2612_Special_Update(); - - ch.ALGO = data & 7; - - ch.SLOT [0].ChgEnM = 0; - ch.SLOT [1].ChgEnM = 0; - ch.SLOT [2].ChgEnM = 0; - ch.SLOT [3].ChgEnM = 0; - } - - ch.FB = 9 - ((data >> 3) & 7); // Real thing ? - -// if (ch.FB = ((data >> 3) & 7)) ch.FB = 9 - ch.FB; // Thunder force 4 (music stage 8), Gynoug, Aladdin bug sound... -// else ch.FB = 31; - break; - - case 0xB4: { - YM2612_Special_Update(); - - ch.LEFT = 0 - ((data >> 7) & 1); - ch.RIGHT = 0 - ((data >> 6) & 1); - - ch.AMS = LFO_AMS_TAB [(data >> 4) & 3]; - ch.FMS = LFO_FMS_TAB [data & 7]; - - for ( int i = 0; i < 4; i++ ) - { - slot_t& sl = ch.SLOT [i]; - sl.AMS = (sl.AMSon ? ch.AMS : 31); - } - break; - } - } - - return 0; -} - - -int Ym2612_GENS_Impl::YM_SET(int Adr, int data) -{ - switch ( Adr ) - { - case 0x22: - if (data & 8) // LFO enable - { - // Cool Spot music 1, LFO modified severals time which - // distord the sound, have to check that on a real genesis... - - g.LFOinc = g.LFO_INC_TAB [data & 7]; - } - else - { - g.LFOinc = g.LFOcnt = 0; - } - break; - - case 0x24: - YM2612.TimerA = (YM2612.TimerA & 0x003) | (((int) data) << 2); - - if (YM2612.TimerAL != (1024 - YM2612.TimerA) << 12) - { - YM2612.TimerAcnt = YM2612.TimerAL = (1024 - YM2612.TimerA) << 12; - } - break; - - case 0x25: - YM2612.TimerA = (YM2612.TimerA & 0x3FC) | (data & 3); - - if (YM2612.TimerAL != (1024 - YM2612.TimerA) << 12) - { - YM2612.TimerAcnt = YM2612.TimerAL = (1024 - YM2612.TimerA) << 12; - } - break; - - case 0x26: - YM2612.TimerB = data; - - if (YM2612.TimerBL != (256 - YM2612.TimerB) << (4 + 12)) - { - YM2612.TimerBcnt = YM2612.TimerBL = (256 - YM2612.TimerB) << (4 + 12); - } - break; - - case 0x27: - // Parametre divers - // b7 = CSM MODE - // b6 = 3 slot mode - // b5 = reset b - // b4 = reset a - // b3 = timer enable b - // b2 = timer enable a - // b1 = load b - // b0 = load a - - if ((data ^ YM2612.Mode) & 0x40) - { - // We changed the channel 2 mode, so recalculate phase step - // This fix the punch sound in Street of Rage 2 - - YM2612_Special_Update(); - - YM2612.CHANNEL [2].SLOT [0].Finc = -1; // recalculate phase step - } - -// if ((data & 2) && (YM2612.Status & 2)) YM2612.TimerBcnt = YM2612.TimerBL; -// if ((data & 1) && (YM2612.Status & 1)) YM2612.TimerAcnt = YM2612.TimerAL; - -// YM2612.Status &= (~data >> 4); // Reset du Status au cas ou c'est demande - YM2612.Status &= (~data >> 4) & (data >> 2); // Reset Status - - YM2612.Mode = data; - break; - - case 0x28: { - int nch = data & 3; - if ( nch == 3 ) - return 1; - if ( data & 4 ) - nch += 3; - channel_t& ch = YM2612.CHANNEL [nch]; - - YM2612_Special_Update(); - - if (data & 0x10) KEY_ON(ch, S0); // On appuie sur la touche pour le slot 1 - else KEY_OFF(ch, S0); // On rel'che la touche pour le slot 1 - if (data & 0x20) KEY_ON(ch, S1); // On appuie sur la touche pour le slot 3 - else KEY_OFF(ch, S1); // On rel'che la touche pour le slot 3 - if (data & 0x40) KEY_ON(ch, S2); // On appuie sur la touche pour le slot 2 - else KEY_OFF(ch, S2); // On rel'che la touche pour le slot 2 - if (data & 0x80) KEY_ON(ch, S3); // On appuie sur la touche pour le slot 4 - else KEY_OFF(ch, S3); // On rel'che la touche pour le slot 4 - break; - } - - case 0x2B: - if (YM2612.DAC ^ (data & 0x80)) YM2612_Special_Update(); - - YM2612.DAC = data & 0x80; // activation/desactivation du DAC - break; - } - - return 0; -} - -void Ym2612_GENS_Impl::set_rate( double sample_rate, double clock_rate ) -{ - assert( sample_rate ); - assert( clock_rate > sample_rate ); - - int i; - - // 144 = 12 * (prescale * 2) = 12 * 6 * 2 - // prescale set to 6 by default - - double Frequence = clock_rate / sample_rate / 144.0; - if ( fabs( Frequence - 1.0 ) < 0.0000001 ) - Frequence = 1.0; - YM2612.TimerBase = int (Frequence * 4096.0); - - // Tableau TL : - // [0 - 4095] = +output [4095 - ...] = +output overflow (fill with 0) - // [12288 - 16383] = -output [16384 - ...] = -output overflow (fill with 0) - - for(i = 0; i < TL_LENGHT; i++) - { - if (i >= PG_CUT_OFF) // YM2612 cut off sound after 78 dB (14 bits output ?) - { - g.TL_TAB [TL_LENGHT + i] = g.TL_TAB [i] = 0; - } - else - { - double x = MAX_OUT; // Max output - x /= pow( 10.0, (ENV_STEP * i) / 20.0 ); // Decibel -> Voltage - - g.TL_TAB [i] = (int) x; - g.TL_TAB [TL_LENGHT + i] = -g.TL_TAB [i]; - } - } - - // Tableau SIN : - // g.SIN_TAB [x] [y] = sin(x) * y; - // x = phase and y = volume - - g.SIN_TAB [0] = g.SIN_TAB [SIN_LENGHT / 2] = PG_CUT_OFF; - - for(i = 1; i <= SIN_LENGHT / 4; i++) - { - double x = sin(2.0 * PI * (double) (i) / (double) (SIN_LENGHT)); // Sinus - x = 20 * log10(1 / x); // convert to dB - - int j = (int) (x / ENV_STEP); // Get TL range - - if (j > PG_CUT_OFF) j = (int) PG_CUT_OFF; - - g.SIN_TAB [i] = g.SIN_TAB [(SIN_LENGHT / 2) - i] = j; - g.SIN_TAB [(SIN_LENGHT / 2) + i] = g.SIN_TAB [SIN_LENGHT - i] = TL_LENGHT + j; - } - - // Tableau LFO (LFO wav) : - - for(i = 0; i < LFO_LENGHT; i++) - { - double x = sin(2.0 * PI * (double) (i) / (double) (LFO_LENGHT)); // Sinus - x += 1.0; - x /= 2.0; // positive only - x *= 11.8 / ENV_STEP; // ajusted to MAX enveloppe modulation - - g.LFO_ENV_TAB [i] = (int) x; - - x = sin(2.0 * PI * (double) (i) / (double) (LFO_LENGHT)); // Sinus - x *= (double) ((1 << (LFO_HBITS - 1)) - 1); - - g.LFO_FREQ_TAB [i] = (int) x; - - } - - // Tableau Enveloppe : - // g.ENV_TAB [0] -> g.ENV_TAB [ENV_LENGHT - 1] = attack curve - // g.ENV_TAB [ENV_LENGHT] -> g.ENV_TAB [2 * ENV_LENGHT - 1] = decay curve - - for(i = 0; i < ENV_LENGHT; i++) - { - // Attack curve (x^8 - music level 2 Vectorman 2) - double x = pow(((double) ((ENV_LENGHT - 1) - i) / (double) (ENV_LENGHT)), 8); - x *= ENV_LENGHT; - - g.ENV_TAB [i] = (int) x; - - // Decay curve (just linear) - x = pow(((double) (i) / (double) (ENV_LENGHT)), 1); - x *= ENV_LENGHT; - - g.ENV_TAB [ENV_LENGHT + i] = (int) x; - } - for ( i = 0; i < 8; i++ ) - g.ENV_TAB [i + ENV_LENGHT * 2] = 0; - - g.ENV_TAB [ENV_END >> ENV_LBITS] = ENV_LENGHT - 1; // for the stopped state - - // Tableau pour la conversion Attack -> Decay and Decay -> Attack - - int j = ENV_LENGHT - 1; - for ( i = 0; i < ENV_LENGHT; i++ ) - { - while ( j && g.ENV_TAB [j] < i ) - j--; - - g.DECAY_TO_ATTACK [i] = j << ENV_LBITS; - } - - // Tableau pour le Substain Level - - for(i = 0; i < 15; i++) - { - double x = i * 3; // 3 and not 6 (Mickey Mania first music for test) - x /= ENV_STEP; - - g.SL_TAB [i] = ((int) x << ENV_LBITS) + ENV_DECAY; - } - - g.SL_TAB [15] = ((ENV_LENGHT - 1) << ENV_LBITS) + ENV_DECAY; // special case : volume off - - // Tableau Frequency Step - - for(i = 0; i < 2048; i++) - { - double x = (double) (i) * Frequence; - -#if ((SIN_LBITS + SIN_HBITS - (21 - 7)) < 0) - x /= (double) (1 << ((21 - 7) - SIN_LBITS - SIN_HBITS)); -#else - x *= (double) (1 << (SIN_LBITS + SIN_HBITS - (21 - 7))); -#endif - - x /= 2.0; // because MUL = value * 2 - - g.FINC_TAB [i] = (unsigned int) x; - } - - // Tableaux Attack & Decay Rate - - for(i = 0; i < 4; i++) - { - g.AR_TAB [i] = 0; - g.DR_TAB [i] = 0; - } - - for(i = 0; i < 60; i++) - { - double x = Frequence; - - x *= 1.0 + ((i & 3) * 0.25); // bits 0-1 : x1.00, x1.25, x1.50, x1.75 - x *= (double) (1 << ((i >> 2))); // bits 2-5 : shift bits (x2^0 - x2^15) - x *= (double) (ENV_LENGHT << ENV_LBITS); // on ajuste pour le tableau g.ENV_TAB - - g.AR_TAB [i + 4] = (unsigned int) (x / AR_RATE); - g.DR_TAB [i + 4] = (unsigned int) (x / DR_RATE); - } - - for(i = 64; i < 96; i++) - { - g.AR_TAB [i] = g.AR_TAB [63]; - g.DR_TAB [i] = g.DR_TAB [63]; - - g.NULL_RATE [i - 64] = 0; - } - - for ( i = 96; i < 128; i++ ) - g.AR_TAB [i] = 0; - - // Tableau Detune - - for(i = 0; i < 4; i++) - { - for (int j = 0; j < 32; j++) - { -#if ((SIN_LBITS + SIN_HBITS - 21) < 0) - double y = (double) DT_DEF_TAB [(i << 5) + j] * Frequence / (double) (1 << (21 - SIN_LBITS - SIN_HBITS)); -#else - double y = (double) DT_DEF_TAB [(i << 5) + j] * Frequence * (double) (1 << (SIN_LBITS + SIN_HBITS - 21)); -#endif - - g.DT_TAB [i + 0] [j] = (int) y; - g.DT_TAB [i + 4] [j] = (int) -y; - } - } - - // Tableau LFO - g.LFO_INC_TAB [0] = (unsigned int) (3.98 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [1] = (unsigned int) (5.56 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [2] = (unsigned int) (6.02 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [3] = (unsigned int) (6.37 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [4] = (unsigned int) (6.88 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [5] = (unsigned int) (9.63 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [6] = (unsigned int) (48.1 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - g.LFO_INC_TAB [7] = (unsigned int) (72.2 * (double) (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate); - - reset(); -} - -const char* Ym2612_GENS_Emu::set_rate( double sample_rate, double clock_rate ) -{ - if ( !impl ) - { - impl = (Ym2612_GENS_Impl*) malloc( sizeof *impl ); - if ( !impl ) - return "Out of memory"; - impl->mute_mask = 0; - } - memset( &impl->YM2612, 0, sizeof impl->YM2612 ); - - impl->set_rate( sample_rate, clock_rate ); - - return 0; -} - -Ym2612_GENS_Emu::~Ym2612_GENS_Emu() -{ - free( impl ); -} - -inline void Ym2612_GENS_Impl::write0( int opn_addr, int data ) -{ - assert( (unsigned) data <= 0xFF ); - - if ( opn_addr < 0x30 ) - { - YM2612.REG [0] [opn_addr] = data; - YM_SET( opn_addr, data ); - } - else if ( YM2612.REG [0] [opn_addr] != data ) - { - YM2612.REG [0] [opn_addr] = data; - - if ( opn_addr < 0xA0 ) - SLOT_SET( opn_addr, data ); - else - CHANNEL_SET( opn_addr, data ); - } -} - -inline void Ym2612_GENS_Impl::write1( int opn_addr, int data ) -{ - assert( (unsigned) data <= 0xFF ); - - if ( opn_addr >= 0x30 && YM2612.REG [1] [opn_addr] != data ) - { - YM2612.REG [1] [opn_addr] = data; - - if ( opn_addr < 0xA0 ) - SLOT_SET( opn_addr + 0x100, data ); - else - CHANNEL_SET( opn_addr + 0x100, data ); - } -} - -void Ym2612_GENS_Emu::reset() -{ - impl->reset(); -} - -void Ym2612_GENS_Impl::reset() -{ - g.LFOcnt = 0; - YM2612.TimerA = 0; - YM2612.TimerAL = 0; - YM2612.TimerAcnt = 0; - YM2612.TimerB = 0; - YM2612.TimerBL = 0; - YM2612.TimerBcnt = 0; - YM2612.DAC = 0; - - YM2612.Status = 0; - - int i; - for ( i = 0; i < channel_count; i++ ) - { - channel_t& ch = YM2612.CHANNEL [i]; - - ch.LEFT = ~0; - ch.RIGHT = ~0; - ch.ALGO = 0; - ch.FB = 31; - ch.FMS = 0; - ch.AMS = 0; - - for ( int j = 0 ;j < 4 ; j++ ) - { - ch.S0_OUT [j] = 0; - ch.FNUM [j] = 0; - ch.FOCT [j] = 0; - ch.KC [j] = 0; - - ch.SLOT [j].Fcnt = 0; - ch.SLOT [j].Finc = 0; - ch.SLOT [j].Ecnt = ENV_END; // Put it at the end of Decay phase... - ch.SLOT [j].Einc = 0; - ch.SLOT [j].Ecmp = 0; - ch.SLOT [j].Ecurp = RELEASE; - - ch.SLOT [j].ChgEnM = 0; - } - } - - for ( i = 0; i < 0x100; i++ ) - { - YM2612.REG [0] [i] = -1; - YM2612.REG [1] [i] = -1; - } - - for ( i = 0xB6; i >= 0xB4; i-- ) - { - write0( i, 0xC0 ); - write1( i, 0xC0 ); - } - - for ( i = 0xB2; i >= 0x22; i-- ) - { - write0( i, 0 ); - write1( i, 0 ); - } - - write0( 0x2A, 0x80 ); -} - -void Ym2612_GENS_Emu::write0( int addr, int data ) -{ - impl->write0( addr, data ); -} - -void Ym2612_GENS_Emu::write1( int addr, int data ) -{ - impl->write1( addr, data ); -} - -void Ym2612_GENS_Emu::mute_voices( int mask ) { impl->mute_mask = mask; } - -static void update_envelope_( slot_t* sl ) -{ - switch ( sl->Ecurp ) - { - case 0: - // Env_Attack_Next - - // Verified with Gynoug even in HQ (explode SFX) - sl->Ecnt = ENV_DECAY; - - sl->Einc = sl->EincD; - sl->Ecmp = sl->SLL; - sl->Ecurp = DECAY; - break; - - case 1: - // Env_Decay_Next - - // Verified with Gynoug even in HQ (explode SFX) - sl->Ecnt = sl->SLL; - - sl->Einc = sl->EincS; - sl->Ecmp = ENV_END; - sl->Ecurp = SUBSTAIN; - break; - - case 2: - // Env_Substain_Next(slot_t *SL) - if (sl->SEG & 8) // SSG envelope type - { - int release = sl->SEG & 1; - - if ( !release ) - { - // re KEY ON - - // sl->Fcnt = 0; - // sl->ChgEnM = ~0; - - sl->Ecnt = 0; - sl->Einc = sl->EincA; - sl->Ecmp = ENV_DECAY; - sl->Ecurp = ATTACK; - } - - set_seg( *sl, (sl->SEG << 1) & 4 ); - - if ( !release ) - break; - } - // fall through - - case 3: - // Env_Release_Next - sl->Ecnt = ENV_END; - sl->Einc = 0; - sl->Ecmp = ENV_END + 1; - break; - - // default: no op - } -} - -inline void update_envelope( slot_t& sl ) -{ - int ecmp = sl.Ecmp; - if ( (sl.Ecnt += sl.Einc) >= ecmp ) - update_envelope_( &sl ); -} - -template -struct ym2612_update_chan { - static void func( tables_t&, channel_t&, Ym2612_GENS_Emu::sample_t*, int ); -}; - -typedef void (*ym2612_update_chan_t)( tables_t&, channel_t&, Ym2612_GENS_Emu::sample_t*, int ); - -template -void ym2612_update_chan::func( tables_t& g, channel_t& ch, - Ym2612_GENS_Emu::sample_t* buf, int length ) -{ - int not_end = ch.SLOT [S3].Ecnt - ENV_END; - - // algo is a compile-time constant, so all conditions based on it are resolved - // during compilation - - // special cases - if ( algo == 7 ) - not_end |= ch.SLOT [S0].Ecnt - ENV_END; - - if ( algo >= 5 ) - not_end |= ch.SLOT [S2].Ecnt - ENV_END; - - if ( algo >= 4 ) - not_end |= ch.SLOT [S1].Ecnt - ENV_END; - - int CH_S0_OUT_1 = ch.S0_OUT [1]; - - int in0 = ch.SLOT [S0].Fcnt; - int in1 = ch.SLOT [S1].Fcnt; - int in2 = ch.SLOT [S2].Fcnt; - int in3 = ch.SLOT [S3].Fcnt; - - int YM2612_LFOinc = g.LFOinc; - int YM2612_LFOcnt = g.LFOcnt + YM2612_LFOinc; - - if ( !not_end ) - return; - - do - { - // envelope - int const env_LFO = g.LFO_ENV_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK]; - - short const* const ENV_TAB = g.ENV_TAB; - - #define CALC_EN( x ) \ - int temp##x = ENV_TAB [ch.SLOT [S##x].Ecnt >> ENV_LBITS] + ch.SLOT [S##x].TLL; \ - int en##x = ((temp##x ^ ch.SLOT [S##x].env_xor) + (env_LFO >> ch.SLOT [S##x].AMS)) & \ - ((temp##x - ch.SLOT [S##x].env_max) >> 31); - - CALC_EN( 0 ) - CALC_EN( 1 ) - CALC_EN( 2 ) - CALC_EN( 3 ) - - int const* const TL_TAB = g.TL_TAB; - - #define SINT( i, o ) (TL_TAB [g.SIN_TAB [(i)] + (o)]) - - // feedback - int CH_S0_OUT_0 = ch.S0_OUT [0]; - { - int temp = in0 + ((CH_S0_OUT_0 + CH_S0_OUT_1) >> ch.FB); - CH_S0_OUT_1 = CH_S0_OUT_0; - CH_S0_OUT_0 = SINT( (temp >> SIN_LBITS) & SIN_MASK, en0 ); - } - - int CH_OUTd; - if ( algo == 0 ) - { - int temp = in1 + CH_S0_OUT_1; - temp = in2 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en1 ); - temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 ); - CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ); - } - else if ( algo == 1 ) - { - int temp = in2 + CH_S0_OUT_1 + SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 ); - temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 ); - CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ); - } - else if ( algo == 2 ) - { - int temp = in2 + SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 ); - temp = in3 + CH_S0_OUT_1 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 ); - CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ); - } - else if ( algo == 3 ) - { - int temp = in1 + CH_S0_OUT_1; - temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en1 ) + - SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ); - CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ); - } - else if ( algo == 4 ) - { - int temp = in3 + SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ); - CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ) + - SINT( ((in1 + CH_S0_OUT_1) >> SIN_LBITS) & SIN_MASK, en1 ); - //DO_LIMIT - } - else if ( algo == 5 ) - { - int temp = CH_S0_OUT_1; - CH_OUTd = SINT( ((in3 + temp) >> SIN_LBITS) & SIN_MASK, en3 ) + - SINT( ((in1 + temp) >> SIN_LBITS) & SIN_MASK, en1 ) + - SINT( ((in2 + temp) >> SIN_LBITS) & SIN_MASK, en2 ); - //DO_LIMIT - } - else if ( algo == 6 ) - { - CH_OUTd = SINT( (in3 >> SIN_LBITS) & SIN_MASK, en3 ) + - SINT( ((in1 + CH_S0_OUT_1) >> SIN_LBITS) & SIN_MASK, en1 ) + - SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ); - //DO_LIMIT - } - else if ( algo == 7 ) - { - CH_OUTd = SINT( (in3 >> SIN_LBITS) & SIN_MASK, en3 ) + - SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 ) + - SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ) + CH_S0_OUT_1; - //DO_LIMIT - } - - CH_OUTd >>= MAX_OUT_BITS - output_bits + 2; - - // update phase - unsigned freq_LFO = ((g.LFO_FREQ_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK] * - ch.FMS) >> (LFO_HBITS - 1 + 1)) + (1L << (LFO_FMS_LBITS - 1)); - YM2612_LFOcnt += YM2612_LFOinc; - in0 += (ch.SLOT [S0].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); - in1 += (ch.SLOT [S1].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); - in2 += (ch.SLOT [S2].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); - in3 += (ch.SLOT [S3].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); - - int t0 = buf [0] + (CH_OUTd & ch.LEFT); - int t1 = buf [1] + (CH_OUTd & ch.RIGHT); - - update_envelope( ch.SLOT [0] ); - update_envelope( ch.SLOT [1] ); - update_envelope( ch.SLOT [2] ); - update_envelope( ch.SLOT [3] ); - - ch.S0_OUT [0] = CH_S0_OUT_0; - buf [0] = t0; - buf [1] = t1; - buf += 2; - } - while ( --length ); - - ch.S0_OUT [1] = CH_S0_OUT_1; - - ch.SLOT [S0].Fcnt = in0; - ch.SLOT [S1].Fcnt = in1; - ch.SLOT [S2].Fcnt = in2; - ch.SLOT [S3].Fcnt = in3; -} - -static const ym2612_update_chan_t UPDATE_CHAN [8] = { - &ym2612_update_chan<0>::func, - &ym2612_update_chan<1>::func, - &ym2612_update_chan<2>::func, - &ym2612_update_chan<3>::func, - &ym2612_update_chan<4>::func, - &ym2612_update_chan<5>::func, - &ym2612_update_chan<6>::func, - &ym2612_update_chan<7>::func -}; - -void Ym2612_GENS_Impl::run_timer( int length ) -{ - int const step = 6; - int remain = length; - do - { - int n = step; - if ( n > remain ) - n = remain; - remain -= n; - - long i = n * YM2612.TimerBase; - if (YM2612.Mode & 1) // Timer A ON ? - { - // if ((YM2612.TimerAcnt -= 14073) <= 0) // 13879=NTSC (old: 14475=NTSC 14586=PAL) - if ((YM2612.TimerAcnt -= i) <= 0) - { - // timer a overflow - - YM2612.Status |= (YM2612.Mode & 0x04) >> 2; - YM2612.TimerAcnt += YM2612.TimerAL; - - if (YM2612.Mode & 0x80) - { - KEY_ON( YM2612.CHANNEL [2], 0 ); - KEY_ON( YM2612.CHANNEL [2], 1 ); - KEY_ON( YM2612.CHANNEL [2], 2 ); - KEY_ON( YM2612.CHANNEL [2], 3 ); - } - } - } - - if (YM2612.Mode & 2) // Timer B ON ? - { - // if ((YM2612.TimerBcnt -= 14073) <= 0) // 13879=NTSC (old: 14475=NTSC 14586=PAL) - if ((YM2612.TimerBcnt -= i) <= 0) - { - // timer b overflow - YM2612.Status |= (YM2612.Mode & 0x08) >> 2; - YM2612.TimerBcnt += YM2612.TimerBL; - } - } - } - while ( remain > 0 ); -} - -void Ym2612_GENS_Impl::run( int pair_count, Ym2612_GENS_Emu::sample_t* out ) -{ - if ( pair_count <= 0 ) - return; - - if ( YM2612.Mode & 3 ) - run_timer( pair_count ); - - // Mise Ă  jour des pas des compteurs-frequences s'ils ont ete modifies - - for ( int chi = 0; chi < channel_count; chi++ ) - { - channel_t& ch = YM2612.CHANNEL [chi]; - if ( ch.SLOT [0].Finc != -1 ) - continue; - - int i2 = 0; - if ( chi == 2 && (YM2612.Mode & 0x40) ) - i2 = 2; - - for ( int i = 0; i < 4; i++ ) - { - // static int seq [4] = { 2, 1, 3, 0 }; - // if ( i2 ) i2 = seq [i]; - - slot_t& sl = ch.SLOT [i]; - int finc = g.FINC_TAB [ch.FNUM [i2]] >> (7 - ch.FOCT [i2]); - int ksr = ch.KC [i2] >> sl.KSR_S; // keycode attenuation - sl.Finc = (finc + sl.DT [ch.KC [i2]]) * sl.MUL; - if (sl.KSR != ksr) // si le KSR a change alors - { // les differents taux pour l'enveloppe sont mis Ă  jour - sl.KSR = ksr; - - sl.EincA = sl.AR [ksr]; - sl.EincD = sl.DR [ksr]; - sl.EincS = sl.SR [ksr]; - sl.EincR = sl.RR [ksr]; - - if (sl.Ecurp == ATTACK) - { - sl.Einc = sl.EincA; - } - else if (sl.Ecurp == DECAY) - { - sl.Einc = sl.EincD; - } - else if (sl.Ecnt < ENV_END) - { - if (sl.Ecurp == SUBSTAIN) - sl.Einc = sl.EincS; - else if (sl.Ecurp == RELEASE) - sl.Einc = sl.EincR; - } - } - - if ( i2 ) - i2 = (i2 ^ 2) ^ (i2 >> 1); - } - } - - for ( int i = 0; i < channel_count; i++ ) - { - if ( !(mute_mask & (1 << i)) && (i != 5 || !YM2612.DAC) ) - UPDATE_CHAN [YM2612.CHANNEL [i].ALGO]( g, YM2612.CHANNEL [i], out, pair_count ); - } - - g.LFOcnt += g.LFOinc * pair_count; -} - -void Ym2612_GENS_Emu::run( int pair_count, sample_t* out ) { impl->run( pair_count, out ); } diff --git a/libraries/game-music-emu/gme/Ym2612_GENS.h b/libraries/game-music-emu/gme/Ym2612_GENS.h deleted file mode 100644 index 4cb2e8ae3..000000000 --- a/libraries/game-music-emu/gme/Ym2612_GENS.h +++ /dev/null @@ -1,38 +0,0 @@ -// YM2612 FM sound chip emulator interface - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef YM2612_EMU_H -#define YM2612_EMU_H - -struct Ym2612_GENS_Impl; - -class Ym2612_GENS_Emu { - Ym2612_GENS_Impl* impl; -public: - Ym2612_GENS_Emu() { impl = 0; } - ~Ym2612_GENS_Emu(); - - // Set output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - const char* set_rate( double sample_rate, double clock_rate ); - - // Reset to power-up state - void reset(); - - // Mute voice n if bit n (1 << n) of mask is set - enum { channel_count = 6 }; - void mute_voices( int mask ); - - // Write addr to register 0 then data to register 1 - void write0( int addr, int data ); - - // Write addr to register 2 then data to register 3 - void write1( int addr, int data ); - - // Run and add pair_count samples into current output buffer contents - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Ym2612_MAME.cpp b/libraries/game-music-emu/gme/Ym2612_MAME.cpp deleted file mode 100644 index 524dab55a..000000000 --- a/libraries/game-music-emu/gme/Ym2612_MAME.cpp +++ /dev/null @@ -1,3108 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -// Based on Mame YM2612 ym2612.c - -#include "Ym2612_MAME.h" - -/* -** -** File: fm2612.c -- software implementation of Yamaha YM2612 FM sound generator -** Split from fm.c to keep 2612 fixes from infecting other OPN chips -** -** Copyright Jarek Burczynski (bujar at mame dot net) -** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development -** -** Version 1.5.1 (Genesis Plus GX ym2612.c rev. 368) -** -*/ - -/* -** History: -** -** 2006~2012 Eke-Eke (Genesis Plus GX): -** Huge thanks to Nemesis, lot of those fixes came from his tests on Sega Genesis hardware -** More informations at http://gendev.spritesmind.net/forum/viewtopic.php?t=386 -** -** TODO: -** -** - core documentation -** - BUSY flag support -** -** CHANGELOG: -** -** 26-09-2017 Eke-Eke (Genesis Plus GX): -** - fixed EG counter loopback behavior (verified on YM3438 die) -** - reverted changes to EG rates 2-7 increment values -** -** xx-xx-xxxx -** - fixed LFO implementation: -** .added support for CH3 special mode: fixes various sound effects (birds in Warlock, bug sound in Aladdin...) -** .inverted LFO AM waveform: fixes Spider-Man & Venom : Separation Anxiety (intro), California Games (surfing event) -** .improved LFO timing accuracy: now updated AFTER sample output, like EG/PG updates, and without any precision loss anymore. -** - improved internal timers emulation -** - adjusted lowest EG rates increment values -** - fixed Attack Rate not being updated in some specific cases (Batman & Robin intro) -** - fixed EG behavior when Attack Rate is maximal -** - fixed EG behavior when SL=0 (Mega Turrican tracks 03,09...) or/and Key ON occurs at minimal attenuation -** - implemented EG output immediate changes on register writes -** - fixed YM2612 initial values (after the reset): fixes missing intro in B.O.B -** - implemented Detune overflow (Ariel, Comix Zone, Shaq Fu, Spiderman & many other games using GEMS sound engine) -** - implemented accurate CSM mode emulation -** - implemented accurate SSG-EG emulation (Asterix, Beavis&Butthead, Bubba'n Stix & many other games) -** - implemented accurate address/data ports behavior -** -** 06-23-2007 Zsolt Vasvari: -** - changed the timing not to require the use of floating point calculations -** -** 03-08-2003 Jarek Burczynski: -** - fixed YM2608 initial values (after the reset) -** - fixed flag and irqmask handling (YM2608) -** - fixed BUFRDY flag handling (YM2608) -** -** 14-06-2003 Jarek Burczynski: -** - implemented all of the YM2608 status register flags -** - implemented support for external memory read/write via YM2608 -** - implemented support for deltat memory limit register in YM2608 emulation -** -** 22-05-2003 Jarek Burczynski: -** - fixed LFO PM calculations (copy&paste bugfix) -** -** 08-05-2003 Jarek Burczynski: -** - fixed SSG support -** -** 22-04-2003 Jarek Burczynski: -** - implemented 100% correct LFO generator (verified on real YM2610 and YM2608) -** -** 15-04-2003 Jarek Burczynski: -** - added support for YM2608's register 0x110 - status mask -** -** 01-12-2002 Jarek Burczynski: -** - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608) -** The addressing patch used for early Neo-Geo games can be removed now. -** -** 26-11-2002 Jarek Burczynski, Nicola Salmoria: -** - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to: -** - added emulation of YM2608 drums. -** - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608) -** -** 16-08-2002 Jarek Burczynski: -** - binary exact Envelope Generator (verified on real YM2203); -** identical to YM2151 -** - corrected 'off by one' error in feedback calculations (when feedback is off) -** - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610) -** -** 18-12-2001 Jarek Burczynski: -** - added SSG-EG support (verified on real YM2203) -** -** 12-08-2001 Jarek Burczynski: -** - corrected sin_tab and tl_tab data (verified on real chip) -** - corrected feedback calculations (verified on real chip) -** - corrected phase generator calculations (verified on real chip) -** - corrected envelope generator calculations (verified on real chip) -** - corrected FM volume level (YM2610 and YM2610B). -** - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) : -** this was needed to calculate YM2610 FM channels output correctly. -** (Each FM channel is calculated as in other chips, but the output of the channel -** gets shifted right by one *before* sending to accumulator. That was impossible to do -** with previous implementation). -** -** 23-07-2001 Jarek Burczynski, Nicola Salmoria: -** - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip) -** -** 11-06-2001 Jarek Burczynski: -** - corrected end of sample bug in ADPCMA_calc_cha(). -** Real YM2610 checks for equality between current and end addresses (only 20 LSB bits). -** -** 08-12-98 hiro-shi: -** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA -** move ROM limit check.(CALC_CH? -> 2610Write1/2) -** test program (ADPCMB_TEST) -** move ADPCM A/B end check. -** ADPCMB repeat flag(no check) -** change ADPCM volume rate (8->16) (32->48). -** -** 09-12-98 hiro-shi: -** change ADPCM volume. (8->16, 48->64) -** replace ym2610 ch0/3 (YM-2610B) -** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff. -** add ADPCM_SHIFT_MASK -** change ADPCMA_DECODE_MIN/MAX. -*/ - -/************************************************************************/ -/* comment of hiro-shi(Hiromitsu Shioya) */ -/* YM2610(B) = OPN-B */ -/* YM2610 : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ -/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ -/************************************************************************/ - -#include -#include /* for memset */ -#include /* for NULL */ -#include -#include - -namespace Ym2612_MameImpl -{ - -/* ---- mamedef - begin ---- */ -/* typedefs to use MAME's (U)INTxx types (copied from MAME\src\ods\odscomm.h) */ -/* 8-bit values */ -typedef unsigned char UINT8; -typedef signed char INT8; - -/* 16-bit values */ -typedef unsigned short UINT16; -typedef signed short INT16; - -/* 32-bit values */ -#ifndef _WINDOWS_H -typedef unsigned int UINT32; -typedef signed int INT32; -#endif - -/* 64-bit values */ -#ifndef _WINDOWS_H -#ifdef _MSC_VER -typedef signed __int64 INT64; -typedef unsigned __int64 UINT64; -#else -__extension__ typedef unsigned long long UINT64; -__extension__ typedef signed long long INT64; -#endif -#endif - -/* offsets and addresses are 32-bit (for now...) */ -typedef UINT32 offs_t; - -/* stream_sample_t is used to represent a single sample in a sound stream */ -typedef INT16 stream_sample_t; - -#if defined(VGM_BIG_ENDIAN) -#define BYTE_XOR_BE(x) (x) -#elif defined(VGM_LITTLE_ENDIAN) -#define BYTE_XOR_BE(x) ((x) ^ 0x01) -#else -/* don't define BYTE_XOR_BE so that it throws an error when compiling */ -#endif - -#if defined(_MSC_VER) -//#define INLINE static __forceinline -#define INLINE static __inline -#elif defined(__GNUC__) -#define INLINE static __inline__ -#else -#define INLINE static inline -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#ifdef _DEBUG -#define logerror printf -#else -#define logerror -#endif - -typedef void (*SRATE_CALLBACK)(void*, UINT32); -/* ---- mamedef - end ---- */ - -/* --- select emulation chips --- */ -/* -#define BUILD_YM2203 (HAS_YM2203) // build YM2203(OPN) emulator -#define BUILD_YM2608 (HAS_YM2608) // build YM2608(OPNA) emulator -#define BUILD_YM2610 (HAS_YM2610) // build YM2610(OPNB) emulator -#define BUILD_YM2610B (HAS_YM2610B) // build YM2610B(OPNB?)emulator -#define BUILD_YM2612 (HAS_YM2612) // build YM2612(OPN2) emulator -#define BUILD_YM3438 (HAS_YM3438) // build YM3438(OPN) emulator -*/ -#define BUILD_YM2203 0 -#define BUILD_YM2608 0 -#define BUILD_YM2610 0 -#define BUILD_YM2610B 0 -#define BUILD_YM2612 1 -#define BUILD_YM3438 0 - -#define FM_BUSY_FLAG_SUPPORT 0 - -/* select bit size of output : 8 or 16 */ -#define FM_SAMPLE_BITS 16 - -/* select timer system internal or external */ -#define FM_INTERNAL_TIMER 1 - -/* --- speedup optimize --- */ -/* busy flag enulation , The definition of FM_GET_TIME_NOW() is necessary. */ -/* #define FM_BUSY_FLAG_SUPPORT 1 */ - -/* --- external SSG(YM2149/AY-3-8910)emulator interface port */ -/* used by YM2203,YM2608,and YM2610 */ -typedef struct _ssg_callbacks ssg_callbacks; -struct _ssg_callbacks -{ - void (*set_clock)(void *param, int clock); - void (*write)(void *param, int address, int data); - int (*read)(void *param); - void (*reset)(void *param); -}; - -/* --- external callback funstions for realtime update --- */ - -#if FM_BUSY_FLAG_SUPPORT -#define TIME_TYPE attotime -#define UNDEFINED_TIME attotime_zero -#define FM_GET_TIME_NOW(machine) timer_get_time(machine) -#define ADD_TIMES(t1, t2) attotime_add((t1), (t2)) -#define COMPARE_TIMES(t1, t2) attotime_compare((t1), (t2)) -#define MULTIPLY_TIME_BY_INT(t,i) attotime_mul(t, i) -#endif - -/* compiler dependence */ -#if 0 -#ifndef OSD_CPU_H -#define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -#endif /* OSD_CPU_H */ -#endif - -typedef stream_sample_t FMSAMPLE; -/* -#if (FM_SAMPLE_BITS==16) -typedef INT16 FMSAMPLE; -#endif -#if (FM_SAMPLE_BITS==8) -typedef unsigned char FMSAMPLE; -#endif -*/ - -typedef void (*FM_TIMERHANDLER)(void *param,int c,int cnt,int clock); -typedef void (*FM_IRQHANDLER)(void *param,int irq); -/* FM_TIMERHANDLER : Stop or Start timer */ -/* int n = chip number */ -/* int c = Channel 0=TimerA,1=TimerB */ -/* int count = timer count (0=stop) */ -/* doube stepTime = step time of one count (sec.)*/ - -/* FM_IRQHHANDLER : IRQ level changing sense */ -/* int n = chip number */ -/* int irq = IRQ level 0=OFF,1=ON */ - -/** - * @brief Initialize chip and return the instance - * @param param Unused, keep NULL - * @param baseclock YM2612 clock - * @param rate Output sample rate - * @param TimerHandler Keep NULL - * @param IRQHandler Keep NULL - * @return Chip instance or NULL on any error - */ -static void * ym2612_init(void *param, int baseclock, int rate, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); -/** - * @brief Free chip instance - * @param chip Chip instance - */ -static void ym2612_shutdown(void *chip); -/** - * @brief Reset state of the chip - * @param chip Chip instance - */ -static void ym2612_reset_chip(void *chip); -/** - * @brief Generate stereo output of specified length - * @param chip Chip instance - * @param buffer Output sound buffer - * @param frames Output buffer size in frames (one frame - two array entries of the buffer) - * @param mix 0 - override buffer data, 1 - mix output data with a content of the buffer - */ -static void ym2612_generate(void *chip, FMSAMPLE *buffer, int frames, int mix); -#define ym2612_update_one(chip, buffer, length) ym2612_generate(chip, buffer, length, 0) - -/** - * @brief Single-Sample generation prepare - * @param chip Chip instance - */ -static void ym2612_pre_generate(void *chip); -/** - * @brief Generate single stereo PCM frame. Will be used native sample rate of 53267 Hz - * @param chip Chip instance - * @param buffer One stereo PCM frame - */ -static void ym2612_generate_one_native(void *chip, FMSAMPLE buffer[2]); - -/* void ym2612_post_generate(void *chip, int length); */ - -static int ym2612_write(void *chip, int a,unsigned char v); -#if 0 -static unsigned char ym2612_read(void *chip,int a); -static int ym2612_timer_over(void *chip, int c ); -#endif - -#ifdef __STATE_H__ -static void ym2612_postload(void *chip); -#endif - -static void ym2612_set_mutemask(void *chip, UINT32 MuteMask); -#if 0 -static void ym2612_setoptions(UINT8 Flags); -#endif - - -static stream_sample_t *DUMMYBUF = NULL; - -/* shared function building option */ -#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B||BUILD_YM2612||BUILD_YM3438) -#define BUILD_OPN_PRESCALER (BUILD_YM2203||BUILD_YM2608) - -#define RSM_ENABLE 0 -#define RSM_FRAC 10 - -/* globals */ -#define TYPE_SSG 0x01 /* SSG support */ -#define TYPE_LFOPAN 0x02 /* OPN type LFO and PAN */ -#define TYPE_6CH 0x04 /* FM 6CH / 3CH */ -#define TYPE_DAC 0x08 /* YM2612's DAC device */ -#define TYPE_ADPCM 0x10 /* two ADPCM units */ -#define TYPE_2610 0x20 /* bogus flag to differentiate 2608 from 2610 */ - - -#define TYPE_YM2203 (TYPE_SSG) -#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM) -#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM |TYPE_2610) -#define TYPE_YM2612 (TYPE_DAC |TYPE_LFOPAN |TYPE_6CH) - - -/* globals */ -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ -#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ -#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ - -#define FREQ_MASK ((1<>3) - -/* sin waveform table in 'decibel' scale */ -static unsigned int sin_tab[SIN_LEN]; - -/* sustain level table (3dB per step) */ -/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */ -/* 1, 2, 4, 8, 16, 32, 64 (value)*/ -/* 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/ - -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -/* attenuation value (10 bits) = (SL << 2) << 3 */ -#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) ) -static const UINT32 sl_table[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) -}; -#undef SC - - -#define RATE_STEPS (8) -static const UINT8 eg_inc[19*RATE_STEPS]={ - -/*cycle:0 1 2 3 4 5 6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ - -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ - -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ -/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ -/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ -/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ - -/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ -/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ -/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ -}; - - -#define O(a) (a*RATE_STEPS) - -/*note that there is no O(17) in this table - it's directly in the code */ -static const UINT8 eg_rate_select2612[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ -/* 32 infinite time rates (same as Rate 0) */ -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), -O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), - -/* rates 00-11 */ -/* -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -*/ -O(18),O(18),O( 2),O( 3), /* from Nemesis's tests on real YM2612 hardware */ -O( 0),O( 1),O( 2),O( 2), /* Nemesis's tests */ - -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), - -/* rate 12 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 13 */ -O( 8),O( 9),O(10),O(11), - -/* rate 14 */ -O(12),O(13),O(14),O(15), - -/* rate 15 */ -O(16),O(16),O(16),O(16), - -/* 32 dummy rates (same as 15 3) */ -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), -O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) - -}; -#undef O - -/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ -/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ -/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ - -#define O(a) (a*1) -static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ -/* 32 infinite time rates */ -/* O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), */ - -/* fixed (should be the same as rate 0, even if it makes no difference since increment value is 0 for these rates) */ -O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), -O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), -O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), -O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), - -/* rates 00-11 */ -O(11),O(11),O(11),O(11), -O(10),O(10),O(10),O(10), -O( 9),O( 9),O( 9),O( 9), -O( 8),O( 8),O( 8),O( 8), -O( 7),O( 7),O( 7),O( 7), -O( 6),O( 6),O( 6),O( 6), -O( 5),O( 5),O( 5),O( 5), -O( 4),O( 4),O( 4),O( 4), -O( 3),O( 3),O( 3),O( 3), -O( 2),O( 2),O( 2),O( 2), -O( 1),O( 1),O( 1),O( 1), -O( 0),O( 0),O( 0),O( 0), - -/* rate 12 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 13 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 14 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 15 */ -O( 0),O( 0),O( 0),O( 0), - -/* 32 dummy rates (same as 15 3) */ -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) - -}; -#undef O - -static const UINT8 dt_tab[4 * 32]={ -/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/ -/* FD=0 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -/* FD=1 */ - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, -/* FD=2 */ - 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, - 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, -/* FD=3 */ - 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, - 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 -}; - - -/* OPN key frequency number -> key code follow table */ -/* fnum higher 4bit -> keycode lower 2bit */ -static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; - - -/* 8 LFO speed parameters */ -/* each value represents number of samples that one LFO level will last for */ -static const UINT32 lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5}; - - - -/*There are 4 different LFO AM depths available, they are: - 0 dB, 1.4 dB, 5.9 dB, 11.8 dB - Here is how it is generated (in EG steps): - - 11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0 - 5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0 - 1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0 - - (1.4 dB is losing precision as you can see) - - It's implemented as generator from 0..126 with step 2 then a shift - right N times, where N is: - 8 for 0 dB - 3 for 1.4 dB - 1 for 5.9 dB - 0 for 11.8 dB -*/ -static const UINT8 lfo_ams_depth_shift[4] = {8, 3, 1, 0}; - - - -/*There are 8 different LFO PM depths available, they are: - 0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents) - - Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10 - (bits 8,9,10 = FNUM MSB from OCT/FNUM register) - - Here we store only first quarter (positive one) of full waveform. - Full table (lfo_pm_table) containing all 128 waveforms is build - at run (init) time. - - One value in table below represents 4 (four) basic LFO steps - (1 PM step = 4 AM steps). - - For example: - at LFO SPEED=0 (which is 108 samples per basic LFO step) - one value from "lfo_pm_output" table lasts for 432 consecutive - samples (4*108=432) and one full LFO waveform cycle lasts for 13824 - samples (32*432=13824; 32 because we store only a quarter of whole - waveform in the table below) -*/ -static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */ -/* FNUM BIT 4: 000 0001xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 6 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 7 */ {0, 0, 0, 0, 1, 1, 1, 1}, - -/* FNUM BIT 5: 000 0010xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 6 */ {0, 0, 0, 0, 1, 1, 1, 1}, -/* DEPTH 7 */ {0, 0, 1, 1, 2, 2, 2, 3}, - -/* FNUM BIT 6: 000 0100xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 1}, -/* DEPTH 5 */ {0, 0, 0, 0, 1, 1, 1, 1}, -/* DEPTH 6 */ {0, 0, 1, 1, 2, 2, 2, 3}, -/* DEPTH 7 */ {0, 0, 2, 3, 4, 4, 5, 6}, - -/* FNUM BIT 7: 000 1000xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 1, 1}, -/* DEPTH 3 */ {0, 0, 0, 0, 1, 1, 1, 1}, -/* DEPTH 4 */ {0, 0, 0, 1, 1, 1, 1, 2}, -/* DEPTH 5 */ {0, 0, 1, 1, 2, 2, 2, 3}, -/* DEPTH 6 */ {0, 0, 2, 3, 4, 4, 5, 6}, -/* DEPTH 7 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, - -/* FNUM BIT 8: 001 0000xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 1, 1, 1, 1}, -/* DEPTH 2 */ {0, 0, 0, 1, 1, 1, 2, 2}, -/* DEPTH 3 */ {0, 0, 1, 1, 2, 2, 3, 3}, -/* DEPTH 4 */ {0, 0, 1, 2, 2, 2, 3, 4}, -/* DEPTH 5 */ {0, 0, 2, 3, 4, 4, 5, 6}, -/* DEPTH 6 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, -/* DEPTH 7 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, - -/* FNUM BIT 9: 010 0000xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 2, 2, 2, 2}, -/* DEPTH 2 */ {0, 0, 0, 2, 2, 2, 4, 4}, -/* DEPTH 3 */ {0, 0, 2, 2, 4, 4, 6, 6}, -/* DEPTH 4 */ {0, 0, 2, 4, 4, 4, 6, 8}, -/* DEPTH 5 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, -/* DEPTH 6 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, -/* DEPTH 7 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, - -/* FNUM BIT10: 100 0000xxxx */ -/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, -/* DEPTH 1 */ {0, 0, 0, 0, 4, 4, 4, 4}, -/* DEPTH 2 */ {0, 0, 0, 4, 4, 4, 8, 8}, -/* DEPTH 3 */ {0, 0, 4, 4, 8, 8, 0xc, 0xc}, -/* DEPTH 4 */ {0, 0, 4, 8, 8, 8, 0xc,0x10}, -/* DEPTH 5 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, -/* DEPTH 6 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, -/* DEPTH 7 */ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60}, - -}; - -/* all 128 LFO PM waveforms */ -static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */ - -/* register number to channel number , slot offset */ -#define OPN_CHAN(N) (N&3) -#define OPN_SLOT(N) ((N>>2)&3) - -/* slot number */ -#define SLOT1 0 -#define SLOT2 2 -#define SLOT3 1 -#define SLOT4 3 - -/* bit0 = Right enable , bit1 = Left enable */ -#define OUTD_RIGHT 1 -#define OUTD_LEFT 2 -#define OUTD_CENTER 3 - - -/* save output as raw 16-bit sample */ -/* #define SAVE_SAMPLE */ - -#ifdef SAVE_SAMPLE -static FILE *sample[1]; - #if 1 /*save to MONO file */ - #define SAVE_ALL_CHANNELS \ - { signed int pom = lt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - } - #else /*save to STEREO file */ - #define SAVE_ALL_CHANNELS \ - { signed int pom = lt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - pom = rt; \ - fputc((unsigned short)pom&0xff,sample[0]); \ - fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ - } - #endif -#endif - - -/* struct describing a single operator (SLOT) */ -typedef struct -{ - INT32 *DT; /* detune :dt_tab[DT] */ - UINT8 KSR; /* key scale rate :3-KSR */ - UINT32 ar; /* attack rate */ - UINT32 d1r; /* decay rate */ - UINT32 d2r; /* sustain rate */ - UINT32 rr; /* release rate */ - UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */ - UINT32 mul; /* multiple :ML_TABLE[ML] */ - - /* Phase Generator */ - UINT32 phase; /* phase counter */ - INT32 Incr; /* phase step */ - - /* Envelope Generator */ - UINT8 state; /* phase type */ - UINT32 tl; /* total level: TL << 3 */ - INT32 volume; /* envelope counter */ - UINT32 sl; /* sustain level:sl_table[SL] */ - UINT32 vol_out; /* current output from EG circuit (without AM from LFO) */ - - UINT8 eg_sh_ar; /* (attack state) */ - UINT8 eg_sel_ar; /* (attack state) */ - UINT8 eg_sh_d1r; /* (decay state) */ - UINT8 eg_sel_d1r; /* (decay state) */ - UINT8 eg_sh_d2r; /* (sustain state) */ - UINT8 eg_sel_d2r; /* (sustain state) */ - UINT8 eg_sh_rr; /* (release state) */ - UINT8 eg_sel_rr; /* (release state) */ - - UINT8 ssg; /* SSG-EG waveform */ - UINT8 ssgn; /* SSG-EG negated output */ - - UINT8 key; /* 0=last key was KEY OFF, 1=KEY ON */ - - /* LFO */ - UINT32 AMmask; /* AM enable flag */ - -} FM_SLOT; - -typedef struct -{ - FM_SLOT SLOT[4]; /* four SLOTs (operators) */ - - UINT8 ALGO; /* algorithm */ - UINT8 FB; /* feedback shift */ - INT32 op1_out[2]; /* op1 output for feedback */ - - INT32 *connect1; /* SLOT1 output pointer */ - INT32 *connect3; /* SLOT3 output pointer */ - INT32 *connect2; /* SLOT2 output pointer */ - INT32 *connect4; /* SLOT4 output pointer */ - - INT32 *mem_connect;/* where to put the delayed sample (MEM) */ - INT32 mem_value; /* delayed sample (MEM) value */ - - INT32 pms; /* channel PMS */ - UINT8 ams; /* channel AMS */ - - UINT32 fc; /* fnum,blk:adjusted to sample rate */ - UINT8 kcode; /* key code: */ - UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ - UINT8 Muted; -} FM_CH; - - -typedef struct -{ - /* running_device *device; */ - void * param; /* this chip parameter */ - double freqbase; /* frequency base */ - int timer_prescaler; /* timer prescaler */ - UINT8 irq; /* interrupt level */ - UINT8 irqmask; /* irq mask */ -#if FM_BUSY_FLAG_SUPPORT - TIME_TYPE busy_expiry_time; /* expiry time of the busy status */ -#endif - UINT32 clock; /* master clock (Hz) */ - UINT32 rate; /* internal sampling rate (Hz) */ -#if RSM_ENABLE - INT32 rateratio; /* resampling ratio */ - INT32 framecnt; /* resampling frames count*/ - FMSAMPLE cur_sample[2]; /* previous sample */ - FMSAMPLE prev_sample[2]; /* previous sample */ -#endif - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT32 mode; /* mode CSM / 3SLOT */ - UINT8 fn_h; /* freq latch */ - UINT8 prescaler_sel; /* prescaler selector */ - INT32 TA; /* timer a */ - INT32 TAC; /* timer a counter */ - UINT8 TB; /* timer b */ - INT32 TBC; /* timer b counter */ - /* local time tables */ - INT32 dt_tab[8][32]; /* DeTune table */ - /* Extention Timer and IRQ handler */ - FM_TIMERHANDLER timer_handler; - FM_IRQHANDLER IRQ_Handler; - const ssg_callbacks *SSG; -} FM_ST; - - - -/***********************************************************/ -/* OPN unit */ -/***********************************************************/ - -/* OPN 3slot struct */ -typedef struct -{ - UINT32 fc[3]; /* fnum3,blk3: calculated */ - UINT8 fn_h; /* freq3 latch */ - UINT8 kcode[3]; /* key code */ - UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ - UINT8 key_csm; /* CSM mode Key-ON flag */ -} FM_3SLOT; - -/* OPN/A/B common state */ -typedef struct -{ - UINT8 type; /* chip type */ - FM_ST ST; /* general state */ - FM_3SLOT SL3; /* 3 slot mode state */ - FM_CH *P_CH; /* pointer of CH */ - unsigned int pan[6*2]; /* fm channels output masks (0xffffffff = enable) */ - - UINT32 eg_cnt; /* global envelope generator counter */ - UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/144/3 */ - UINT32 eg_timer_add; /* step of eg_timer */ - UINT32 eg_timer_overflow;/* envelope generator timer overlfows every 3 samples (on real chip) */ - - - /* there are 2048 FNUMs that can be generated using FNUM/BLK registers - but LFO works with one more bit of a precision so we really need 4096 elements */ - UINT32 fn_table[4096]; /* fnumber->increment counter */ - UINT32 fn_max; /* maximal phase increment (used for phase overflow) */ - - /* LFO */ - UINT8 lfo_cnt; /* current LFO phase (out of 128) */ - UINT32 lfo_timer; /* current LFO phase runs at LFO frequency */ - UINT32 lfo_timer_add; /* step of lfo_timer */ - UINT32 lfo_timer_overflow; /* LFO timer overflows every N samples (depends on LFO frequency) */ - UINT32 LFO_AM; /* current LFO AM step */ - UINT32 LFO_PM; /* current LFO PM step */ - - INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */ - INT32 mem; /* one sample delay memory */ - INT32 out_fm[6]; /* outputs of working channels */ - -} FM_OPN; - -/* here's the virtual YM2612 */ -typedef struct -{ - UINT8 REGS[512]; /* registers */ - FM_OPN OPN; /* OPN state */ - FM_CH CH[6]; /* channel state */ - UINT8 addr_A1; /* address line A1 */ - - /* dac output (YM2612) */ - /* int dacen; */ - UINT8 dacen; - UINT8 dac_test; - INT32 dacout; - UINT8 MuteDAC; - - UINT8 WaveOutMode; - INT32 WaveL; - INT32 WaveR; -} YM2612; - -/* log output level */ -#define LOG_ERR 3 /* ERROR */ -#define LOG_WAR 2 /* WARNING */ -#define LOG_INF 1 /* INFORMATION */ -#define LOG_LEVEL LOG_INF - -#ifndef __RAINE__ -#define LOG(n,x) do { if( (n)>=LOG_LEVEL ) logerror x; } while (0) -#endif - -/* limitter */ -#define Limit(val, max,min) { \ - if ( val > max ) val = max; \ - else if ( val < min ) val = min; \ -} - -#if 0 -#define USE_VGM_INIT_SWITCH -static UINT8 IsVGMInit = 0; -#endif -static UINT8 PseudoSt = 0x00; -/*#include -static FILE* hFile; -static UINT32 FileSample;*/ - -/* status set and IRQ handling */ -INLINE void FM_STATUS_SET(FM_ST *ST,int flag) -{ - /* set status flag */ - ST->status |= flag; - if ( !(ST->irq) && (ST->status & ST->irqmask) ) - { - ST->irq = 1; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,1); - } -} - -/* status reset and IRQ handling */ -INLINE void FM_STATUS_RESET(FM_ST *ST,int flag) -{ - /* reset status flag */ - ST->status &=~flag; - if ( (ST->irq) && !(ST->status & ST->irqmask) ) - { - ST->irq = 0; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,0); - } -} - -/* IRQ mask set */ -INLINE void FM_IRQMASK_SET(FM_ST *ST,int flag) -{ - ST->irqmask = flag; - /* IRQ handling check */ - FM_STATUS_SET(ST,0); - FM_STATUS_RESET(ST,0); -} - -INLINE void FM_KEYON(FM_OPN *OPN, FM_CH *CH , int s ) -{ - FM_SLOT *SLOT = &CH->SLOT[s]; - - /* Note by Valley Bell: - I assume that the CSM mode shouldn't affect channels - other than FM3, so I added a check for it here.*/ - if( !SLOT->key && (!OPN->SL3.key_csm || CH == &OPN->P_CH[3])) - { - /* restart Phase Generator */ - SLOT->phase = 0; - - /* reset SSG-EG inversion flag */ - SLOT->ssgn = 0; - - if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) - { - SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT; - } - else - { - /* force attenuation level to 0 */ - SLOT->volume = MIN_ATT_INDEX; - - /* directly switch to Decay (or Sustain) */ - SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; - } - - /* recalculate EG output */ - if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - - SLOT->key = 1; -} - -INLINE void FM_KEYOFF(FM_OPN *OPN, FM_CH *CH , int s ) -{ - FM_SLOT *SLOT = &CH->SLOT[s]; - - if (SLOT->key && (!OPN->SL3.key_csm || CH == &OPN->P_CH[3])) - { -#ifdef USE_VGM_INIT_SWITCH - if (IsVGMInit) /* workaround for VGMs trimmed with VGMTool */ - { - SLOT->state = EG_OFF; - SLOT->volume = MAX_ATT_INDEX; - SLOT->vol_out= MAX_ATT_INDEX; - } - else -#endif - if (SLOT->state>EG_REL) - { - SLOT->state = EG_REL; /* phase -> Release */ - - /* SSG-EG specific update */ - if (SLOT->ssg&0x08) - { - /* convert EG attenuation level */ - if (SLOT->ssgn ^ (SLOT->ssg&0x04)) - SLOT->volume = (0x200 - SLOT->volume); - - /* force EG attenuation level */ - if (SLOT->volume >= 0x200) - { - SLOT->volume = MAX_ATT_INDEX; - SLOT->state = EG_OFF; - } - - /* recalculate EG output */ - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - } - } - - SLOT->key = 0; -} - -INLINE void FM_KEYON_CSM(FM_OPN *OPN, FM_CH *CH , int s ) -{ - FM_SLOT *SLOT = &CH->SLOT[s]; - - if( !SLOT->key && !OPN->SL3.key_csm) - { - /* restart Phase Generator */ - SLOT->phase = 0; - - /* reset SSG-EG inversion flag */ - SLOT->ssgn = 0; - - if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) - { - SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT; - } - else - { - /* force attenuation level to 0 */ - SLOT->volume = MIN_ATT_INDEX; - - /* directly switch to Decay (or Sustain) */ - SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; - } - - /* recalculate EG output */ - if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } -} - -INLINE void FM_KEYOFF_CSM(FM_CH *CH , int s ) -{ - FM_SLOT *SLOT = &CH->SLOT[s]; - if (!SLOT->key) - { -#ifdef USE_VGM_INIT_SWITCH - if (IsVGMInit) - { - SLOT->state = EG_OFF; - SLOT->volume = MAX_ATT_INDEX; - SLOT->vol_out= MAX_ATT_INDEX; - } - else -#endif - if (SLOT->state>EG_REL) - { - SLOT->state = EG_REL; /* phase -> Release */ - - /* SSG-EG specific update */ - if (SLOT->ssg&0x08) - { - /* convert EG attenuation level */ - if (SLOT->ssgn ^ (SLOT->ssg&0x04)) - SLOT->volume = (0x200 - SLOT->volume); - - /* force EG attenuation level */ - if (SLOT->volume >= 0x200) - { - SLOT->volume = MAX_ATT_INDEX; - SLOT->state = EG_OFF; - } - - /* recalculate EG output */ - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - } - } -} - -/* OPN Mode Register Write */ -INLINE void set_timers( FM_OPN *OPN, FM_ST *ST, void *n, int v ) -{ - /* b7 = CSM MODE */ - /* b6 = 3 slot mode */ - /* b5 = reset b */ - /* b4 = reset a */ - /* b3 = timer enable b */ - /* b2 = timer enable a */ - /* b1 = load b */ - /* b0 = load a */ - - if ((OPN->ST.mode ^ v) & 0xC0) - { - /* phase increment need to be recalculated */ - OPN->P_CH[2].SLOT[SLOT1].Incr=-1; - - /* CSM mode disabled and CSM key ON active*/ - if (((v & 0xC0) != 0x80) && OPN->SL3.key_csm) - { - /* CSM Mode Key OFF (verified by Nemesis on real hardware) */ - FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT1); - FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT2); - FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT3); - FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT4); - OPN->SL3.key_csm = 0; - } - } - - /* reset Timer b flag */ - if( v & 0x20 ) - FM_STATUS_RESET(ST,0x02); - /* reset Timer a flag */ - if( v & 0x10 ) - FM_STATUS_RESET(ST,0x01); - /* load b */ - if ((v&2) && !(ST->mode&2)) - { - ST->TBC = ( 256-ST->TB)<<4; - /* External timer handler */ - if (ST->timer_handler) (ST->timer_handler)(n,1,ST->TBC * ST->timer_prescaler,(int)ST->clock); - } - /* load a */ - if ((v&1) && !(ST->mode&1)) - { - ST->TAC = (1024-ST->TA); - /* External timer handler */ - if (ST->timer_handler) (ST->timer_handler)(n,0,ST->TAC * ST->timer_prescaler,(int)ST->clock); - ST->TAC *= 4096; - } - - ST->mode = (UINT32)v; -} - - -/* Timer A Overflow */ -INLINE void TimerAOver(FM_ST *ST) -{ - /* set status (if enabled) */ - if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); - /* clear or reload the counter */ - ST->TAC = (1024-ST->TA); - if (ST->timer_handler) (ST->timer_handler)(ST->param,0,ST->TAC * ST->timer_prescaler,(int)ST->clock); - ST->TAC *= 4096; -} -/* Timer B Overflow */ -INLINE void TimerBOver(FM_ST *ST) -{ - /* set status (if enabled) */ - if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); - /* clear or reload the counter */ - ST->TBC = ( 256-ST->TB)<<4; - if (ST->timer_handler) (ST->timer_handler)(ST->param,1,ST->TBC * ST->timer_prescaler,(int)ST->clock); -} - - -#if FM_INTERNAL_TIMER -/* ----- internal timer mode , update timer */ -/* Valley Bell: defines fixed */ - -/* ---------- calculate timer A ---------- */ - #define INTERNAL_TIMER_A(ST,CSM_CH) \ - { \ - if( (ST)->TAC && ((ST)->timer_handler==0) ) \ - if( ((ST)->TAC -= (int)((ST)->freqbase*4096)) <= 0 ) \ - { \ - TimerAOver( ST ); \ - /* CSM mode total level latch and auto key on */ \ - if( (ST)->mode & 0x80 ) \ - CSMKeyControll( OPN, CSM_CH ); \ - } \ - } -/* ---------- calculate timer B ---------- */ - #define INTERNAL_TIMER_B(ST,step) \ - { \ - if( (ST)->TBC && ((ST)->timer_handler==0) ) \ - if( ((ST)->TBC -= (int)((ST)->freqbase*4096*step)) <= 0 ) \ - TimerBOver( ST ); \ - } -#else /* FM_INTERNAL_TIMER */ -/* external timer mode */ -#define INTERNAL_TIMER_A(ST,CSM_CH) -#define INTERNAL_TIMER_B(ST,step) -#endif /* FM_INTERNAL_TIMER */ - - - -#if FM_BUSY_FLAG_SUPPORT -#define FM_BUSY_CLEAR(ST) ((ST)->busy_expiry_time = UNDEFINED_TIME) -INLINE UINT8 FM_STATUS_FLAG(FM_ST *ST) -{ - if( COMPARE_TIMES(ST->busy_expiry_time, UNDEFINED_TIME) != 0 ) - { - if (COMPARE_TIMES(ST->busy_expiry_time, FM_GET_TIME_NOW(ST->device->machine)) > 0) - return ST->status | 0x80; /* with busy */ - /* expire */ - FM_BUSY_CLEAR(ST); - } - return ST->status; -} -INLINE void FM_BUSY_SET(FM_ST *ST,int busyclock ) -{ - TIME_TYPE expiry_period = MULTIPLY_TIME_BY_INT(ATTOTIME_IN_HZ(ST->clock), busyclock * ST->timer_prescaler); - ST->busy_expiry_time = ADD_TIMES(FM_GET_TIME_NOW(ST->device->machine), expiry_period); -} -#else -#define FM_STATUS_FLAG(ST) ((ST)->status) -#define FM_BUSY_SET(ST,bclock) {} -#define FM_BUSY_CLEAR(ST) {} -#endif - - -/* set algorithm connection */ -INLINE void setup_connection( FM_OPN *OPN, FM_CH *CH, int ch ) -{ - INT32 *carrier = &OPN->out_fm[ch]; - - INT32 **om1 = &CH->connect1; - INT32 **om2 = &CH->connect3; - INT32 **oc1 = &CH->connect2; - - INT32 **memc = &CH->mem_connect; - - switch( CH->ALGO ) - { - case 0: - /* M1---C1---MEM---M2---C2---OUT */ - *om1 = &OPN->c1; - *oc1 = &OPN->mem; - *om2 = &OPN->c2; - *memc= &OPN->m2; - break; - case 1: - /* M1------+-MEM---M2---C2---OUT */ - /* C1-+ */ - *om1 = &OPN->mem; - *oc1 = &OPN->mem; - *om2 = &OPN->c2; - *memc= &OPN->m2; - break; - case 2: - /* M1-----------------+-C2---OUT */ - /* C1---MEM---M2-+ */ - *om1 = &OPN->c2; - *oc1 = &OPN->mem; - *om2 = &OPN->c2; - *memc= &OPN->m2; - break; - case 3: - /* M1---C1---MEM------+-C2---OUT */ - /* M2-+ */ - *om1 = &OPN->c1; - *oc1 = &OPN->mem; - *om2 = &OPN->c2; - *memc= &OPN->c2; - break; - case 4: - /* M1---C1-+-OUT */ - /* M2---C2-+ */ - /* MEM: not used */ - *om1 = &OPN->c1; - *oc1 = carrier; - *om2 = &OPN->c2; - *memc= &OPN->mem; /* store it anywhere where it will not be used */ - break; - case 5: - /* +----C1----+ */ - /* M1-+-MEM---M2-+-OUT */ - /* +----C2----+ */ - *om1 = 0; /* special mark */ - *oc1 = carrier; - *om2 = carrier; - *memc= &OPN->m2; - break; - case 6: - /* M1---C1-+ */ - /* M2-+-OUT */ - /* C2-+ */ - /* MEM: not used */ - *om1 = &OPN->c1; - *oc1 = carrier; - *om2 = carrier; - *memc= &OPN->mem; /* store it anywhere where it will not be used */ - break; - case 7: - /* M1-+ */ - /* C1-+-OUT */ - /* M2-+ */ - /* C2-+ */ - /* MEM: not used*/ - *om1 = carrier; - *oc1 = carrier; - *om2 = carrier; - *memc= &OPN->mem; /* store it anywhere where it will not be used */ - break; - } - - CH->connect4 = carrier; -} - -/* set detune & multiple */ -INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v) -{ - SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1; - SLOT->DT = ST->dt_tab[(v>>4)&7]; - CH->SLOT[SLOT1].Incr=-1; -} - -/* set total level */ -INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v) -{ - SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ - (void)CH; - - /* recalculate EG output */ - if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)) && (SLOT->state > EG_REL)) - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; -} - -/* set attack rate & key scale */ -INLINE void set_ar_ksr(UINT8 type, FM_CH *CH,FM_SLOT *SLOT,int v) -{ - UINT8 old_KSR = SLOT->KSR; - (void)type; - - SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; - - SLOT->KSR = 3-(v>>6); - if (SLOT->KSR != old_KSR) - { - CH->SLOT[SLOT1].Incr=-1; - } - - /* Even if it seems unnecessary, in some odd case, KSR and KC are both modified */ - /* and could result in SLOT->kc remaining unchanged. */ - /* In such case, AR values would not be recalculated despite SLOT->ar has changed */ - /* This fixes the introduction music of Batman & Robin (Eke-Eke) */ - if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select2612[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 18*RATE_STEPS; /* verified by Nemesis on real hardware */ - } -} - -/* set decay rate */ -INLINE void set_dr(UINT8 type, FM_SLOT *SLOT,int v) -{ - (void)type; - SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; - - SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; - SLOT->eg_sel_d1r= eg_rate_select2612[SLOT->d1r + SLOT->ksr]; -} - -/* set sustain rate */ -INLINE void set_sr(UINT8 type, FM_SLOT *SLOT,int v) -{ - (void)type; - SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; - - SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; - SLOT->eg_sel_d2r= eg_rate_select2612[SLOT->d2r + SLOT->ksr]; -} - -/* set release rate */ -INLINE void set_sl_rr(UINT8 type, FM_SLOT *SLOT,int v) -{ - (void)type; - SLOT->sl = sl_table[ v>>4 ]; - - /* check EG state changes */ - if ((SLOT->state == EG_DEC) && (SLOT->volume >= (INT32)(SLOT->sl))) - SLOT->state = EG_SUS; - - SLOT->rr = 34 + ((v&0x0f)<<2); - - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; - SLOT->eg_sel_rr = eg_rate_select2612[SLOT->rr + SLOT->ksr]; -} - -/* advance LFO to next sample */ -INLINE void advance_lfo(FM_OPN *OPN) -{ - if (OPN->lfo_timer_overflow) /* LFO enabled ? */ - { - /* increment LFO timer */ - OPN->lfo_timer += OPN->lfo_timer_add; - - /* when LFO is enabled, one level will last for 108, 77, 71, 67, 62, 44, 8 or 5 samples */ - while (OPN->lfo_timer >= OPN->lfo_timer_overflow) - { - OPN->lfo_timer -= OPN->lfo_timer_overflow; - - /* There are 128 LFO steps */ - OPN->lfo_cnt = ( OPN->lfo_cnt + 1 ) & 127; - - /* Valley Bell: Replaced old code (non-inverted triangle) with - the one from Genesis Plus GX 1.71. */ - /* triangle (inverted) */ - /* AM: from 126 to 0 step -2, 0 to 126 step +2 */ - if (OPN->lfo_cnt<64) - OPN->LFO_AM = (UINT32)(OPN->lfo_cnt ^ 63) << 1; - else - OPN->LFO_AM = (UINT32)(OPN->lfo_cnt & 63) << 1; - - /* PM works with 4 times slower clock */ - OPN->LFO_PM = OPN->lfo_cnt >> 2; - } - } -} - -INLINE void advance_eg_channel(FM_OPN *OPN, FM_SLOT *SLOT) -{ - /* unsigned int out; */ - unsigned int i = 4; /* four operators per channel */ - - do - { - switch(SLOT->state) - { - case EG_ATT: /* attack phase */ - if (!(OPN->eg_cnt & ((1<eg_sh_ar)-1))) - { - /* update attenuation level */ - SLOT->volume += (~SLOT->volume * (eg_inc[SLOT->eg_sel_ar + ((OPN->eg_cnt>>SLOT->eg_sh_ar)&7)]))>>4; - - /* check phase transition*/ - if (SLOT->volume <= MIN_ATT_INDEX) - { - SLOT->volume = MIN_ATT_INDEX; - SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; /* special case where SL=0 */ - } - - /* recalculate EG output */ - if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) /* SSG-EG Output Inversion */ - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - break; - - case EG_DEC: /* decay phase */ - if (!(OPN->eg_cnt & ((1<eg_sh_d1r)-1))) - { - /* SSG EG type */ - if (SLOT->ssg&0x08) - { - /* update attenuation level */ - if (SLOT->volume < 0x200) - { - SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)]; - - /* recalculate EG output */ - if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */ - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - - } - else - { - /* update attenuation level */ - SLOT->volume += eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)]; - - /* recalculate EG output */ - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - - /* check phase transition*/ - if (SLOT->volume >= (INT32)(SLOT->sl)) - SLOT->state = EG_SUS; - } - break; - - case EG_SUS: /* sustain phase */ - if (!(OPN->eg_cnt & ((1<eg_sh_d2r)-1))) - { - /* SSG EG type */ - if (SLOT->ssg&0x08) - { - /* update attenuation level */ - if (SLOT->volume < 0x200) - { - SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)]; - - /* recalculate EG output */ - if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */ - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - } - else - { - /* update attenuation level */ - SLOT->volume += eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)]; - - /* check phase transition*/ - if ( SLOT->volume >= MAX_ATT_INDEX ) - SLOT->volume = MAX_ATT_INDEX; - /* do not change SLOT->state (verified on real chip) */ - - /* recalculate EG output */ - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - } - break; - - case EG_REL: /* release phase */ - if (!(OPN->eg_cnt & ((1<eg_sh_rr)-1))) - { - /* SSG EG type */ - if (SLOT->ssg&0x08) - { - /* update attenuation level */ - if (SLOT->volume < 0x200) - SLOT->volume += 4 * eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)]; - /* check phase transition */ - if (SLOT->volume >= 0x200) - { - SLOT->volume = MAX_ATT_INDEX; - SLOT->state = EG_OFF; - } - } - else - { - /* update attenuation level */ - SLOT->volume += eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)]; - - /* check phase transition*/ - if (SLOT->volume >= MAX_ATT_INDEX) - { - SLOT->volume = MAX_ATT_INDEX; - SLOT->state = EG_OFF; - } - } - - /* recalculate EG output */ - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - - } - break; - } - - /* Valley Bell: These few lines are missing in Genesis Plus GX' ym2612 core file. - Disabling them fixes the SSG-EG. - Additional Note: Asterix and the Great Rescue: Level 1 sounds "better" with these lines, - but less accurate. */ - #if 0 - out = ((UINT32)SLOT->volume); - - /* negate output (changes come from alternate bit, init comes from attack bit) */ - if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && (SLOT->state > EG_REL)) - out ^= MAX_ATT_INDEX; - - /* we need to store the result here because we are going to change ssgn - in next instruction */ - SLOT->vol_out = out + SLOT->tl; - #endif - - SLOT++; - i--; - } while (i); - -} - -/* SSG-EG update process */ -/* The behavior is based upon Nemesis tests on real hardware */ -/* This is actually executed before each samples */ -INLINE void update_ssg_eg_channel(FM_SLOT *SLOT) -{ - unsigned int i = 4; /* four operators per channel */ - - do - { - /* detect SSG-EG transition */ - /* this is not required during release phase as the attenuation has been forced to MAX and output invert flag is not used */ - /* if an Attack Phase is programmed, inversion can occur on each sample */ - if ((SLOT->ssg & 0x08) && (SLOT->volume >= 0x200) && (SLOT->state > EG_REL)) - { - if (SLOT->ssg & 0x01) /* bit 0 = hold SSG-EG */ - { - /* set inversion flag */ - if (SLOT->ssg & 0x02) - SLOT->ssgn = 4; - - /* force attenuation level during decay phases */ - if ((SLOT->state != EG_ATT) && !(SLOT->ssgn ^ (SLOT->ssg & 0x04))) - SLOT->volume = MAX_ATT_INDEX; - } - else /* loop SSG-EG */ - { - /* toggle output inversion flag or reset Phase Generator */ - if (SLOT->ssg & 0x02) - SLOT->ssgn ^= 4; - else - SLOT->phase = 0; - - /* same as Key ON */ - if (SLOT->state != EG_ATT) - { - if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) - { - SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT; - } - else - { - /* Attack Rate is maximal: directly switch to Decay or Substain */ - SLOT->volume = MIN_ATT_INDEX; - SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; - } - } - } - - /* recalculate EG output */ - if (SLOT->ssgn ^ (SLOT->ssg&0x04)) - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - - /* next slot */ - SLOT++; - i--; - } while (i); -} - - -INLINE void update_phase_lfo_slot(FM_OPN *OPN, FM_SLOT *SLOT, INT32 pms, UINT32 block_fnum) -{ - UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; - INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + pms + OPN->LFO_PM ]; - - block_fnum = block_fnum*2 + lfo_fn_table_index_offset; - - if (lfo_fn_table_index_offset) /* LFO phase modulation active */ - { - UINT8 blk = (block_fnum&0x7000) >> 12; - UINT32 fn = block_fnum & 0xfff; - - /* recalculate keyscale code */ - /*int kc = (blk<<2) | opn_fktable[fn >> 7];*/ - /* This really stupid bug caused a read outside of the - array [size 0x10] and returned invalid values. - This caused an annoying vibrato for some notes. - (Note: seems to be a copy-and-paste from OPNWriteReg -> case 0xA0) - Why are MAME cores always SOO buggy ?! */ - /* Oh, and before I forget: it's correct in fm.c */ - int kc = (blk<<2) | opn_fktable[fn >> 8]; - /* Thanks to Blargg - his patch that helped me to find this bug */ - - /* recalculate (frequency) phase increment counter */ - int fc = (OPN->fn_table[fn]>>(7-blk)) + SLOT->DT[kc]; - - /* (frequency) phase overflow (credits to Nemesis) */ - if (fc < 0) fc += OPN->fn_max; - - /* update phase */ - SLOT->phase += (fc * SLOT->mul) >> 1; - } - else /* LFO phase modulation = zero */ - { - SLOT->phase += SLOT->Incr; - } -} - -INLINE void update_phase_lfo_channel(FM_OPN *OPN, FM_CH *CH) -{ - UINT32 block_fnum = CH->block_fnum; - - UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; - INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + OPN->LFO_PM ]; - - block_fnum = block_fnum*2 + lfo_fn_table_index_offset; - - if (lfo_fn_table_index_offset) /* LFO phase modulation active */ - { - UINT8 blk = (block_fnum&0x7000) >> 12; - UINT32 fn = block_fnum & 0xfff; - - /* recalculate keyscale code */ - /*int kc = (blk<<2) | opn_fktable[fn >> 7];*/ - /* the same stupid bug as above */ - int kc = (blk<<2) | opn_fktable[fn >> 8]; - - /* recalculate (frequency) phase increment counter */ - int fc = (OPN->fn_table[fn]>>(7-blk)); - - /* (frequency) phase overflow (credits to Nemesis) */ - int finc = fc + CH->SLOT[SLOT1].DT[kc]; - if (finc < 0) finc += OPN->fn_max; - CH->SLOT[SLOT1].phase += (finc*CH->SLOT[SLOT1].mul) >> 1; - - finc = fc + CH->SLOT[SLOT2].DT[kc]; - if (finc < 0) finc += OPN->fn_max; - CH->SLOT[SLOT2].phase += (finc*CH->SLOT[SLOT2].mul) >> 1; - - finc = fc + CH->SLOT[SLOT3].DT[kc]; - if (finc < 0) finc += OPN->fn_max; - CH->SLOT[SLOT3].phase += (finc*CH->SLOT[SLOT3].mul) >> 1; - - finc = fc + CH->SLOT[SLOT4].DT[kc]; - if (finc < 0) finc += OPN->fn_max; - CH->SLOT[SLOT4].phase += (finc*CH->SLOT[SLOT4].mul) >> 1; - } - else /* LFO phase modulation = zero */ - { - CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr; - CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr; - CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr; - CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr; - } -} - -/* update phase increment and envelope generator */ -INLINE void refresh_fc_eg_slot(FM_OPN *OPN, FM_SLOT *SLOT , int fc , int kc ) -{ - int ksr = kc >> SLOT->KSR; - - fc += SLOT->DT[kc]; - - /* detects frequency overflow (credits to Nemesis) */ - if (fc < 0) fc += OPN->fn_max; - - /* (frequency) phase increment counter */ - SLOT->Incr = (fc * SLOT->mul) >> 1; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - - /* calculate envelope generator rates */ - if ((SLOT->ar + SLOT->ksr) < 32+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select2612[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 18*RATE_STEPS; /* verified by Nemesis on real hardware (Attack phase is blocked) */ - } - - SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; - SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; - - SLOT->eg_sel_d1r= eg_rate_select2612[SLOT->d1r + SLOT->ksr]; - SLOT->eg_sel_d2r= eg_rate_select2612[SLOT->d2r + SLOT->ksr]; - SLOT->eg_sel_rr = eg_rate_select2612[SLOT->rr + SLOT->ksr]; - } -} - -/* update phase increment counters */ -INLINE void refresh_fc_eg_chan(FM_OPN *OPN, FM_CH *CH ) -{ - if( CH->SLOT[SLOT1].Incr==-1) - { - int fc = CH->fc; - int kc = CH->kcode; - refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT1] , fc , kc ); - refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT2] , fc , kc ); - refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT3] , fc , kc ); - refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT4] , fc , kc ); - } -} - -#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask)) - -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm) -{ - UINT32 p; - - p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) -{ - UINT32 p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ]; - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -INLINE void chan_calc(YM2612 *F2612, FM_OPN *OPN, FM_CH *CH) -{ - UINT32 AM = OPN->LFO_AM >> CH->ams; - unsigned int eg_out; - - if (CH->Muted) - return; - - OPN->m2 = OPN->c1 = OPN->c2 = OPN->mem = 0; - - *CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ - - eg_out = volume_calc(&CH->SLOT[SLOT1]); - { - INT32 out = CH->op1_out[0] + CH->op1_out[1]; - CH->op1_out[0] = CH->op1_out[1]; - - if( !CH->connect1 ) - { - /* algorithm 5 */ - OPN->mem = OPN->c1 = OPN->c2 = CH->op1_out[0]; - } - else - { - /* other algorithms */ - *CH->connect1 += CH->op1_out[0]; - } - - - CH->op1_out[1] = 0; - if( eg_out < ENV_QUIET ) /* SLOT 1 */ - { - if (!CH->FB) - out=0; - - CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<FB) ); - } - } - - eg_out = volume_calc(&CH->SLOT[SLOT3]); - if( eg_out < ENV_QUIET ) /* SLOT 3 */ - *CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, OPN->m2); - - eg_out = volume_calc(&CH->SLOT[SLOT2]); - if( eg_out < ENV_QUIET ) /* SLOT 2 */ - *CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, OPN->c1); - - eg_out = volume_calc(&CH->SLOT[SLOT4]); - if( eg_out < ENV_QUIET ) /* SLOT 4 */ - *CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, OPN->c2); - - - /* store current MEM */ - CH->mem_value = OPN->mem; - - /* update phase counters AFTER output calculations */ - if(CH->pms) - { - /* add support for 3 slot mode */ - if ((OPN->ST.mode & 0xC0) && (CH == &F2612->CH[2])) - { - update_phase_lfo_slot(OPN, &CH->SLOT[SLOT1], CH->pms, OPN->SL3.block_fnum[1]); - update_phase_lfo_slot(OPN, &CH->SLOT[SLOT2], CH->pms, OPN->SL3.block_fnum[2]); - update_phase_lfo_slot(OPN, &CH->SLOT[SLOT3], CH->pms, OPN->SL3.block_fnum[0]); - update_phase_lfo_slot(OPN, &CH->SLOT[SLOT4], CH->pms, CH->block_fnum); - } - else update_phase_lfo_channel(OPN, CH); - } - else /* no LFO phase modulation */ - { - CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr; - CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr; - CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr; - CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr; - } -} - -static void FMCloseTable( void ) -{ -#ifdef SAVE_SAMPLE - fclose(sample[0]); -#endif - return; -} - - -/* CSM Key Controll */ -INLINE void CSMKeyControll(FM_OPN *OPN, FM_CH *CH) -{ - /* all key ON (verified by Nemesis on real hardware) */ - FM_KEYON_CSM(OPN,CH,SLOT1); - FM_KEYON_CSM(OPN,CH,SLOT2); - FM_KEYON_CSM(OPN,CH,SLOT3); - FM_KEYON_CSM(OPN,CH,SLOT4); - OPN->SL3.key_csm = 1; -} - -#ifdef __STATE_H__ -/* FM channel save , internal state only */ -static void FMsave_state_channel(running_device *device,FM_CH *CH,int num_ch) -{ - int slot , ch; - - for(ch=0;chop1_out); - state_save_register_device_item(device, ch, CH->fc); - /* slots */ - for(slot=0;slot<4;slot++) - { - FM_SLOT *SLOT = &CH->SLOT[slot]; - state_save_register_device_item(device, ch * 4 + slot, SLOT->phase); - state_save_register_device_item(device, ch * 4 + slot, SLOT->state); - state_save_register_device_item(device, ch * 4 + slot, SLOT->volume); - } - } -} - -static void FMsave_state_st(running_device *device,FM_ST *ST) -{ -#if FM_BUSY_FLAG_SUPPORT - state_save_register_device_item(device, 0, ST->busy_expiry_time.seconds ); - state_save_register_device_item(device, 0, ST->busy_expiry_time.attoseconds ); -#endif - state_save_register_device_item(device, 0, ST->address ); - state_save_register_device_item(device, 0, ST->irq ); - state_save_register_device_item(device, 0, ST->irqmask ); - state_save_register_device_item(device, 0, ST->status ); - state_save_register_device_item(device, 0, ST->mode ); - state_save_register_device_item(device, 0, ST->prescaler_sel ); - state_save_register_device_item(device, 0, ST->fn_h ); - state_save_register_device_item(device, 0, ST->TA ); - state_save_register_device_item(device, 0, ST->TAC ); - state_save_register_device_item(device, 0, ST->TB ); - state_save_register_device_item(device, 0, ST->TBC ); -} -#endif /* _STATE_H */ - -#if BUILD_OPN -/* write a OPN mode register 0x20-0x2f */ -static void OPNWriteMode(FM_OPN *OPN, int r, int v) -{ - UINT8 c; - FM_CH *CH; - - switch(r) - { - case 0x21: /* Test */ - break; - case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */ - if (v&8) /* LFO enabled ? */ - { - #if 0 - if (!OPN->lfo_timer_overflow) - { - /* restart LFO */ - OPN->lfo_cnt = 0; - OPN->lfo_timer = 0; - OPN->LFO_AM = 0; - OPN->LFO_PM = 0; - } - #endif - - OPN->lfo_timer_overflow = lfo_samples_per_step[v&7] << LFO_SH; - } - else - { - /* Valley Bell: Ported from Genesis Plus GX 1.71 - hold LFO waveform in reset state */ - OPN->lfo_timer_overflow = 0; - OPN->lfo_timer = 0; - OPN->lfo_cnt = 0; - - - OPN->LFO_PM = 0; - OPN->LFO_AM = 126; - /* OPN->lfo_timer_overflow = 0; */ - } - break; - case 0x24: /* timer A High 8*/ - OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2); - break; - case 0x25: /* timer A Low 2*/ - OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3); - break; - case 0x26: /* timer B */ - OPN->ST.TB = (UINT8)v; - break; - case 0x27: /* mode, timer control */ - set_timers( OPN, &(OPN->ST),OPN->ST.param,v ); - break; - case 0x28: /* key on / off */ - c = v & 0x03; - if( c == 3 ) break; - if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3; - CH = OPN->P_CH; - CH = &CH[c]; - if(v&0x10) FM_KEYON(OPN,CH,SLOT1); else FM_KEYOFF(OPN,CH,SLOT1); - if(v&0x20) FM_KEYON(OPN,CH,SLOT2); else FM_KEYOFF(OPN,CH,SLOT2); - if(v&0x40) FM_KEYON(OPN,CH,SLOT3); else FM_KEYOFF(OPN,CH,SLOT3); - if(v&0x80) FM_KEYON(OPN,CH,SLOT4); else FM_KEYOFF(OPN,CH,SLOT4); - break; - } -} - -/* write a OPN register (0x30-0xff) */ -static void OPNWriteReg(FM_OPN *OPN, int r, int v) -{ - FM_CH *CH; - FM_SLOT *SLOT; - - UINT8 c = OPN_CHAN(r); - - if (c == 3) return; /* 0xX3,0xX7,0xXB,0xXF */ - - if (r >= 0x100) c+=3; - - CH = OPN->P_CH; - CH = &CH[c]; - - SLOT = &(CH->SLOT[OPN_SLOT(r)]); - - switch( r & 0xf0 ) { - case 0x30: /* DET , MUL */ - set_det_mul(&OPN->ST,CH,SLOT,v); - break; - - case 0x40: /* TL */ - set_tl(CH,SLOT,v); - break; - - case 0x50: /* KS, AR */ - set_ar_ksr(OPN->type,CH,SLOT,v); - break; - - case 0x60: /* bit7 = AM ENABLE, DR */ - set_dr(OPN->type, SLOT,v); - - if(OPN->type & TYPE_LFOPAN) /* YM2608/2610/2610B/2612 */ - { - SLOT->AMmask = (v&0x80) ? ~0 : 0; - } - break; - - case 0x70: /* SR */ - set_sr(OPN->type,SLOT,v); - break; - - case 0x80: /* SL, RR */ - set_sl_rr(OPN->type,SLOT,v); - break; - - case 0x90: /* SSG-EG */ - SLOT->ssg = v&0x0f; - - /* recalculate EG output */ - if (SLOT->state > EG_REL) - { - if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) - SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; - else - SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; - } - - /* SSG-EG envelope shapes : - - E AtAlH - 1 0 0 0 \\\\ - - 1 0 0 1 \___ - - 1 0 1 0 \/\/ - ___ - 1 0 1 1 \ - - 1 1 0 0 //// - ___ - 1 1 0 1 / - - 1 1 1 0 /\/\ - - 1 1 1 1 /___ - - - E = SSG-EG enable - - - The shapes are generated using Attack, Decay and Sustain phases. - - Each single character in the diagrams above represents this whole - sequence: - - - when KEY-ON = 1, normal Attack phase is generated (*without* any - difference when compared to normal mode), - - - later, when envelope level reaches minimum level (max volume), - the EG switches to Decay phase (which works with bigger steps - when compared to normal mode - see below), - - - later when envelope level passes the SL level, - the EG swithes to Sustain phase (which works with bigger steps - when compared to normal mode - see below), - - - finally when envelope level reaches maximum level (min volume), - the EG switches to Attack phase again (depends on actual waveform). - - Important is that when switch to Attack phase occurs, the phase counter - of that operator will be zeroed-out (as in normal KEY-ON) but not always. - (I havent found the rule for that - perhaps only when the output level is low) - - The difference (when compared to normal Envelope Generator mode) is - that the resolution in Decay and Sustain phases is 4 times lower; - this results in only 256 steps instead of normal 1024. - In other words: - when SSG-EG is disabled, the step inside of the EG is one, - when SSG-EG is enabled, the step is four (in Decay and Sustain phases). - - Times between the level changes are the same in both modes. - - - Important: - Decay 1 Level (so called SL) is compared to actual SSG-EG output, so - it is the same in both SSG and no-SSG modes, with this exception: - - when the SSG-EG is enabled and is generating raising levels - (when the EG output is inverted) the SL will be found at wrong level !!! - For example, when SL=02: - 0 -6 = -6dB in non-inverted EG output - 96-6 = -90dB in inverted EG output - Which means that EG compares its level to SL as usual, and that the - output is simply inverted afterall. - - - The Yamaha's manuals say that AR should be set to 0x1f (max speed). - That is not necessary, but then EG will be generating Attack phase. - - */ - - - break; - - case 0xa0: - switch( OPN_SLOT(r) ) - { - case 0: /* 0xa0-0xa2 : FNUM1 */ -#ifdef USE_VGM_INIT_SWITCH - if (IsVGMInit) - OPN->ST.fn_h = CH->block_fnum >> 8; -#endif - { - UINT32 fn = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + v; - UINT8 blk = OPN->ST.fn_h>>3; - /* keyscale code */ - CH->kcode = (blk<<2) | opn_fktable[fn >> 7]; - /* phase increment counter */ - CH->fc = OPN->fn_table[fn*2]>>(7-blk); - - /* store fnum in clear form for LFO PM calculations */ - CH->block_fnum = (blk<<11) | fn; - - CH->SLOT[SLOT1].Incr=-1; - } - break; - case 1: /* 0xa4-0xa6 : FNUM2,BLK */ - OPN->ST.fn_h = v&0x3f; -#ifdef USE_VGM_INIT_SWITCH - if (IsVGMInit) // workaround for stupid Kega Fusion init block - CH->block_fnum = (OPN->ST.fn_h << 8) | (CH->block_fnum & 0xFF); -#endif - break; - case 2: /* 0xa8-0xaa : 3CH FNUM1 */ -#ifdef USE_VGM_INIT_SWITCH - if (IsVGMInit) - OPN->SL3.fn_h = OPN->SL3.block_fnum[c] >> 8; -#endif - if(r < 0x100) - { - UINT32 fn = (((UINT32)(OPN->SL3.fn_h&7))<<8) + v; - UINT8 blk = OPN->SL3.fn_h>>3; - /* keyscale code */ - OPN->SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7]; - /* phase increment counter */ - OPN->SL3.fc[c] = OPN->fn_table[fn*2]>>(7-blk); - OPN->SL3.block_fnum[c] = (blk<<11) | fn; - (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; - } - break; - case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ - if(r < 0x100) - { - OPN->SL3.fn_h = v&0x3f; -#ifdef USE_VGM_INIT_SWITCH - if (IsVGMInit) - OPN->SL3.block_fnum[c] = (OPN->SL3.fn_h << 8) | (OPN->SL3.block_fnum[c] & 0xFF); -#endif - } - break; - } - break; - - case 0xb0: - switch( OPN_SLOT(r) ) - { - case 0: /* 0xb0-0xb2 : FB,ALGO */ - { - unsigned char feedback = ((v>>3)&7); - CH->ALGO = v&7; - CH->FB = feedback ? feedback + 6 : 0; - setup_connection( OPN, CH, c ); - } - break; - case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */ - if( OPN->type & TYPE_LFOPAN) - { - /* b0-2 PMS */ - CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */ - - /* b4-5 AMS */ - CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03]; - - /* PAN : b7 = L, b6 = R */ - OPN->pan[ c*2 ] = (v & 0x80) ? ~0 : 0; - OPN->pan[ c*2+1 ] = (v & 0x40) ? ~0 : 0; - - } - break; - } - break; - } -} - -/* initialize time tables */ -static void init_timetables(FM_OPN *OPN, double freqbase) -{ - int i,d; - double rate; - - /* DeTune table */ - for (d = 0;d <= 3;d++) - { - for (i = 0;i <= 31;i++) - { - rate = ((double)dt_tab[d*32 + i]) * freqbase * (1<<(FREQ_SH-10)); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ - OPN->ST.dt_tab[d][i] = (INT32) rate; - OPN->ST.dt_tab[d+4][i] = -OPN->ST.dt_tab[d][i]; - } - } - - /* there are 2048 FNUMs that can be generated using FNUM/BLK registers - but LFO works with one more bit of a precision so we really need 4096 elements */ - /* calculate fnumber -> increment counter table */ - for(i = 0; i < 4096; i++) - { - /* freq table for octave 7 */ - /* OPN phase increment counter = 20bit */ - /* the correct formula is : F-Number = (144 * fnote * 2^20 / M) / 2^(B-1) */ - /* where sample clock is M/144 */ - /* this means the increment value for one clock sample is FNUM * 2^(B-1) = FNUM * 64 for octave 7 */ - /* we also need to handle the ratio between the chip frequency and the emulated frequency (can be 1.0) */ - OPN->fn_table[i] = (UINT32)( (double)i * 32 * freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ - } - - /* maximal frequency is required for Phase overflow calculation, register size is 17 bits (Nemesis) */ - OPN->fn_max = (UINT32)( (double)0x20000 * freqbase * (1<<(FREQ_SH-10)) ); -} - -/* prescaler set (and make time tables) */ -static void OPNSetPres(FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres) -{ - /* frequency base */ - OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0; - - /* EG is updated every 3 samples */ - OPN->eg_timer_add = (UINT32)((1<ST.freqbase); - OPN->eg_timer_overflow = ( 3 ) * (1<lfo_timer_add = (UINT32)((1<ST.freqbase); - - /* Timer base time */ - OPN->ST.timer_prescaler = timer_prescaler; - - /* SSG part prescaler set */ - if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres ); - - /* make time tables */ - init_timetables(OPN, OPN->ST.freqbase); -} - -static void reset_channels( FM_ST *ST , FM_CH *CH , int num ) -{ - int c,s; - (void)ST; - - for( c = 0 ; c < num ; c++ ) - { - /* memset(&CH[c], 0x00, sizeof(FM_CH)); */ - CH[c].mem_value = 0; - CH[c].op1_out[0] = 0; - CH[c].op1_out[1] = 0; - CH[c].fc = 0; - for(s = 0 ; s < 4 ; s++ ) - { - /* memset(&CH[c].SLOT[s], 0x00, sizeof(FM_SLOT)); */ - CH[c].SLOT[s].Incr = -1; - CH[c].SLOT[s].key = 0; - CH[c].SLOT[s].phase = 0; - CH[c].SLOT[s].ssg = 0; - CH[c].SLOT[s].ssgn = 0; - CH[c].SLOT[s].state= EG_OFF; - CH[c].SLOT[s].volume = MAX_ATT_INDEX; - CH[c].SLOT[s].vol_out= MAX_ATT_INDEX; - } - } -} - -/* initialize generic tables */ -static void init_tables(void) -{ - signed int i,x; - signed int n; - double o,m; - - /* build Linear Power Table */ - for (x=0; x>= 4; /* 12 bits here */ - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - /* 11 bits here (rounded) */ - n <<= 2; /* 13 bits here (as in real chip) */ - - - /* 14 bits (with sign bit) */ - tl_tab[ x*2 + 0 ] = n; - tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - - /* one entry in the 'Power' table use the following format, xxxxxyyyyyyyys with: */ - /* s = sign bit */ - /* yyyyyyyy = 8-bits decimal part (0-TL_RES_LEN) */ - /* xxxxx = 5-bits integer 'shift' value (0-31) but, since Power table output is 13 bits, */ - /* any value above 13 (included) would be discarded. */ - for (i=1; i<13; i++) - { - tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; - tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; - } - } - - /* build Logarithmic Sinus table */ - for (i=0; i0.0) - o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ - else - o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ - - o = o / (ENV_STEP/4); - - n = (int)(2.0*o); - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - - /* 13-bits (8.5) value is formatted for above 'Power' table */ - sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - } - - /* build LFO PM modulation table */ - for(i = 0; i < 8; i++) /* 8 PM depths */ - { - UINT8 fnum; - for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */ - { - UINT8 value; - UINT8 step; - UINT32 offset_depth = i; - UINT32 offset_fnum_bit; - UINT32 bit_tmp; - - for (step=0; step<8; step++) - { - value = 0; - for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */ - { - if (fnum & (1<CH; - FMSAMPLE *bufOut = buffer; - int i; -#if !RSM_ENABLE - FMSAMPLE bufTmp[2]; -#endif - - ym2612_pre_generate(chip); - - if (!frames) - { - update_ssg_eg_channel(&cch[0].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[1].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[2].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[3].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[4].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[5].SLOT[SLOT1]); - } - - /* buffering */ - for(i=0 ; i < frames ; i++) - { -#if RSM_ENABLE - while(F2612->OPN.ST.framecnt >= F2612->OPN.ST.rateratio)/* Copy-Pasta from Nuked */ - { - /* Copy-Pasta from Nuked */ - F2612->OPN.ST.prev_sample[0] = F2612->OPN.ST.cur_sample[0]; - F2612->OPN.ST.prev_sample[1] = F2612->OPN.ST.cur_sample[1]; - ym2612_generate_one_native(chip, F2612->OPN.ST.cur_sample); - F2612->OPN.ST.framecnt -= F2612->OPN.ST.rateratio; - /* Copy-Pasta from Nuked */ - } - if (mix) - { - *bufOut++ += (FMSAMPLE)((F2612->OPN.ST.prev_sample[0] * (F2612->OPN.ST.rateratio - F2612->OPN.ST.framecnt) - + F2612->OPN.ST.cur_sample[0] * F2612->OPN.ST.framecnt) / F2612->OPN.ST.rateratio); - *bufOut++ += (FMSAMPLE)((F2612->OPN.ST.prev_sample[1] * (F2612->OPN.ST.rateratio - F2612->OPN.ST.framecnt) - + F2612->OPN.ST.cur_sample[1] * F2612->OPN.ST.framecnt) / F2612->OPN.ST.rateratio); - } else { - *bufOut++ = (FMSAMPLE)((F2612->OPN.ST.prev_sample[0] * (F2612->OPN.ST.rateratio - F2612->OPN.ST.framecnt) - + F2612->OPN.ST.cur_sample[0] * F2612->OPN.ST.framecnt) / F2612->OPN.ST.rateratio); - *bufOut++ = (FMSAMPLE)((F2612->OPN.ST.prev_sample[1] * (F2612->OPN.ST.rateratio - F2612->OPN.ST.framecnt) - + F2612->OPN.ST.cur_sample[1] * F2612->OPN.ST.framecnt) / F2612->OPN.ST.rateratio); - } - F2612->OPN.ST.framecnt += 1 << RSM_FRAC; -#else - if (mix) - { - ym2612_generate_one_native(chip, bufTmp); - bufOut[0] += bufTmp[0]; - bufOut[1] += bufTmp[1]; - } - else - { - ym2612_generate_one_native(chip, bufOut); - } - bufOut += 2; -#endif - } - /* ym2612_post_generate(chip, frames); */ -} - -void ym2612_pre_generate(void *chip) -{ - YM2612 *F2612 = (YM2612 *)chip; - FM_OPN *OPN = &F2612->OPN; - FM_CH *cch = F2612->CH; - - /* refresh PG and EG */ - refresh_fc_eg_chan( OPN, &cch[0] ); - refresh_fc_eg_chan( OPN, &cch[1] ); - if( (OPN->ST.mode & 0xc0) ) - { - /* 3SLOT MODE */ - if( cch[2].SLOT[SLOT1].Incr==-1) - { - refresh_fc_eg_slot(OPN, &cch[2].SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - refresh_fc_eg_slot(OPN, &cch[2].SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - refresh_fc_eg_slot(OPN, &cch[2].SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - refresh_fc_eg_slot(OPN, &cch[2].SLOT[SLOT4] , cch[2].fc , cch[2].kcode ); - } - } else - refresh_fc_eg_chan( OPN, &cch[2] ); - refresh_fc_eg_chan( OPN, &cch[3] ); - refresh_fc_eg_chan( OPN, &cch[4] ); - refresh_fc_eg_chan( OPN, &cch[5] ); -} - -void ym2612_generate_one_native(void *chip, FMSAMPLE buffer[]) -{ - YM2612 *F2612 = (YM2612 *)chip; - FM_OPN *OPN = &F2612->OPN; - INT32 *out_fm = OPN->out_fm; - FM_CH *cch = F2612->CH; - INT32 dacout; - int lt,rt; - - if (! F2612->MuteDAC) - dacout = F2612->dacout; - else - dacout = 0; - - /* clear outputs */ - out_fm[0] = 0; - out_fm[1] = 0; - out_fm[2] = 0; - out_fm[3] = 0; - out_fm[4] = 0; - out_fm[5] = 0; - - /* update SSG-EG output */ - update_ssg_eg_channel(&cch[0].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[1].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[2].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[3].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[4].SLOT[SLOT1]); - update_ssg_eg_channel(&cch[5].SLOT[SLOT1]); - - /* calculate FM */ - if (! F2612->dac_test) - { - chan_calc(F2612, OPN, &cch[0]); - chan_calc(F2612, OPN, &cch[1]); - chan_calc(F2612, OPN, &cch[2]); - chan_calc(F2612, OPN, &cch[3]); - chan_calc(F2612, OPN, &cch[4]); - if( F2612->dacen ) - cch[5].connect4 += dacout; - else - chan_calc(F2612, OPN, &cch[5]); - } - else - { - out_fm[0] = out_fm[1] = dacout; - out_fm[2] = out_fm[3] = dacout; - out_fm[5] = dacout; - } - - /* advance LFO */ - advance_lfo(OPN); - - /* advance envelope generator */ - OPN->eg_timer += OPN->eg_timer_add; - while (OPN->eg_timer >= OPN->eg_timer_overflow) - { - /* reset EG timer */ - OPN->eg_timer -= OPN->eg_timer_overflow; - /* increment EG counter */ - OPN->eg_cnt++; - /* EG counter is 12-bit only and zero value is skipped (verified on real hardware) */ - if (OPN->eg_cnt == 4096) - OPN->eg_cnt = 1; - - /* advance envelope generator */ - advance_eg_channel(OPN, &cch[0].SLOT[SLOT1]); - advance_eg_channel(OPN, &cch[1].SLOT[SLOT1]); - advance_eg_channel(OPN, &cch[2].SLOT[SLOT1]); - advance_eg_channel(OPN, &cch[3].SLOT[SLOT1]); - advance_eg_channel(OPN, &cch[4].SLOT[SLOT1]); - advance_eg_channel(OPN, &cch[5].SLOT[SLOT1]); - } - - /*fprintf(hFile, "%u", FileSample, out_fm[0]); - for (lt = 0; lt < 6; lt ++) - fprintf(hFile, "\t%d", out_fm[lt]); - fprintf(hFile, "\n"); - FileSample ++;*/ - - if (out_fm[0] > 8192) out_fm[0] = 8192; - else if (out_fm[0] < -8192) out_fm[0] = -8192; - if (out_fm[1] > 8192) out_fm[1] = 8192; - else if (out_fm[1] < -8192) out_fm[1] = -8192; - if (out_fm[2] > 8192) out_fm[2] = 8192; - else if (out_fm[2] < -8192) out_fm[2] = -8192; - if (out_fm[3] > 8192) out_fm[3] = 8192; - else if (out_fm[3] < -8192) out_fm[3] = -8192; - if (out_fm[4] > 8192) out_fm[4] = 8192; - else if (out_fm[4] < -8192) out_fm[4] = -8192; - if (out_fm[5] > 8192) out_fm[5] = 8192; - else if (out_fm[5] < -8192) out_fm[5] = -8192; - - /* 6-channels mixing */ - lt = ((out_fm[0]>>0) & OPN->pan[0]); - rt = ((out_fm[0]>>0) & OPN->pan[1]); - lt += ((out_fm[1]>>0) & OPN->pan[2]); - rt += ((out_fm[1]>>0) & OPN->pan[3]); - lt += ((out_fm[2]>>0) & OPN->pan[4]); - rt += ((out_fm[2]>>0) & OPN->pan[5]); - lt += ((out_fm[3]>>0) & OPN->pan[6]); - rt += ((out_fm[3]>>0) & OPN->pan[7]); - if (! F2612->dac_test) - { - lt += ((out_fm[4]>>0) & OPN->pan[8]); - rt += ((out_fm[4]>>0) & OPN->pan[9]); - } - else - { - lt += dacout; - lt += dacout; - } - lt += ((out_fm[5]>>0) & OPN->pan[10]); - rt += ((out_fm[5]>>0) & OPN->pan[11]); - - /* Limit( lt, MAXOUT, MINOUT ); */ - /* Limit( rt, MAXOUT, MINOUT ); */ - - #ifdef SAVE_SAMPLE - SAVE_ALL_CHANNELS - #endif - - /* buffering */ - if (F2612->WaveOutMode & 0x01) - F2612->WaveL = lt; - if (F2612->WaveOutMode & 0x02) - F2612->WaveR = rt; - if (F2612->WaveOutMode ^ 0x03) - F2612->WaveOutMode ^= 0x03; - - buffer[0] = (FMSAMPLE)(F2612->WaveL / 2); - buffer[1] = (FMSAMPLE)(F2612->WaveR / 2); - - /* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */ - /* only if Timer A does not overflow again (i.e CSM Key ON not set again) */ - OPN->SL3.key_csm <<= 1; - - /* timer A control */ - /* INTERNAL_TIMER_A( &OPN->ST , cch[2] ) */ - { - if( OPN->ST.TAC && (OPN->ST.timer_handler==0) ) - if( (OPN->ST.TAC -= (int)(OPN->ST.freqbase*4096)) <= 0 ) - { - TimerAOver( &OPN->ST ); - /* CSM mode total level latch and auto key on */ - if( OPN->ST.mode & 0x80 ) - CSMKeyControll( OPN, &cch[2] ); - } - } - - /* CSM Mode Key ON still disabled */ - if (OPN->SL3.key_csm & 2) - { - /* CSM Mode Key OFF (verified by Nemesis on real hardware) */ - FM_KEYOFF_CSM(&cch[2],SLOT1); - FM_KEYOFF_CSM(&cch[2],SLOT2); - FM_KEYOFF_CSM(&cch[2],SLOT3); - FM_KEYOFF_CSM(&cch[2],SLOT4); - OPN->SL3.key_csm = 0; - } -} - -#if 0 -void ym2612_post_generate(void *chip, int length) -{ - YM2612 *F2612 = (YM2612 *)chip; - /* timer B control */ - INTERNAL_TIMER_B(&F2612->OPN.ST, length); -} -#endif - -#ifdef __STATE_H__ -void ym2612_postload(void *chip) -{ - if (chip) - { - YM2612 *F2612 = (YM2612 *)chip; - int r; - - /* DAC data & port */ - F2612->dacout = ((int)F2612->REGS[0x2a] - 0x80) << 6; /* level unknown */ - F2612->dacen = F2612->REGS[0x2d] & 0x80; - /* OPN registers */ - /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */ - for(r=0x30;r<0x9e;r++) - if((r&3) != 3) - { - OPNWriteReg(&F2612->OPN,r,F2612->REGS[r]); - OPNWriteReg(&F2612->OPN,r|0x100,F2612->REGS[r|0x100]); - } - /* FB / CONNECT , L / R / AMS / PMS */ - for(r=0xb0;r<0xb6;r++) - if((r&3) != 3) - { - OPNWriteReg(&F2612->OPN,r,F2612->REGS[r]); - OPNWriteReg(&F2612->OPN,r|0x100,F2612->REGS[r|0x100]); - } - /* channels */ - /*FM_channel_postload(F2612->CH,6);*/ - } -} - -static void YM2612_save_state(YM2612 *F2612, running_device *device) -{ - state_save_register_device_item_array(device, 0, F2612->REGS); - FMsave_state_st(device,&F2612->OPN.ST); - FMsave_state_channel(device,F2612->CH,6); - /* 3slots */ - state_save_register_device_item_array(device, 0, F2612->OPN.SL3.fc); - state_save_register_device_item(device, 0, F2612->OPN.SL3.fn_h); - state_save_register_device_item_array(device, 0, F2612->OPN.SL3.kcode); - /* address register1 */ - state_save_register_device_item(device, 0, F2612->addr_A1); -} -#endif /* _STATE_H */ - -/* initialize YM2612 emulator(s) */ -static void * ym2612_init(void *param, int clock, int rate, - FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler) -{ - YM2612 *F2612; - - if (clock <= 0 || rate <= 0) - return NULL; /* Forbid zero clock and sample rate */ - - /* allocate extend state space */ - /* F2612 = auto_alloc_clear(device->machine, YM2612); */ - F2612 = (YM2612 *)malloc(sizeof(YM2612)); - if (F2612 == NULL) - return NULL; - memset(F2612, 0x00, sizeof(YM2612)); - /* allocate total level table (128kb space) */ - init_tables(); - - F2612->OPN.ST.param = param; - F2612->OPN.type = TYPE_YM2612; - F2612->OPN.P_CH = F2612->CH; - /* F2612->OPN.ST.device = device; */ - F2612->OPN.ST.clock = clock; -#if RSM_ENABLE - F2612->OPN.ST.rate = 53267; - F2612->OPN.ST.rateratio = (INT32)(UINT32)((((UINT64)144 * rate) << RSM_FRAC) / clock); - F2612->OPN.ST.framecnt = 1 << RSM_FRAC; - memset(&(F2612->OPN.ST.cur_sample), 0x00, sizeof(FMSAMPLE) * 2); - memset(&(F2612->OPN.ST.prev_sample), 0x00, sizeof(FMSAMPLE) * 2); -#else - F2612->OPN.ST.rate = rate; -#endif - /* F2612->OPN.ST.irq = 0; */ - /* F2612->OPN.ST.status = 0; */ - /* Extend handler */ - F2612->OPN.ST.timer_handler = timer_handler; - F2612->OPN.ST.IRQ_Handler = IRQHandler; - - if (PseudoSt) - F2612->WaveOutMode = 0x01; - else - F2612->WaveOutMode = 0x03; - /*hFile = fopen("YM2612.log", "wt"); - fprintf(hFile, "Clock: %d, Sample Rate: %d\n", clock, rate); - fprintf(hFile, "Sample\tCh 0\tCh 1\tCh 2\tCh 3\tCh 4\tCh 5\n"); - FileSample = 0;*/ - -#ifdef __STATE_H__ - YM2612_save_state(F2612, device); -#endif - return F2612; -} - -/* shut down emulator */ -static void ym2612_shutdown(void *chip) -{ - YM2612 *F2612 = (YM2612 *)chip; - /* fclose(hFile); */ - - FMCloseTable(); - /* auto_free(F2612->OPN.ST.device->machine, F2612); */ - free(F2612); -} - -/* reset one of chip */ -static void ym2612_reset_chip(void *chip) -{ - int i; - YM2612 *F2612 = (YM2612 *)chip; - FM_OPN *OPN = &F2612->OPN; - - OPNSetPres( OPN, 6*24, 6*24, 0); - /* status clear */ - FM_IRQMASK_SET(&OPN->ST,0x03); - FM_BUSY_CLEAR(&OPN->ST); - /* OPNWriteMode(OPN,0x27,0x30); */ /* mode 0 , timer reset */ - -#if RSM_ENABLE - /* Resampler's state */ - F2612->OPN.ST.framecnt = 1 << RSM_FRAC; - memset(&(F2612->OPN.ST.cur_sample), 0x00, sizeof(FMSAMPLE) * 2); - memset(&(F2612->OPN.ST.prev_sample), 0x00, sizeof(FMSAMPLE) * 2); -#endif - - OPN->eg_timer = 0; - OPN->eg_cnt = 0; - - OPN->lfo_timer = 0; - OPN->lfo_cnt = 0; - OPN->LFO_AM = 126; - OPN->LFO_PM = 0; - - OPN->ST.TAC = 0; - OPN->ST.TBC = 0; - - OPN->SL3.key_csm = 0; - - OPN->ST.status = 0; - OPN->ST.mode = 0; - - memset(F2612->REGS, 0x00, sizeof(UINT8) * 512); - - OPNWriteMode(OPN,0x22,0x00); - - OPNWriteMode(OPN,0x27,0x30); - OPNWriteMode(OPN,0x26,0x00); - OPNWriteMode(OPN,0x25,0x00); - OPNWriteMode(OPN,0x24,0x00); - - reset_channels( &OPN->ST , &F2612->CH[0] , 6 ); - - for(i = 0xb6 ; i >= 0xb4 ; i-- ) - { - OPNWriteReg(OPN,i ,0xc0); - OPNWriteReg(OPN,i|0x100,0xc0); - } - for(i = 0xb2 ; i >= 0x30 ; i-- ) - { - OPNWriteReg(OPN,i ,0); - OPNWriteReg(OPN,i|0x100,0); - } - - /* DAC mode clear */ - F2612->dacen = 0; - F2612->dac_test = 0; - F2612->dacout = 0; - - if (F2612->WaveOutMode == 0x02) - F2612->WaveOutMode >>= 1; -} - -/* YM2612 write */ -/* n = number */ -/* a = address */ -/* v = value */ -static int ym2612_write(void *chip, int a, UINT8 v) -{ - YM2612 *F2612 = (YM2612 *)chip; - int addr; - - v &= 0xff; /* adjust to 8 bit bus */ - - switch( a&3) - { - case 0: /* address port 0 */ - F2612->OPN.ST.address = v; - F2612->addr_A1 = 0; - break; - - case 1: /* data port 0 */ - if (F2612->addr_A1 != 0) - break; /* verified on real YM2608 */ - - addr = F2612->OPN.ST.address; - F2612->REGS[addr] = v; - switch( addr & 0xf0 ) - { - case 0x20: /* 0x20-0x2f Mode */ - switch( addr ) - { - case 0x2a: /* DAC data (YM2612) */ - ym2612_update_one(chip, DUMMYBUF, 0); - F2612->dacout = ((int)v - 0x80) << 6; /* level unknown */ - break; - case 0x2b: /* DAC Sel (YM2612) */ - /* b7 = dac enable */ - F2612->dacen = v & 0x80; - break; - case 0x2C: /* undocumented: DAC Test Reg */ - /* b5 = volume enable */ - F2612->dac_test = v & 0x20; - break; - default: /* OPN section */ - /* ym2612_update_req(F2612->OPN.ST.param); */ - ym2612_update_one(chip, DUMMYBUF, 0); - /* write register */ - OPNWriteMode(&(F2612->OPN),addr,v); - } - break; - default: /* 0x30-0xff OPN section */ - ym2612_update_one(chip, DUMMYBUF, 0); - /* write register */ - OPNWriteReg(&(F2612->OPN),addr,v); - } - break; - - case 2: /* address port 1 */ - F2612->OPN.ST.address = v; - F2612->addr_A1 = 1; - break; - - case 3: /* data port 1 */ - if (F2612->addr_A1 != 1) - break; /* verified on real YM2608 */ - - addr = F2612->OPN.ST.address; - F2612->REGS[addr | 0x100] = v; - ym2612_update_one(chip, DUMMYBUF, 0); - OPNWriteReg(&(F2612->OPN),addr | 0x100,v); - break; - } - return F2612->OPN.ST.irq; -} - -#if 0 -static UINT8 ym2612_read(void *chip,int a) -{ - YM2612 *F2612 = (YM2612 *)chip; - - switch( a&3) - { - case 0: /* status 0 */ - return FM_STATUS_FLAG(&F2612->OPN.ST); - case 1: - case 2: - case 3: - /* LOG(LOG_WAR,("YM2612 #%p:A=%d read unmapped area\n",F2612->OPN.ST.param,a)); */ - return FM_STATUS_FLAG(&F2612->OPN.ST); - } - return 0; -} - -static int ym2612_timer_over(void *chip,int c) -{ - YM2612 *F2612 = (YM2612 *)chip; - - if( c ) - { /* Timer B */ - TimerBOver( &(F2612->OPN.ST) ); - } - else - { /* Timer A */ - ym2612_update_one(chip, DUMMYBUF, 0); - /* timer update */ - TimerAOver( &(F2612->OPN.ST) ); - /* CSM mode key,TL controll */ - if ((F2612->OPN.ST.mode & 0xc0) == 0x80) - { /* CSM mode total level latch and auto key on */ - CSMKeyControll( &F2612->OPN, &(F2612->CH[2]) ); - } - } - return F2612->OPN.ST.irq; -} -#endif - -static void ym2612_set_mutemask(void *chip, UINT32 MuteMask) -{ - YM2612 *F2612 = (YM2612 *)chip; - UINT8 CurChn; - - for (CurChn = 0; CurChn < 6; CurChn ++) - F2612->CH[CurChn].Muted = (MuteMask >> CurChn) & 0x01; - F2612->MuteDAC = (MuteMask >> 6) & 0x01; - - return; -} -#if 0 -static void ym2612_setoptions(UINT8 Flags) -{ - PseudoSt = (Flags >> 2) & 0x01; - - return; -} -#endif - -} // Ym2612_MameImpl - - -Ym2612_MAME_Emu::Ym2612_MAME_Emu() { impl = 0; } - -Ym2612_MAME_Emu::~Ym2612_MAME_Emu() -{ - if ( impl ) Ym2612_MameImpl::ym2612_shutdown( impl ); -} - -const char *Ym2612_MAME_Emu::set_rate(double sample_rate, double clock_rate) -{ - if ( impl ) Ym2612_MameImpl::ym2612_shutdown( impl ); - impl = Ym2612_MameImpl::ym2612_init( NULL, static_cast(clock_rate), static_cast(sample_rate), NULL, NULL ); - if ( !impl ) - return "Out of memory"; - return 0; -} - -void Ym2612_MAME_Emu::reset() -{ - if ( impl ) Ym2612_MameImpl::ym2612_reset_chip( impl ); -} - -void Ym2612_MAME_Emu::mute_voices(int mask) -{ - if ( impl ) Ym2612_MameImpl::ym2612_set_mutemask( impl, mask ); -} - -void Ym2612_MAME_Emu::write0(int addr, int data) -{ - if ( !impl ) return; - Ym2612_MameImpl::ym2612_write( impl, 0, static_cast(addr) ); - Ym2612_MameImpl::ym2612_write( impl, 1, static_cast(data) ); -} - -void Ym2612_MAME_Emu::write1(int addr, int data) -{ - if ( !impl ) return; - Ym2612_MameImpl::ym2612_write( impl, 0 + 2, static_cast(addr) ); - Ym2612_MameImpl::ym2612_write( impl, 1 + 2, static_cast(data) ); -} - -void Ym2612_MAME_Emu::run(int pair_count, Ym2612_MAME_Emu::sample_t *out) -{ - if ( impl ) Ym2612_MameImpl::ym2612_generate( impl, out, pair_count, 0); -} diff --git a/libraries/game-music-emu/gme/Ym2612_MAME.h b/libraries/game-music-emu/gme/Ym2612_MAME.h deleted file mode 100644 index 03831065a..000000000 --- a/libraries/game-music-emu/gme/Ym2612_MAME.h +++ /dev/null @@ -1,38 +0,0 @@ -// YM2612 FM sound chip emulator interface - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef YM2612_EMU_H -#define YM2612_EMU_H - -typedef void Ym2612_MAME_Impl; - -class Ym2612_MAME_Emu { - Ym2612_MAME_Impl* impl; -public: - Ym2612_MAME_Emu(); - ~Ym2612_MAME_Emu(); - - // Set output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - const char* set_rate( double sample_rate, double clock_rate ); - - // Reset to power-up state - void reset(); - - // Mute voice n if bit n (1 << n) of mask is set - enum { channel_count = 6 }; - void mute_voices( int mask ); - - // Write addr to register 0 then data to register 1 - void write0( int addr, int data ); - - // Write addr to register 2 then data to register 3 - void write1( int addr, int data ); - - // Run and add pair_count samples into current output buffer contents - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif diff --git a/libraries/game-music-emu/gme/Ym2612_Nuked.cpp b/libraries/game-music-emu/gme/Ym2612_Nuked.cpp deleted file mode 100644 index fc49ac690..000000000 --- a/libraries/game-music-emu/gme/Ym2612_Nuked.cpp +++ /dev/null @@ -1,1872 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -// Based on Nuked OPN2 ym3438.c and ym3438.h - -#include "Ym2612_Nuked.h" - -/* - * Copyright (C) 2017 Alexey Khokholov (Nuke.YKT) - * - * This library 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 library 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 library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * - * Nuked OPN2(Yamaha YM3438) emulator. - * Thanks: - * Silicon Pr0n: - * Yamaha YM3438 decap and die shot(digshadow). - * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - * OPL2 ROMs. - * - * version: 1.0.7 - */ - - -#include -#include - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint64_t Bit64u; -typedef int64_t Bit64s; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; - -namespace Ym2612_NukedImpl -{ - -/*EXTRA*/ -#define RSM_FRAC 10 -#define OPN_WRITEBUF_SIZE 2048 -#define OPN_WRITEBUF_DELAY 15 - -enum { - ym3438_type_discrete = 0, /* Discrete YM3438 (Teradrive) */ - ym3438_type_asic = 1, /* ASIC YM3438 (MD1 VA7, MD2, MD3, etc) */ - ym3438_type_ym2612 = 2 /* YM2612 (MD1, MD2 VA2) */ -}; - -/*EXTRA*/ -typedef struct _opn2_writebuf { - Bit64u time; - Bit8u port; - Bit8u data; - Bit8u reserved[6]; -} opn2_writebuf; - -typedef struct -{ - Bit32u cycles; - Bit32u channel; - Bit16s mol, mor; - /* IO */ - Bit16u write_data; - Bit8u write_a; - Bit8u write_d; - Bit8u write_a_en; - Bit8u write_d_en; - Bit8u write_busy; - Bit8u write_busy_cnt; - Bit8u write_fm_address; - Bit8u write_fm_data; - Bit8u write_fm_mode_a; - Bit16u address; - Bit8u data; - Bit8u pin_test_in; - Bit8u pin_irq; - Bit8u busy; - /* LFO */ - Bit8u lfo_en; - Bit8u lfo_freq; - Bit8u lfo_pm; - Bit8u lfo_am; - Bit8u lfo_cnt; - Bit8u lfo_inc; - Bit8u lfo_quotient; - /* Phase generator */ - Bit16u pg_fnum; - Bit8u pg_block; - Bit8u pg_kcode; - Bit32u pg_inc[24]; - Bit32u pg_phase[24]; - Bit8u pg_reset[24]; - Bit32u pg_read; - /* Envelope generator */ - Bit8u eg_cycle; - Bit8u eg_cycle_stop; - Bit8u eg_shift; - Bit8u eg_shift_lock; - Bit8u eg_timer_low_lock; - Bit16u eg_timer; - Bit8u eg_timer_inc; - Bit16u eg_quotient; - Bit8u eg_custom_timer; - Bit8u eg_rate; - Bit8u eg_ksv; - Bit8u eg_inc; - Bit8u eg_ratemax; - Bit8u eg_sl[2]; - Bit8u eg_lfo_am; - Bit8u eg_tl[2]; - Bit8u eg_state[24]; - Bit16u eg_level[24]; - Bit16u eg_out[24]; - Bit8u eg_kon[24]; - Bit8u eg_kon_csm[24]; - Bit8u eg_kon_latch[24]; - Bit8u eg_csm_mode[24]; - Bit8u eg_ssg_enable[24]; - Bit8u eg_ssg_pgrst_latch[24]; - Bit8u eg_ssg_repeat_latch[24]; - Bit8u eg_ssg_hold_up_latch[24]; - Bit8u eg_ssg_dir[24]; - Bit8u eg_ssg_inv[24]; - Bit32u eg_read[2]; - Bit8u eg_read_inc; - /* FM */ - Bit16s fm_op1[6][2]; - Bit16s fm_op2[6]; - Bit16s fm_out[24]; - Bit16u fm_mod[24]; - /* Channel */ - Bit16s ch_acc[6]; - Bit16s ch_out[6]; - Bit16s ch_lock; - Bit8u ch_lock_l; - Bit8u ch_lock_r; - Bit16s ch_read; - /* Timer */ - Bit16u timer_a_cnt; - Bit16u timer_a_reg; - Bit8u timer_a_load_lock; - Bit8u timer_a_load; - Bit8u timer_a_enable; - Bit8u timer_a_reset; - Bit8u timer_a_load_latch; - Bit8u timer_a_overflow_flag; - Bit8u timer_a_overflow; - - Bit16u timer_b_cnt; - Bit8u timer_b_subcnt; - Bit16u timer_b_reg; - Bit8u timer_b_load_lock; - Bit8u timer_b_load; - Bit8u timer_b_enable; - Bit8u timer_b_reset; - Bit8u timer_b_load_latch; - Bit8u timer_b_overflow_flag; - Bit8u timer_b_overflow; - - /* Register set */ - Bit8u mode_test_21[8]; - Bit8u mode_test_2c[8]; - Bit8u mode_ch3; - Bit8u mode_kon_channel; - Bit8u mode_kon_operator[4]; - Bit8u mode_kon[24]; - Bit8u mode_csm; - Bit8u mode_kon_csm; - Bit8u dacen; - Bit16s dacdata; - - Bit8u ks[24]; - Bit8u ar[24]; - Bit8u sr[24]; - Bit8u dt[24]; - Bit8u multi[24]; - Bit8u sl[24]; - Bit8u rr[24]; - Bit8u dr[24]; - Bit8u am[24]; - Bit8u tl[24]; - Bit8u ssg_eg[24]; - - Bit16u fnum[6]; - Bit8u block[6]; - Bit8u kcode[6]; - Bit16u fnum_3ch[6]; - Bit8u block_3ch[6]; - Bit8u kcode_3ch[6]; - Bit8u reg_a4; - Bit8u reg_ac; - Bit8u connect[6]; - Bit8u fb[6]; - Bit8u pan_l[6], pan_r[6]; - Bit8u ams[6]; - Bit8u pms[6]; - - /*EXTRA*/ - Bit32u mute[7]; - Bit32s rateratio; - Bit32s samplecnt; - Bit32s oldsamples[2]; - Bit32s samples[2]; - - Bit64u writebuf_samplecnt; - Bit32u writebuf_cur; - Bit32u writebuf_last; - Bit64u writebuf_lasttime; - opn2_writebuf writebuf[OPN_WRITEBUF_SIZE]; -} ym3438_t; - -/* EXTRA, original was "void OPN2_Reset(ym3438_t *chip)" */ -void OPN2_Reset(ym3438_t *chip, Bit32u rate, Bit32u clock); -void OPN2_SetChipType(Bit32u type); -void OPN2_Clock(ym3438_t *chip, Bit16s *buffer); -void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data); -void OPN2_SetTestPin(ym3438_t *chip, Bit32u value); -Bit32u OPN2_ReadTestPin(ym3438_t *chip); -Bit32u OPN2_ReadIRQPin(ym3438_t *chip); -Bit8u OPN2_Read(ym3438_t *chip, Bit32u port); - -/*EXTRA*/ -void OPN2_WriteBuffered(ym3438_t *chip, Bit32u port, Bit8u data); -void OPN2_Generate(ym3438_t *chip, Bit16s *buf); -void OPN2_GenerateResampled(ym3438_t *chip, Bit16s *buf); -void OPN2_GenerateStream(ym3438_t *chip, Bit16s *output, Bit32u numsamples); -void OPN2_GenerateStreamMix(ym3438_t *chip, Bit16s *output, Bit32u numsamples); -void OPN2_SetOptions(Bit8u flags); -void OPN2_SetMute(ym3438_t *chip, Bit32u mute); - - - - - -enum { - eg_num_attack = 0, - eg_num_decay = 1, - eg_num_sustain = 2, - eg_num_release = 3 -}; - -/* logsin table */ -static const Bit16u logsinrom[256] = { - 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, - 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, - 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, - 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, - 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, - 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, - 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, - 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, - 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, - 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, - 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, - 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, - 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, - 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, - 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, - 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, - 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, - 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, - 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, - 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, - 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, - 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, - 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, - 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, - 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, - 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, - 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, - 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, - 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, - 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, - 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 -}; - -/* exp table */ -static const Bit16u exprom[256] = { - 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, - 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, - 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, - 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, - 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, - 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, - 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, - 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, - 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, - 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, - 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, - 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, - 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, - 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, - 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, - 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, - 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, - 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, - 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, - 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, - 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, - 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, - 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, - 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, - 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, - 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, - 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, - 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, - 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, - 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, - 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, - 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa -}; - -/* Note table */ -static const Bit32u fn_note[16] = { - 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3 -}; - -/* Envelope generator */ -static const Bit32u eg_stephi[4][4] = { - { 0, 0, 0, 0 }, - { 1, 0, 0, 0 }, - { 1, 0, 1, 0 }, - { 1, 1, 1, 0 } -}; - -static const Bit8u eg_am_shift[4] = { - 7, 3, 1, 0 -}; - -/* Phase generator */ -static const Bit32u pg_detune[8] = { 16, 17, 19, 20, 22, 24, 27, 29 }; - -static const Bit32u pg_lfo_sh1[8][8] = { - { 7, 7, 7, 7, 7, 7, 7, 7 }, - { 7, 7, 7, 7, 7, 7, 7, 7 }, - { 7, 7, 7, 7, 7, 7, 1, 1 }, - { 7, 7, 7, 7, 1, 1, 1, 1 }, - { 7, 7, 7, 1, 1, 1, 1, 0 }, - { 7, 7, 1, 1, 0, 0, 0, 0 }, - { 7, 7, 1, 1, 0, 0, 0, 0 }, - { 7, 7, 1, 1, 0, 0, 0, 0 } -}; - -static const Bit32u pg_lfo_sh2[8][8] = { - { 7, 7, 7, 7, 7, 7, 7, 7 }, - { 7, 7, 7, 7, 2, 2, 2, 2 }, - { 7, 7, 7, 2, 2, 2, 7, 7 }, - { 7, 7, 2, 2, 7, 7, 2, 2 }, - { 7, 7, 2, 7, 7, 7, 2, 7 }, - { 7, 7, 7, 2, 7, 7, 2, 1 }, - { 7, 7, 7, 2, 7, 7, 2, 1 }, - { 7, 7, 7, 2, 7, 7, 2, 1 } -}; - -/* Address decoder */ -static const Bit32u op_offset[12] = { - 0x000, /* Ch1 OP1/OP2 */ - 0x001, /* Ch2 OP1/OP2 */ - 0x002, /* Ch3 OP1/OP2 */ - 0x100, /* Ch4 OP1/OP2 */ - 0x101, /* Ch5 OP1/OP2 */ - 0x102, /* Ch6 OP1/OP2 */ - 0x004, /* Ch1 OP3/OP4 */ - 0x005, /* Ch2 OP3/OP4 */ - 0x006, /* Ch3 OP3/OP4 */ - 0x104, /* Ch4 OP3/OP4 */ - 0x105, /* Ch5 OP3/OP4 */ - 0x106 /* Ch6 OP3/OP4 */ -}; - -static const Bit32u ch_offset[6] = { - 0x000, /* Ch1 */ - 0x001, /* Ch2 */ - 0x002, /* Ch3 */ - 0x100, /* Ch4 */ - 0x101, /* Ch5 */ - 0x102 /* Ch6 */ -}; - -/* LFO */ -static const Bit32u lfo_cycles[8] = { - 108, 77, 71, 67, 62, 44, 8, 5 -}; - -/* FM algorithm */ -static const Bit32u fm_algorithm[4][6][8] = { - { - { 1, 1, 1, 1, 1, 1, 1, 1 }, /* OP1_0 */ - { 1, 1, 1, 1, 1, 1, 1, 1 }, /* OP1_1 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP2 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ - { 0, 0, 0, 0, 0, 0, 0, 1 } /* Out */ - }, - { - { 0, 1, 0, 0, 0, 1, 0, 0 }, /* OP1_0 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1 */ - { 1, 1, 1, 0, 0, 0, 0, 0 }, /* OP2 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ - { 0, 0, 0, 0, 0, 1, 1, 1 } /* Out */ - }, - { - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_0 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP2 */ - { 1, 0, 0, 1, 1, 1, 1, 0 }, /* Last operator */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ - { 0, 0, 0, 0, 1, 1, 1, 1 } /* Out */ - }, - { - { 0, 0, 1, 0, 0, 1, 0, 0 }, /* OP1_0 */ - { 0, 0, 0, 0, 0, 0, 0, 0 }, /* OP1_1 */ - { 0, 0, 0, 1, 0, 0, 0, 0 }, /* OP2 */ - { 1, 1, 0, 1, 1, 0, 0, 0 }, /* Last operator */ - { 0, 0, 1, 0, 0, 0, 0, 0 }, /* Last operator */ - { 1, 1, 1, 1, 1, 1, 1, 1 } /* Out */ - } -}; - -static Bit32u chip_type = ym3438_type_discrete; - -void OPN2_DoIO(ym3438_t *chip) -{ - /* Write signal check */ - chip->write_a_en = (chip->write_a & 0x03) == 0x01; - chip->write_d_en = (chip->write_d & 0x03) == 0x01; - chip->write_a <<= 1; - chip->write_d <<= 1; - /* Busy counter */ - chip->busy = chip->write_busy; - chip->write_busy_cnt += chip->write_busy; - chip->write_busy = (chip->write_busy && !(chip->write_busy_cnt >> 5)) || chip->write_d_en; - chip->write_busy_cnt &= 0x1f; -} - -void OPN2_DoRegWrite(ym3438_t *chip) -{ - Bit32u i; - Bit32u slot = chip->cycles % 12; - Bit32u address; - Bit32u channel = chip->channel; - /* Update registers */ - if (chip->write_fm_data) - { - /* Slot */ - if (op_offset[slot] == (chip->address & 0x107)) - { - if (chip->address & 0x08) - { - /* OP2, OP4 */ - slot += 12; - } - address = chip->address & 0xf0; - switch (address) - { - case 0x30: /* DT, MULTI */ - chip->multi[slot] = chip->data & 0x0f; - if (!chip->multi[slot]) - { - chip->multi[slot] = 1; - } - else - { - chip->multi[slot] <<= 1; - } - chip->dt[slot] = (chip->data >> 4) & 0x07; - break; - case 0x40: /* TL */ - chip->tl[slot] = chip->data & 0x7f; - break; - case 0x50: /* KS, AR */ - chip->ar[slot] = chip->data & 0x1f; - chip->ks[slot] = (chip->data >> 6) & 0x03; - break; - case 0x60: /* AM, DR */ - chip->dr[slot] = chip->data & 0x1f; - chip->am[slot] = (chip->data >> 7) & 0x01; - break; - case 0x70: /* SR */ - chip->sr[slot] = chip->data & 0x1f; - break; - case 0x80: /* SL, RR */ - chip->rr[slot] = chip->data & 0x0f; - chip->sl[slot] = (chip->data >> 4) & 0x0f; - chip->sl[slot] |= (chip->sl[slot] + 1) & 0x10; - break; - case 0x90: /* SSG-EG */ - chip->ssg_eg[slot] = chip->data & 0x0f; - break; - default: - break; - } - } - - /* Channel */ - if (ch_offset[channel] == (chip->address & 0x103)) - { - address = chip->address & 0xfc; - switch (address) - { - case 0xa0: - chip->fnum[channel] = (chip->data & 0xff) | ((chip->reg_a4 & 0x07) << 8); - chip->block[channel] = (chip->reg_a4 >> 3) & 0x07; - chip->kcode[channel] = (chip->block[channel] << 2) | fn_note[chip->fnum[channel] >> 7]; - break; - case 0xa4: - chip->reg_a4 = chip->data & 0xff; - break; - case 0xa8: - chip->fnum_3ch[channel] = (chip->data & 0xff) | ((chip->reg_ac & 0x07) << 8); - chip->block_3ch[channel] = (chip->reg_ac >> 3) & 0x07; - chip->kcode_3ch[channel] = (chip->block_3ch[channel] << 2) | fn_note[chip->fnum_3ch[channel] >> 7]; - break; - case 0xac: - chip->reg_ac = chip->data & 0xff; - break; - case 0xb0: - chip->connect[channel] = chip->data & 0x07; - chip->fb[channel] = (chip->data >> 3) & 0x07; - break; - case 0xb4: - chip->pms[channel] = chip->data & 0x07; - chip->ams[channel] = (chip->data >> 4) & 0x03; - chip->pan_l[channel] = (chip->data >> 7) & 0x01; - chip->pan_r[channel] = (chip->data >> 6) & 0x01; - break; - default: - break; - } - } - } - - if (chip->write_a_en || chip->write_d_en) - { - /* Data */ - if (chip->write_a_en) - { - chip->write_fm_data = 0; - } - - if (chip->write_fm_address && chip->write_d_en) - { - chip->write_fm_data = 1; - } - - /* Address */ - if (chip->write_a_en) - { - if ((chip->write_data & 0xf0) != 0x00) - { - /* FM Write */ - chip->address = chip->write_data; - chip->write_fm_address = 1; - } - else - { - /* SSG write */ - chip->write_fm_address = 0; - } - } - - /* FM Mode */ - /* Data */ - if (chip->write_d_en && (chip->write_data & 0x100) == 0) - { - switch (chip->address) - { - case 0x21: /* LSI test 1 */ - for (i = 0; i < 8; i++) - { - chip->mode_test_21[i] = (chip->write_data >> i) & 0x01; - } - break; - case 0x22: /* LFO control */ - if ((chip->write_data >> 3) & 0x01) - { - chip->lfo_en = 0x7f; - } - else - { - chip->lfo_en = 0; - } - chip->lfo_freq = chip->write_data & 0x07; - break; - case 0x24: /* Timer A */ - chip->timer_a_reg &= 0x03; - chip->timer_a_reg |= (chip->write_data & 0xff) << 2; - break; - case 0x25: - chip->timer_a_reg &= 0x3fc; - chip->timer_a_reg |= chip->write_data & 0x03; - break; - case 0x26: /* Timer B */ - chip->timer_b_reg = chip->write_data & 0xff; - break; - case 0x27: /* CSM, Timer control */ - chip->mode_ch3 = (chip->write_data & 0xc0) >> 6; - chip->mode_csm = chip->mode_ch3 == 2; - chip->timer_a_load = chip->write_data & 0x01; - chip->timer_a_enable = (chip->write_data >> 2) & 0x01; - chip->timer_a_reset = (chip->write_data >> 4) & 0x01; - chip->timer_b_load = (chip->write_data >> 1) & 0x01; - chip->timer_b_enable = (chip->write_data >> 3) & 0x01; - chip->timer_b_reset = (chip->write_data >> 5) & 0x01; - break; - case 0x28: /* Key on/off */ - for (i = 0; i < 4; i++) - { - chip->mode_kon_operator[i] = (chip->write_data >> (4 + i)) & 0x01; - } - if ((chip->write_data & 0x03) == 0x03) - { - /* Invalid address */ - chip->mode_kon_channel = 0xff; - } - else - { - chip->mode_kon_channel = (chip->write_data & 0x03) + ((chip->write_data >> 2) & 1) * 3; - } - break; - case 0x2a: /* DAC data */ - chip->dacdata &= 0x01; - chip->dacdata |= (chip->write_data ^ 0x80) << 1; - break; - case 0x2b: /* DAC enable */ - chip->dacen = chip->write_data >> 7; - break; - case 0x2c: /* LSI test 2 */ - for (i = 0; i < 8; i++) - { - chip->mode_test_2c[i] = (chip->write_data >> i) & 0x01; - } - chip->dacdata &= 0x1fe; - chip->dacdata |= chip->mode_test_2c[3]; - chip->eg_custom_timer = !chip->mode_test_2c[7] && chip->mode_test_2c[6]; - break; - default: - break; - } - } - - /* Address */ - if (chip->write_a_en) - { - chip->write_fm_mode_a = chip->write_data & 0xff; - } - } - - if (chip->write_fm_data) - { - chip->data = chip->write_data & 0xff; - } -} - -void OPN2_PhaseCalcIncrement(ym3438_t *chip) -{ - Bit32u chan = chip->channel; - Bit32u slot = chip->cycles; - Bit32u fnum = chip->pg_fnum; - Bit32u fnum_h = fnum >> 4; - Bit32u fm; - Bit32u basefreq; - Bit8u lfo = chip->lfo_pm; - Bit8u lfo_l = lfo & 0x0f; - Bit8u pms = chip->pms[chan]; - Bit8u dt = chip->dt[slot]; - Bit8u dt_l = dt & 0x03; - Bit8u detune = 0; - Bit8u block, note; - Bit8u sum, sum_h, sum_l; - Bit8u kcode = chip->pg_kcode; - - fnum <<= 1; - /* Apply LFO */ - if (lfo_l & 0x08) - { - lfo_l ^= 0x0f; - } - fm = (fnum_h >> pg_lfo_sh1[pms][lfo_l]) + (fnum_h >> pg_lfo_sh2[pms][lfo_l]); - if (pms > 5) - { - fm <<= pms - 5; - } - fm >>= 2; - if (lfo & 0x10) - { - fnum -= fm; - } - else - { - fnum += fm; - } - fnum &= 0xfff; - - basefreq = (fnum << chip->pg_block) >> 2; - - /* Apply detune */ - if (dt_l) - { - if (kcode > 0x1c) - { - kcode = 0x1c; - } - block = kcode >> 2; - note = kcode & 0x03; - sum = block + 9 + ((dt_l == 3) | (dt_l & 0x02)); - sum_h = sum >> 1; - sum_l = sum & 0x01; - detune = pg_detune[(sum_l << 2) | note] >> (9 - sum_h); - } - if (dt & 0x04) - { - basefreq -= detune; - } - else - { - basefreq += detune; - } - basefreq &= 0x1ffff; - chip->pg_inc[slot] = (basefreq * chip->multi[slot]) >> 1; - chip->pg_inc[slot] &= 0xfffff; -} - -void OPN2_PhaseGenerate(ym3438_t *chip) -{ - Bit32u slot; - /* Mask increment */ - slot = (chip->cycles + 20) % 24; - if (chip->pg_reset[slot]) - { - chip->pg_inc[slot] = 0; - } - /* Phase step */ - slot = (chip->cycles + 19) % 24; - chip->pg_phase[slot] += chip->pg_inc[slot]; - chip->pg_phase[slot] &= 0xfffff; - if (chip->pg_reset[slot] || chip->mode_test_21[3]) - { - chip->pg_phase[slot] = 0; - } -} - -void OPN2_EnvelopeSSGEG(ym3438_t *chip) -{ - Bit32u slot = chip->cycles; - Bit8u direction = 0; - chip->eg_ssg_pgrst_latch[slot] = 0; - chip->eg_ssg_repeat_latch[slot] = 0; - chip->eg_ssg_hold_up_latch[slot] = 0; - chip->eg_ssg_inv[slot] = 0; - if (chip->ssg_eg[slot] & 0x08) - { - direction = chip->eg_ssg_dir[slot]; - if (chip->eg_level[slot] & 0x200) - { - /* Reset */ - if ((chip->ssg_eg[slot] & 0x03) == 0x00) - { - chip->eg_ssg_pgrst_latch[slot] = 1; - } - /* Repeat */ - if ((chip->ssg_eg[slot] & 0x01) == 0x00) - { - chip->eg_ssg_repeat_latch[slot] = 1; - } - /* Inverse */ - if ((chip->ssg_eg[slot] & 0x03) == 0x02) - { - direction ^= 1; - } - if ((chip->ssg_eg[slot] & 0x03) == 0x03) - { - direction = 1; - } - } - /* Hold up */ - if (chip->eg_kon_latch[slot] - && ((chip->ssg_eg[slot] & 0x07) == 0x05 || (chip->ssg_eg[slot] & 0x07) == 0x03)) - { - chip->eg_ssg_hold_up_latch[slot] = 1; - } - direction &= chip->eg_kon[slot]; - chip->eg_ssg_inv[slot] = (chip->eg_ssg_dir[slot] ^ ((chip->ssg_eg[slot] >> 2) & 0x01)) - & chip->eg_kon[slot]; - } - chip->eg_ssg_dir[slot] = direction; - chip->eg_ssg_enable[slot] = (chip->ssg_eg[slot] >> 3) & 0x01; -} - -void OPN2_EnvelopeADSR(ym3438_t *chip) -{ - Bit32u slot = (chip->cycles + 22) % 24; - - Bit8u nkon = chip->eg_kon_latch[slot]; - Bit8u okon = chip->eg_kon[slot]; - Bit8u kon_event; - Bit8u koff_event; - Bit8u eg_off; - Bit16s level; - Bit16s nextlevel = 0; - Bit16s ssg_level; - Bit8u nextstate = chip->eg_state[slot]; - Bit16s inc = 0; - chip->eg_read[0] = chip->eg_read_inc; - chip->eg_read_inc = chip->eg_inc > 0; - - /* Reset phase generator */ - chip->pg_reset[slot] = (nkon && !okon) || chip->eg_ssg_pgrst_latch[slot]; - - /* KeyOn/Off */ - kon_event = (nkon && !okon) || (okon && chip->eg_ssg_repeat_latch[slot]); - koff_event = okon && !nkon; - - ssg_level = level = (Bit16s)chip->eg_level[slot]; - - if (chip->eg_ssg_inv[slot]) - { - /* Inverse */ - ssg_level = 512 - level; - ssg_level &= 0x3ff; - } - if (koff_event) - { - level = ssg_level; - } - if (chip->eg_ssg_enable[slot]) - { - eg_off = level >> 9; - } - else - { - eg_off = (level & 0x3f0) == 0x3f0; - } - nextlevel = level; - if (kon_event) - { - nextstate = eg_num_attack; - /* Instant attack */ - if (chip->eg_ratemax) - { - nextlevel = 0; - } - else if (chip->eg_state[slot] == eg_num_attack && level != 0 && chip->eg_inc && nkon) - { - inc = (~level << chip->eg_inc) >> 5; - } - } - else - { - switch (chip->eg_state[slot]) - { - case eg_num_attack: - if (level == 0) - { - nextstate = eg_num_decay; - } - else if(chip->eg_inc && !chip->eg_ratemax && nkon) - { - inc = (~level << chip->eg_inc) >> 5; - } - break; - case eg_num_decay: - if ((level >> 5) == chip->eg_sl[1]) - { - nextstate = eg_num_sustain; - } - else if (!eg_off && chip->eg_inc) - { - inc = 1 << (chip->eg_inc - 1); - if (chip->eg_ssg_enable[slot]) - { - inc <<= 2; - } - } - break; - case eg_num_sustain: - case eg_num_release: - if (!eg_off && chip->eg_inc) - { - inc = 1 << (chip->eg_inc - 1); - if (chip->eg_ssg_enable[slot]) - { - inc <<= 2; - } - } - break; - default: - break; - } - if (!nkon) - { - nextstate = eg_num_release; - } - } - if (chip->eg_kon_csm[slot]) - { - nextlevel |= chip->eg_tl[1] << 3; - } - - /* Envelope off */ - if (!kon_event && !chip->eg_ssg_hold_up_latch[slot] && chip->eg_state[slot] != eg_num_attack && eg_off) - { - nextstate = eg_num_release; - nextlevel = 0x3ff; - } - - nextlevel += inc; - - chip->eg_kon[slot] = chip->eg_kon_latch[slot]; - chip->eg_level[slot] = (Bit16u)nextlevel & 0x3ff; - chip->eg_state[slot] = nextstate; -} - -void OPN2_EnvelopePrepare(ym3438_t *chip) -{ - Bit8u rate; - Bit8u sum; - Bit8u inc = 0; - Bit32u slot = chip->cycles; - Bit8u rate_sel; - - /* Prepare increment */ - rate = (chip->eg_rate << 1) + chip->eg_ksv; - - if (rate > 0x3f) - { - rate = 0x3f; - } - - sum = ((rate >> 2) + chip->eg_shift_lock) & 0x0f; - if (chip->eg_rate != 0 && chip->eg_quotient == 2) - { - if (rate < 48) - { - switch (sum) - { - case 12: - inc = 1; - break; - case 13: - inc = (rate >> 1) & 0x01; - break; - case 14: - inc = rate & 0x01; - break; - default: - break; - } - } - else - { - inc = eg_stephi[rate & 0x03][chip->eg_timer_low_lock] + (rate >> 2) - 11; - if (inc > 4) - { - inc = 4; - } - } - } - chip->eg_inc = inc; - chip->eg_ratemax = (rate >> 1) == 0x1f; - - /* Prepare rate & ksv */ - rate_sel = chip->eg_state[slot]; - if ((chip->eg_kon[slot] && chip->eg_ssg_repeat_latch[slot]) - || (!chip->eg_kon[slot] && chip->eg_kon_latch[slot])) - { - rate_sel = eg_num_attack; - } - switch (rate_sel) - { - case eg_num_attack: - chip->eg_rate = chip->ar[slot]; - break; - case eg_num_decay: - chip->eg_rate = chip->dr[slot]; - break; - case eg_num_sustain: - chip->eg_rate = chip->sr[slot]; - break; - case eg_num_release: - chip->eg_rate = (chip->rr[slot] << 1) | 0x01; - break; - default: - break; - } - chip->eg_ksv = chip->pg_kcode >> (chip->ks[slot] ^ 0x03); - if (chip->am[slot]) - { - chip->eg_lfo_am = chip->lfo_am >> eg_am_shift[chip->ams[chip->channel]]; - } - else - { - chip->eg_lfo_am = 0; - } - /* Delay TL & SL value */ - chip->eg_tl[1] = chip->eg_tl[0]; - chip->eg_tl[0] = chip->tl[slot]; - chip->eg_sl[1] = chip->eg_sl[0]; - chip->eg_sl[0] = chip->sl[slot]; -} - -void OPN2_EnvelopeGenerate(ym3438_t *chip) -{ - Bit32u slot = (chip->cycles + 23) % 24; - Bit16u level; - - level = chip->eg_level[slot]; - - if (chip->eg_ssg_inv[slot]) - { - /* Inverse */ - level = 512 - level; - } - if (chip->mode_test_21[5]) - { - level = 0; - } - level &= 0x3ff; - - /* Apply AM LFO */ - level += chip->eg_lfo_am; - - /* Apply TL */ - if (!(chip->mode_csm && chip->channel == 2 + 1)) - { - level += chip->eg_tl[0] << 3; - } - if (level > 0x3ff) - { - level = 0x3ff; - } - chip->eg_out[slot] = level; -} - -void OPN2_UpdateLFO(ym3438_t *chip) -{ - if ((chip->lfo_quotient & lfo_cycles[chip->lfo_freq]) == lfo_cycles[chip->lfo_freq]) - { - chip->lfo_quotient = 0; - chip->lfo_cnt++; - } - else - { - chip->lfo_quotient += chip->lfo_inc; - } - chip->lfo_cnt &= chip->lfo_en; -} - -void OPN2_FMPrepare(ym3438_t *chip) -{ - Bit32u slot = (chip->cycles + 6) % 24; - Bit32u channel = chip->channel; - Bit16s mod, mod1, mod2; - Bit32u op = slot / 6; - Bit8u connect = chip->connect[channel]; - Bit32u prevslot = (chip->cycles + 18) % 24; - - /* Calculate modulation */ - mod1 = mod2 = 0; - - if (fm_algorithm[op][0][connect]) - { - mod2 |= chip->fm_op1[channel][0]; - } - if (fm_algorithm[op][1][connect]) - { - mod1 |= chip->fm_op1[channel][1]; - } - if (fm_algorithm[op][2][connect]) - { - mod1 |= chip->fm_op2[channel]; - } - if (fm_algorithm[op][3][connect]) - { - mod2 |= chip->fm_out[prevslot]; - } - if (fm_algorithm[op][4][connect]) - { - mod1 |= chip->fm_out[prevslot]; - } - mod = mod1 + mod2; - if (op == 0) - { - /* Feedback */ - mod = mod >> (10 - chip->fb[channel]); - if (!chip->fb[channel]) - { - mod = 0; - } - } - else - { - mod >>= 1; - } - chip->fm_mod[slot] = mod; - - slot = (chip->cycles + 18) % 24; - /* OP1 */ - if (slot / 6 == 0) - { - chip->fm_op1[channel][1] = chip->fm_op1[channel][0]; - chip->fm_op1[channel][0] = chip->fm_out[slot]; - } - /* OP2 */ - if (slot / 6 == 2) - { - chip->fm_op2[channel] = chip->fm_out[slot]; - } -} - -void OPN2_ChGenerate(ym3438_t *chip) -{ - Bit32u slot = (chip->cycles + 18) % 24; - Bit32u channel = chip->channel; - Bit32u op = slot / 6; - Bit32u test_dac = chip->mode_test_2c[5]; - Bit16s acc = chip->ch_acc[channel]; - Bit16s add = test_dac; - Bit16s sum = 0; - if (op == 0 && !test_dac) - { - acc = 0; - } - if (fm_algorithm[op][5][chip->connect[channel]] && !test_dac) - { - add += chip->fm_out[slot] >> 5; - } - sum = acc + add; - /* Clamp */ - if (sum > 255) - { - sum = 255; - } - else if(sum < -256) - { - sum = -256; - } - - if (op == 0 || test_dac) - { - chip->ch_out[channel] = chip->ch_acc[channel]; - } - chip->ch_acc[channel] = sum; -} - -void OPN2_ChOutput(ym3438_t *chip) -{ - Bit32u cycles = chip->cycles; - Bit32u slot = chip->cycles; - Bit32u channel = chip->channel; - Bit32u test_dac = chip->mode_test_2c[5]; - Bit16s out; - Bit16s sign; - Bit32u out_en; - chip->ch_read = chip->ch_lock; - if (slot < 12) - { - /* Ch 4,5,6 */ - channel++; - } - if ((cycles & 3) == 0) - { - if (!test_dac) - { - /* Lock value */ - chip->ch_lock = chip->ch_out[channel]; - } - chip->ch_lock_l = chip->pan_l[channel]; - chip->ch_lock_r = chip->pan_r[channel]; - } - /* Ch 6 */ - if (((cycles >> 2) == 1 && chip->dacen) || test_dac) - { - out = (Bit16s)chip->dacdata; - out <<= 7; - out >>= 7; - } - else - { - out = chip->ch_lock; - } - chip->mol = 0; - chip->mor = 0; - - if (chip_type == ym3438_type_ym2612) - { - out_en = ((cycles & 3) == 3) || test_dac; - /* YM2612 DAC emulation(not verified) */ - sign = out >> 8; - if (out >= 0) - { - out++; - sign++; - } - if (chip->ch_lock_l && out_en) - { - chip->mol = out; - } - else - { - chip->mol = sign; - } - if (chip->ch_lock_r && out_en) - { - chip->mor = out; - } - else - { - chip->mor = sign; - } - /* Amplify signal */ - chip->mol *= 3; - chip->mor *= 3; - } - else - { - out_en = ((cycles & 3) != 0) || test_dac; - /* Discrete YM3438 seems has the ladder effect too */ - if (out >= 0 && chip_type == ym3438_type_discrete) - { - out++; - } - if (chip->ch_lock_l && out_en) - { - chip->mol = out; - } - if (chip->ch_lock_r && out_en) - { - chip->mor = out; - } - } -} - -void OPN2_FMGenerate(ym3438_t *chip) -{ - Bit32u slot = (chip->cycles + 19) % 24; - /* Calculate phase */ - Bit16u phase = (chip->fm_mod[slot] + (chip->pg_phase[slot] >> 10)) & 0x3ff; - Bit16u quarter; - Bit16u level; - Bit16s output; - if (phase & 0x100) - { - quarter = (phase ^ 0xff) & 0xff; - } - else - { - quarter = phase & 0xff; - } - level = logsinrom[quarter]; - /* Apply envelope */ - level += chip->eg_out[slot] << 2; - /* Transform */ - if (level > 0x1fff) - { - level = 0x1fff; - } - output = ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 2) >> (level >> 8); - if (phase & 0x200) - { - output = ((~output) ^ (chip->mode_test_21[4] << 13)) + 1; - } - else - { - output = output ^ (chip->mode_test_21[4] << 13); - } - output <<= 2; - output >>= 2; - chip->fm_out[slot] = output; -} - -void OPN2_DoTimerA(ym3438_t *chip) -{ - Bit16u time; - Bit8u load; - load = chip->timer_a_overflow; - if (chip->cycles == 2) - { - /* Lock load value */ - load |= (!chip->timer_a_load_lock && chip->timer_a_load); - chip->timer_a_load_lock = chip->timer_a_load; - if (chip->mode_csm) - { - /* CSM KeyOn */ - chip->mode_kon_csm = load; - } - else - { - chip->mode_kon_csm = 0; - } - } - /* Load counter */ - if (chip->timer_a_load_latch) - { - time = chip->timer_a_reg; - } - else - { - time = chip->timer_a_cnt; - } - chip->timer_a_load_latch = load; - /* Increase counter */ - if ((chip->cycles == 1 && chip->timer_a_load_lock) || chip->mode_test_21[2]) - { - time++; - } - /* Set overflow flag */ - if (chip->timer_a_reset) - { - chip->timer_a_reset = 0; - chip->timer_a_overflow_flag = 0; - } - else - { - chip->timer_a_overflow_flag |= chip->timer_a_overflow & chip->timer_a_enable; - } - chip->timer_a_overflow = (time >> 10); - chip->timer_a_cnt = time & 0x3ff; -} - -void OPN2_DoTimerB(ym3438_t *chip) -{ - Bit16u time; - Bit8u load; - load = chip->timer_b_overflow; - if (chip->cycles == 2) - { - /* Lock load value */ - load |= (!chip->timer_b_load_lock && chip->timer_b_load); - chip->timer_b_load_lock = chip->timer_b_load; - } - /* Load counter */ - if (chip->timer_b_load_latch) - { - time = chip->timer_b_reg; - } - else - { - time = chip->timer_b_cnt; - } - chip->timer_b_load_latch = load; - /* Increase counter */ - if (chip->cycles == 1) - { - chip->timer_b_subcnt++; - } - if ((chip->timer_b_subcnt == 0x10 && chip->timer_b_load_lock) || chip->mode_test_21[2]) - { - time++; - } - chip->timer_b_subcnt &= 0x0f; - /* Set overflow flag */ - if (chip->timer_b_reset) - { - chip->timer_b_reset = 0; - chip->timer_b_overflow_flag = 0; - } - else - { - chip->timer_b_overflow_flag |= chip->timer_b_overflow & chip->timer_b_enable; - } - chip->timer_b_overflow = (time >> 8); - chip->timer_b_cnt = time & 0xff; -} - -void OPN2_KeyOn(ym3438_t*chip) -{ - Bit32u slot = chip->cycles; - Bit32u chan = chip->channel; - /* Key On */ - chip->eg_kon_latch[slot] = chip->mode_kon[slot]; - chip->eg_kon_csm[slot] = 0; - if (chip->channel == 2 && chip->mode_kon_csm) - { - /* CSM Key On */ - chip->eg_kon_latch[slot] = 1; - chip->eg_kon_csm[slot] = 1; - } - if (chip->cycles == chip->mode_kon_channel) - { - /* OP1 */ - chip->mode_kon[chan] = chip->mode_kon_operator[0]; - /* OP2 */ - chip->mode_kon[chan + 12] = chip->mode_kon_operator[1]; - /* OP3 */ - chip->mode_kon[chan + 6] = chip->mode_kon_operator[2]; - /* OP4 */ - chip->mode_kon[chan + 18] = chip->mode_kon_operator[3]; - } -} - -void OPN2_Reset(ym3438_t *chip, Bit32u rate, Bit32u clock) -{ - Bit32u i, rateratio; - rateratio = (Bit32u)chip->rateratio; - memset(chip, 0, sizeof(ym3438_t)); - for (i = 0; i < 24; i++) - { - chip->eg_out[i] = 0x3ff; - chip->eg_level[i] = 0x3ff; - chip->eg_state[i] = eg_num_release; - chip->multi[i] = 1; - } - for (i = 0; i < 6; i++) - { - chip->pan_l[i] = 1; - chip->pan_r[i] = 1; - } - - if (rate != 0) - { - chip->rateratio = (Bit32s)(Bit32u)((((Bit64u)144 * rate) << RSM_FRAC) / clock); - } - else - { - chip->rateratio = (Bit32s)rateratio; - } -} - -void OPN2_SetChipType(Bit32u type) -{ - chip_type = type; -} - -void OPN2_Clock(ym3438_t *chip, Bit16s *buffer) -{ - Bit32u slot = chip->cycles; - chip->lfo_inc = chip->mode_test_21[1]; - chip->pg_read >>= 1; - chip->eg_read[1] >>= 1; - chip->eg_cycle++; - /* Lock envelope generator timer value */ - if (chip->cycles == 1 && chip->eg_quotient == 2) - { - if (chip->eg_cycle_stop) - { - chip->eg_shift_lock = 0; - } - else - { - chip->eg_shift_lock = chip->eg_shift + 1; - } - chip->eg_timer_low_lock = chip->eg_timer & 0x03; - } - /* Cycle specific functions */ - switch (chip->cycles) - { - case 0: - chip->lfo_pm = chip->lfo_cnt >> 2; - if (chip->lfo_cnt & 0x40) - { - chip->lfo_am = chip->lfo_cnt & 0x3f; - } - else - { - chip->lfo_am = chip->lfo_cnt ^ 0x3f; - } - chip->lfo_am <<= 1; - break; - case 1: - chip->eg_quotient++; - chip->eg_quotient %= 3; - chip->eg_cycle = 0; - chip->eg_cycle_stop = 1; - chip->eg_shift = 0; - chip->eg_timer_inc |= chip->eg_quotient >> 1; - chip->eg_timer = chip->eg_timer + chip->eg_timer_inc; - chip->eg_timer_inc = chip->eg_timer >> 12; - chip->eg_timer &= 0xfff; - break; - case 2: - chip->pg_read = chip->pg_phase[21] & 0x3ff; - chip->eg_read[1] = chip->eg_out[0]; - break; - case 13: - chip->eg_cycle = 0; - chip->eg_cycle_stop = 1; - chip->eg_shift = 0; - chip->eg_timer = chip->eg_timer + chip->eg_timer_inc; - chip->eg_timer_inc = chip->eg_timer >> 12; - chip->eg_timer &= 0xfff; - break; - case 23: - chip->lfo_inc |= 1; - break; - } - chip->eg_timer &= ~(chip->mode_test_21[5] << chip->eg_cycle); - if (((chip->eg_timer >> chip->eg_cycle) | (chip->pin_test_in & chip->eg_custom_timer)) & chip->eg_cycle_stop) - { - chip->eg_shift = chip->eg_cycle; - chip->eg_cycle_stop = 0; - } - - OPN2_DoIO(chip); - - OPN2_DoTimerA(chip); - OPN2_DoTimerB(chip); - OPN2_KeyOn(chip); - - OPN2_ChOutput(chip); - OPN2_ChGenerate(chip); - - OPN2_FMPrepare(chip); - OPN2_FMGenerate(chip); - - OPN2_PhaseGenerate(chip); - OPN2_PhaseCalcIncrement(chip); - - OPN2_EnvelopeADSR(chip); - OPN2_EnvelopeGenerate(chip); - OPN2_EnvelopeSSGEG(chip); - OPN2_EnvelopePrepare(chip); - - /* Prepare fnum & block */ - if (chip->mode_ch3) - { - /* Channel 3 special mode */ - switch (slot) - { - case 1: /* OP1 */ - chip->pg_fnum = chip->fnum_3ch[1]; - chip->pg_block = chip->block_3ch[1]; - chip->pg_kcode = chip->kcode_3ch[1]; - break; - case 7: /* OP3 */ - chip->pg_fnum = chip->fnum_3ch[0]; - chip->pg_block = chip->block_3ch[0]; - chip->pg_kcode = chip->kcode_3ch[0]; - break; - case 13: /* OP2 */ - chip->pg_fnum = chip->fnum_3ch[2]; - chip->pg_block = chip->block_3ch[2]; - chip->pg_kcode = chip->kcode_3ch[2]; - break; - case 19: /* OP4 */ - default: - chip->pg_fnum = chip->fnum[(chip->channel + 1) % 6]; - chip->pg_block = chip->block[(chip->channel + 1) % 6]; - chip->pg_kcode = chip->kcode[(chip->channel + 1) % 6]; - break; - } - } - else - { - chip->pg_fnum = chip->fnum[(chip->channel + 1) % 6]; - chip->pg_block = chip->block[(chip->channel + 1) % 6]; - chip->pg_kcode = chip->kcode[(chip->channel + 1) % 6]; - } - - OPN2_UpdateLFO(chip); - OPN2_DoRegWrite(chip); - chip->cycles = (chip->cycles + 1) % 24; - chip->channel = chip->cycles % 6; - - buffer[0] = chip->mol; - buffer[1] = chip->mor; -} - -void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data) -{ - port &= 3; - chip->write_data = ((port << 7) & 0x100) | data; - if (port & 1) - { - /* Data */ - chip->write_d |= 1; - } - else - { - /* Address */ - chip->write_a |= 1; - } -} - -void OPN2_SetTestPin(ym3438_t *chip, Bit32u value) -{ - chip->pin_test_in = value & 1; -} - -Bit32u OPN2_ReadTestPin(ym3438_t *chip) -{ - if (!chip->mode_test_2c[7]) - { - return 0; - } - return chip->cycles == 23; -} - -Bit32u OPN2_ReadIRQPin(ym3438_t *chip) -{ - return chip->timer_a_overflow_flag | chip->timer_b_overflow_flag; -} - -Bit8u OPN2_Read(ym3438_t *chip, Bit32u port) -{ - if ((port & 3) == 0 || chip_type == ym3438_type_asic) - { - if (chip->mode_test_21[6]) - { - /* Read test data */ - Bit32u slot = (chip->cycles + 18) % 24; - Bit16u testdata = ((chip->pg_read & 0x01) << 15) - | ((chip->eg_read[chip->mode_test_21[0]] & 0x01) << 14); - if (chip->mode_test_2c[4]) - { - testdata |= chip->ch_read & 0x1ff; - } - else - { - testdata |= chip->fm_out[slot] & 0x3fff; - } - if (chip->mode_test_21[7]) - { - return testdata & 0xff; - } - else - { - return testdata >> 8; - } - } - else - { - return (Bit8u)(chip->busy << 7) | (Bit8u)(chip->timer_b_overflow_flag << 1) - | (Bit8u)chip->timer_a_overflow_flag; - } - } - return 0; -} - -void OPN2_WriteBuffered(ym3438_t *chip, Bit32u port, Bit8u data) -{ - Bit64u time1, time2; - Bit16s buffer[2]; - Bit64u skip; - - if (chip->writebuf[chip->writebuf_last].port & 0x04) - { - OPN2_Write(chip, chip->writebuf[chip->writebuf_last].port & 0X03, - chip->writebuf[chip->writebuf_last].data); - - chip->writebuf_cur = (chip->writebuf_last + 1) % OPN_WRITEBUF_SIZE; - skip = chip->writebuf[chip->writebuf_last].time - chip->writebuf_samplecnt; - chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; - while (skip--) - { - OPN2_Clock(chip, buffer); - } - } - - chip->writebuf[chip->writebuf_last].port = (port & 0x03) | 0x04; - chip->writebuf[chip->writebuf_last].data = data; - time1 = chip->writebuf_lasttime + OPN_WRITEBUF_DELAY; - time2 = chip->writebuf_samplecnt; - - if (time1 < time2) - { - time1 = time2; - } - - chip->writebuf[chip->writebuf_last].time = time1; - chip->writebuf_lasttime = time1; - chip->writebuf_last = (chip->writebuf_last + 1) % OPN_WRITEBUF_SIZE; -} - -void OPN2_Generate(ym3438_t *chip, Bit16s *buf) -{ - Bit32u i; - Bit16s buffer[2]; - Bit32u mute; - - buf[0] = 0; - buf[1] = 0; - - for (i = 0; i < 24; i++) - { - switch (chip->cycles >> 2) - { - case 0: /* Ch 2 */ - mute = chip->mute[1]; - break; - case 1: /* Ch 6, DAC */ - mute = chip->mute[5 + chip->dacen]; - break; - case 2: /* Ch 4 */ - mute = chip->mute[3]; - break; - case 3: /* Ch 1 */ - mute = chip->mute[0]; - break; - case 4: /* Ch 5 */ - mute = chip->mute[4]; - break; - case 5: /* Ch 3 */ - mute = chip->mute[2]; - break; - default: - mute = 0; - break; - } - OPN2_Clock(chip, buffer); - if (!mute) - { - buf[0] += buffer[0]; - buf[1] += buffer[1]; - } - - while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) - { - if (!(chip->writebuf[chip->writebuf_cur].port & 0x04)) - { - break; - } - chip->writebuf[chip->writebuf_cur].port &= 0x03; - OPN2_Write(chip, chip->writebuf[chip->writebuf_cur].port, - chip->writebuf[chip->writebuf_cur].data); - chip->writebuf_cur = (chip->writebuf_cur + 1) % OPN_WRITEBUF_SIZE; - } - chip->writebuf_samplecnt++; - } -} - -void OPN2_GenerateResampled(ym3438_t *chip, Bit16s *buf) -{ - Bit16s buffer[2]; - - while (chip->samplecnt >= chip->rateratio) - { - chip->oldsamples[0] = chip->samples[0]; - chip->oldsamples[1] = chip->samples[1]; - OPN2_Generate(chip, buffer); - chip->samples[0] = buffer[0] * 11; - chip->samples[1] = buffer[1] * 11; - chip->samplecnt -= chip->rateratio; - } - buf[0] = (Bit16s)(((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) - + chip->samples[0] * chip->samplecnt) / chip->rateratio)>>1); - buf[1] = (Bit16s)(((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) - + chip->samples[1] * chip->samplecnt) / chip->rateratio)>>1); - chip->samplecnt += 1 << RSM_FRAC; -} - -void OPN2_GenerateStream(ym3438_t *chip, Bit16s *output, Bit32u numsamples) -{ - Bit32u i; - Bit16s buffer[2]; - - for (i = 0; i < numsamples; i++) - { - OPN2_GenerateResampled(chip, buffer); - *output++ = buffer[0]; - *output++ = buffer[1]; - } -} - -void OPN2_GenerateStreamMix(ym3438_t *chip, Bit16s *output, Bit32u numsamples) -{ - Bit32u i; - Bit16s buffer[2]; - - for (i = 0; i < numsamples; i++) - { - OPN2_GenerateResampled(chip, buffer); - *output++ += buffer[0]; - *output++ += buffer[1]; - } -} - - -void OPN2_SetOptions(Bit8u flags) -{ - switch ((flags >> 3) & 0x03) - { - case 0x00: /* YM2612 */ - default: - OPN2_SetChipType(ym3438_type_ym2612); - break; - case 0x01: /* ASIC YM3438 */ - OPN2_SetChipType(ym3438_type_asic); - break; - case 0x02: /* Discrete YM3438 */ - OPN2_SetChipType(ym3438_type_discrete); - break; - } -} - -void OPN2_SetMute(ym3438_t *chip, Bit32u mute) -{ - Bit32u i; - for (i = 0; i < 7; i++) - { - chip->mute[i] = (mute >> i) & 0x01; - } -} - - -} // Ym2612_NukedImpl - - -Ym2612_Nuked_Emu::Ym2612_Nuked_Emu() -{ - Ym2612_NukedImpl::OPN2_SetChipType( Ym2612_NukedImpl::ym3438_type_asic ); - impl = new Ym2612_NukedImpl::ym3438_t; -} - -Ym2612_Nuked_Emu::~Ym2612_Nuked_Emu() -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( chip_r ) delete chip_r; -} - -const char *Ym2612_Nuked_Emu::set_rate(double sample_rate, double clock_rate) -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( !chip_r ) - return "Out of memory"; - prev_sample_rate = sample_rate; - prev_clock_rate = clock_rate; - Ym2612_NukedImpl::OPN2_Reset( chip_r, static_cast(sample_rate), static_cast(clock_rate) ); - return 0; -} - -void Ym2612_Nuked_Emu::reset() -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( !chip_r ) Ym2612_NukedImpl::OPN2_Reset( chip_r, static_cast(prev_sample_rate), static_cast(prev_clock_rate) ); -} - -void Ym2612_Nuked_Emu::mute_voices(int mask) -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( chip_r ) Ym2612_NukedImpl::OPN2_SetMute( chip_r, mask ); -} - -void Ym2612_Nuked_Emu::write0(int addr, int data) -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( !chip_r ) return; - Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 0, static_cast(addr) ); - Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 1, static_cast(data) ); -} - -void Ym2612_Nuked_Emu::write1(int addr, int data) -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( !chip_r ) return; - Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 0 + 2, static_cast(addr) ); - Ym2612_NukedImpl::OPN2_WriteBuffered( chip_r, 1 + 2, static_cast(data) ); -} - -void Ym2612_Nuked_Emu::run(int pair_count, Ym2612_Nuked_Emu::sample_t *out) -{ - Ym2612_NukedImpl::ym3438_t *chip_r = reinterpret_cast(impl); - if ( !chip_r ) return; - Ym2612_NukedImpl::OPN2_GenerateStream(chip_r, out, pair_count); -} diff --git a/libraries/game-music-emu/gme/Ym2612_Nuked.h b/libraries/game-music-emu/gme/Ym2612_Nuked.h deleted file mode 100644 index 6c265b138..000000000 --- a/libraries/game-music-emu/gme/Ym2612_Nuked.h +++ /dev/null @@ -1,41 +0,0 @@ -// YM2612 FM sound chip emulator interface - -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ -#ifndef YM2612_EMU_H -#define YM2612_EMU_H - -typedef void Ym2612_Nuked_Impl; - -class Ym2612_Nuked_Emu { - Ym2612_Nuked_Impl* impl; - double prev_sample_rate; - double prev_clock_rate; -public: - Ym2612_Nuked_Emu(); - ~Ym2612_Nuked_Emu(); - - // Set output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - const char* set_rate( double sample_rate, double clock_rate ); - - // Reset to power-up state - void reset(); - - // Mute voice n if bit n (1 << n) of mask is set - enum { channel_count = 6 }; - void mute_voices( int mask ); - - // Write addr to register 0 then data to register 1 - void write0( int addr, int data ); - - // Write addr to register 2 then data to register 3 - void write1( int addr, int data ); - - // Run and add pair_count samples into current output buffer contents - typedef short sample_t; - enum { out_chan_count = 2 }; // stereo - void run( int pair_count, sample_t* out ); -}; - -#endif - diff --git a/libraries/game-music-emu/gme/blargg_common.h b/libraries/game-music-emu/gme/blargg_common.h deleted file mode 100644 index 13cc2417e..000000000 --- a/libraries/game-music-emu/gme/blargg_common.h +++ /dev/null @@ -1,160 +0,0 @@ -// Sets up common environment for Shay Green's libraries. -// To change configuration options, modify blargg_config.h, not this file. - -#ifndef BLARGG_COMMON_H -#define BLARGG_COMMON_H - -#include -#include -#include -#include - -#undef BLARGG_COMMON_H -// allow blargg_config.h to #include blargg_common.h -#include "blargg_config.h" -#ifndef 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 (expr) -#ifndef STATIC_CAST - #define STATIC_CAST(T,expr) ((T) (expr)) -#endif - -// blargg_err_t (0 on success, otherwise error string) -#ifndef blargg_err_t - typedef const char* blargg_err_t; -#endif - -// blargg_vector - very lightweight vector of POD types (no constructor/destructor) -template -class blargg_vector { - T* begin_; - size_t size_; -public: - blargg_vector() : begin_( 0 ), size_( 0 ) { } - ~blargg_vector() { free( begin_ ); } - size_t size() const { return size_; } - T* begin() const { return begin_; } - T* end() const { return begin_ + size_; } - blargg_err_t resize( size_t n ) - { - void* p = realloc( begin_, n * sizeof (T) ); - if ( !p && n ) - return "Out of memory"; - begin_ = (T*) p; - size_ = n; - return 0; - } - void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } - T& operator [] ( size_t n ) const - { - assert( n <= size_ ); // <= to allow past-the-end value - return begin_ [n]; - } -}; - -#ifndef BLARGG_DISABLE_NOTHROW - // throw spec mandatory in ISO C++ if operator new can return NULL - #if __cplusplus >= 199711 || __GNUC__ >= 3 - #define BLARGG_THROWS( spec ) throw spec - #else - #define BLARGG_THROWS( spec ) - #endif - #define BLARGG_DISABLE_NOTHROW \ - void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ - void operator delete ( void* p ) { free( p ); } - #define BLARGG_NEW new -#else - #include - #define BLARGG_NEW new (std::nothrow) -#endif - -// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) -#define BLARGG_4CHAR( a, b, c, d ) \ - ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) - -#define BLARGG_2CHAR( a, b ) \ - ((a&0xFF)*0x100L + (b&0xFF)) - -// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. -#ifndef BOOST_STATIC_ASSERT - #ifdef _MSC_VER - // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) - #else - // Some other compilers fail when declaring same function multiple times in class, - // so differentiate them by line - #define BOOST_STATIC_ASSERT( expr ) \ - void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) - #endif -#endif - -// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, -// compiler is assumed to support bool. If undefined, availability is determined. -#ifndef BLARGG_COMPILER_HAS_BOOL - #if defined (__MWERKS__) - #if !__option(bool) - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (_MSC_VER) - #if _MSC_VER < 1100 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif - #elif defined (__GNUC__) - // supports bool - #elif __cplusplus < 199711 - #define BLARGG_COMPILER_HAS_BOOL 0 - #endif -#endif -#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL - // If you get errors here, modify your blargg_config.h file - typedef int bool; - const bool true = 1; - const bool false = 0; -#endif - -// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough - -#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF - typedef long blargg_long; -#else - typedef int blargg_long; -#endif - -#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF - typedef unsigned long blargg_ulong; -#else - typedef unsigned blargg_ulong; -#endif - -// int8_t etc. - -// TODO: Add CMake check for this, although I'd likely just point affected -// persons to a real compiler... -#if 1 || defined (HAVE_STDINT_H) - #include -#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 diff --git a/libraries/game-music-emu/gme/blargg_config.h b/libraries/game-music-emu/gme/blargg_config.h deleted file mode 100644 index 377dd2d8c..000000000 --- a/libraries/game-music-emu/gme/blargg_config.h +++ /dev/null @@ -1,43 +0,0 @@ -// Library configuration. Modify this file as necessary. - -#ifndef BLARGG_CONFIG_H -#define BLARGG_CONFIG_H - -// Uncomment to use zlib for transparent decompression of gzipped files -//#define HAVE_ZLIB_H - -// Uncomment and edit list to support only the listed game music types, -// so that the others don't get linked in at all. -/* -#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 -//#define BLARGG_NONPORTABLE 1 - -// Uncomment to use faster, lower quality sound synthesis -//#define BLIP_BUFFER_FAST 1 - -// Uncomment if automatic byte-order determination doesn't work -//#define BLARGG_BIG_ENDIAN 1 - -// Uncomment if you get errors in the bool section of blargg_common.h -//#define BLARGG_COMPILER_HAS_BOOL 1 - -// Use standard config.h if present -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#endif diff --git a/libraries/game-music-emu/gme/blargg_endian.h b/libraries/game-music-emu/gme/blargg_endian.h deleted file mode 100644 index 46e58e2f0..000000000 --- a/libraries/game-music-emu/gme/blargg_endian.h +++ /dev/null @@ -1,184 +0,0 @@ -// CPU Byte Order Utilities - -#ifndef BLARGG_ENDIAN -#define BLARGG_ENDIAN - -#include "blargg_common.h" - -// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) -#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64) - #define BLARGG_CPU_X86 1 - #define BLARGG_CPU_CISC 1 -#endif - -#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \ - defined (__POWERPC__) || defined (__powerc) - #define BLARGG_CPU_POWERPC 1 - #define BLARGG_CPU_RISC 1 -#endif - -// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only -// one may be #defined to 1. Only needed if something actually depends on byte order. -#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) -#ifdef __GLIBC__ - // GCC handles this for us - #include - #if __BYTE_ORDER == __LITTLE_ENDIAN - #define BLARGG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER == __BIG_ENDIAN - #define BLARGG_BIG_ENDIAN 1 - #endif -#else - -#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ - (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) - #define BLARGG_LITTLE_ENDIAN 1 -#endif - -#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ - defined (__sparc__) || BLARGG_CPU_POWERPC || \ - (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) - #define BLARGG_BIG_ENDIAN 1 -#elif !defined (__mips__) - // No endian specified; assume little-endian, since it's most common - #define BLARGG_LITTLE_ENDIAN 1 -#endif -#endif -#endif - -#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN - #undef BLARGG_LITTLE_ENDIAN - #undef BLARGG_BIG_ENDIAN -#endif - -inline void blargg_verify_byte_order() -{ - #ifndef NDEBUG - #if BLARGG_BIG_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i == 0 ); - #elif BLARGG_LITTLE_ENDIAN - volatile int i = 1; - assert( *(volatile char*) &i != 0 ); - #endif - #endif -} - -inline unsigned get_le16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [1] << 8 | - (unsigned) ((unsigned char const*) p) [0]; -} - -inline unsigned get_be16( void const* p ) -{ - return (unsigned) ((unsigned char const*) p) [0] << 8 | - (unsigned) ((unsigned char const*) p) [1]; -} - -inline blargg_ulong get_le32( void const* p ) -{ - return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | - (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 (blargg_ulong) ((unsigned char const*) p) [0] << 24 | - (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 ) -{ - ((unsigned char*) p) [1] = (unsigned char) (n >> 8); - ((unsigned char*) p) [0] = (unsigned char) n; -} - -inline void set_be16( void* p, unsigned n ) -{ - ((unsigned char*) p) [0] = (unsigned char) (n >> 8); - ((unsigned char*) p) [1] = (unsigned char) n; -} - -inline void set_le32( void* p, blargg_ulong 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) [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 - // Optimized implementation if byte order is known - #if BLARGG_LITTLE_ENDIAN - #define GET_LE16( addr ) (*(uint16_t*) (addr)) - #define GET_LE32( addr ) (*(uint32_t*) (addr)) - #define SET_LE16( addr, data ) (void) (*(uint16_t*) (addr) = (data)) - #define SET_LE32( addr, data ) (void) (*(uint32_t*) (addr) = (data)) - #elif BLARGG_BIG_ENDIAN - #define GET_BE16( addr ) (*(uint16_t*) (addr)) - #define GET_BE32( addr ) (*(uint32_t*) (addr)) - #define SET_BE16( addr, data ) (void) (*(uint16_t*) (addr) = (data)) - #define SET_BE32( addr, data ) (void) (*(uint32_t*) (addr) = (data)) - - #if BLARGG_CPU_POWERPC - // PowerPC has special byte-reversed instructions - #if defined (__MWERKS__) - #define GET_LE16( addr ) (__lhbrx( addr, 0 )) - #define GET_LE32( addr ) (__lwbrx( addr, 0 )) - #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) - #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) - #elif defined (__GNUC__) - #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 - -#ifndef GET_LE16 - #define GET_LE16( addr ) get_le16( addr ) - #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 ) -#endif - -#ifndef GET_BE16 - #define GET_BE16( addr ) get_be16( addr ) - #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 ) -#endif - -// auto-selecting versions - -inline void set_le( uint16_t* p, unsigned n ) { SET_LE16( p, n ); } -inline void set_le( uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } -inline void set_be( uint16_t* p, unsigned n ) { SET_BE16( p, n ); } -inline void set_be( uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } -inline unsigned get_le( uint16_t* p ) { return GET_LE16( p ); } -inline blargg_ulong get_le( uint32_t* p ) { return GET_LE32( p ); } -inline unsigned get_be( uint16_t* p ) { return GET_BE16( p ); } -inline blargg_ulong get_be( uint32_t* p ) { return GET_BE32( p ); } - -#endif diff --git a/libraries/game-music-emu/gme/blargg_source.h b/libraries/game-music-emu/gme/blargg_source.h deleted file mode 100644 index b65afd30b..000000000 --- a/libraries/game-music-emu/gme/blargg_source.h +++ /dev/null @@ -1,123 +0,0 @@ -/* 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 -#define BLARGG_SOURCE_H - -// If debugging is enabled, abort program if expr is false. Meant for checking -// internal state and consistency. A failed assertion indicates a bug in the module. -// void assert( bool expr ); -#include - -// If debugging is enabled and expr is false, abort program. Meant for checking -// caller-supplied parameters and operations that are outside the control of the -// module. A failed requirement indicates a bug outside the module. -// void require( bool expr ); -#undef require -#define require( expr ) assert( expr ) - -// Use to provide hints to compiler for optimized code layout in situations where we -// can almost always expect a conditional to go one way or the other. Should only be -// used in situations where an unexpected branch is truly exceptional though! -#undef likely -#undef unlikely -#ifdef __GNUC__ - #define likely( x ) __builtin_expect(x, 1) - #define unlikely( x ) __builtin_expect(x, 0) -#else - #define likely( x ) (x) - #define unlikely( x ) (x) -#endif - -// Like printf() except output goes to debug log file. Might be defined to do -// nothing (not even evaluate its arguments). -// void debug_printf( const char* format, ... ); -static inline void blargg_dprintf_( const char*, ... ) { } -#undef debug_printf -#define debug_printf (1) ? (void) 0 : blargg_dprintf_ - -// 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 -// don't indicate a problem. In all cases, execution continues normally. -#undef check -#define check( expr ) ((void) 0) - -// If expr yields error string, return it from current function, otherwise continue. -#undef RETURN_ERR -#define RETURN_ERR( expr ) do { \ - blargg_err_t blargg_return_err_ = (expr); \ - if ( blargg_return_err_ ) return blargg_return_err_; \ - } while ( 0 ) - -// If ptr is 0, return out of memory error string. -#undef CHECK_ALLOC -#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) - -// Avoid any macros which evaluate their arguments multiple times -#undef min -#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 -// for built-in types, so they take arguments by value - -// TODO: remove -inline int min( int x, int y ) -template -inline T min( T x, T y ) -{ - if ( x < y ) - return x; - return y; -} - -template -inline T max( T x, T y ) -{ - if ( x < y ) - return y; - return x; -} -*/ - -// TODO: good idea? bad idea? -#undef byte -#define byte 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 -#define BLARGG_CHECK_ALLOC CHECK_ALLOC -#define BLARGG_RETURN_ERR RETURN_ERR - -// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of debug_printf and check -#ifdef BLARGG_SOURCE_BEGIN - #include BLARGG_SOURCE_BEGIN -#endif - -#endif diff --git a/libraries/game-music-emu/gme/gb_cpu_io.h b/libraries/game-music-emu/gme/gb_cpu_io.h deleted file mode 100644 index 8bd69aa2d..000000000 --- a/libraries/game-music-emu/gme/gb_cpu_io.h +++ /dev/null @@ -1,72 +0,0 @@ - -#include "Gbs_Emu.h" - -#include "blargg_source.h" - -int Gbs_Emu::cpu_read( gb_addr_t addr ) -{ - int result = *cpu::get_code( addr ); - if ( unsigned (addr - Gb_Apu::start_addr) < Gb_Apu::register_count ) - result = apu.read_register( clock(), addr ); -#ifndef NDEBUG - else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 ) - debug_printf( "Read from unmapped memory $%.4x\n", (unsigned) addr ); - else if ( unsigned (addr - 0xFF01) < 0xFF80 - 0xFF01 ) - debug_printf( "Unhandled I/O read 0x%4X\n", (unsigned) addr ); -#endif - return result; -} - -void Gbs_Emu::cpu_write( gb_addr_t addr, int data ) -{ - unsigned offset = addr - ram_addr; - if ( offset <= 0xFFFF - ram_addr ) - { - ram [offset] = data; - if ( (addr ^ 0xE000) <= 0x1F80 - 1 ) - { - if ( unsigned (addr - Gb_Apu::start_addr) < Gb_Apu::register_count ) - { - GME_APU_HOOK( this, addr - Gb_Apu::start_addr, data ); - apu.write_register( clock(), addr, data ); - } - else if ( (addr ^ 0xFF06) < 2 ) - update_timer(); - else if ( addr == joypad_addr ) - ram [offset] = 0; // keep joypad return value 0 - else - ram [offset] = 0xFF; - - //if ( addr == 0xFFFF ) - // debug_printf( "Wrote interrupt mask\n" ); - } - } - else if ( (addr ^ 0x2000) <= 0x2000 - 1 ) - { - set_bank( data ); - } -#ifndef NDEBUG - else if ( unsigned (addr - 0x8000) < 0x2000 || unsigned (addr - 0xE000) < 0x1F00 ) - { - debug_printf( "Wrote to unmapped memory $%.4x\n", (unsigned) addr ); - } -#endif -} - -#define CPU_READ_FAST( cpu, addr, time, out ) \ - CPU_READ_FAST_( STATIC_CAST(Gbs_Emu*,cpu), addr, time, out ) - -#define CPU_READ_FAST_( emu, addr, time, out ) \ -{\ - out = READ_PROG( addr );\ - if ( unsigned (addr - Gb_Apu::start_addr) < Gb_Apu::register_count )\ - out = emu->apu.read_register( emu->cpu_time - time * clocks_per_instr, addr );\ - else\ - check( out == emu->cpu_read( addr ) );\ -} - -#define CPU_READ( cpu, addr, time ) \ - STATIC_CAST(Gbs_Emu*,cpu)->cpu_read( addr ) - -#define CPU_WRITE( cpu, addr, data, time ) \ - STATIC_CAST(Gbs_Emu*,cpu)->cpu_write( addr, data ) diff --git a/libraries/game-music-emu/gme/gme.cpp b/libraries/game-music-emu/gme/gme.cpp deleted file mode 100644 index 8558e0904..000000000 --- a/libraries/game-music-emu/gme/gme.cpp +++ /dev/null @@ -1,420 +0,0 @@ -// Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ - -#include "Music_Emu.h" - -#include "gme_types.h" -#if !GME_DISABLE_STEREO_DEPTH -#include "Effects_Buffer.h" -#endif -#include "blargg_endian.h" -#include -#include - -/* Copyright (C) 2003-2006 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -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" - -BLARGG_EXPORT gme_type_t const* gme_type_list() -{ - 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_; -} - -BLARGG_EXPORT const char* gme_identify_header( void const* header ) -{ - switch ( get_be32( header ) ) - { - case BLARGG_4CHAR('Z','X','A','Y'): return "AY"; - case BLARGG_4CHAR('G','B','S',0x01): return "GBS"; - case BLARGG_4CHAR('G','Y','M','X'): return "GYM"; - case BLARGG_4CHAR('H','E','S','M'): return "HES"; - case BLARGG_4CHAR('K','S','C','C'): - case BLARGG_4CHAR('K','S','S','X'): return "KSS"; - case BLARGG_4CHAR('N','E','S','M'): return "NSF"; - case BLARGG_4CHAR('N','S','F','E'): return "NSFE"; - case BLARGG_4CHAR('S','A','P',0x0D): return "SAP"; - case BLARGG_4CHAR('S','N','E','S'): return "SPC"; - case BLARGG_4CHAR('V','g','m',' '): return "VGM"; - } - if (get_be16(header) == BLARGG_2CHAR(0x1F, 0x8B)) - return "VGZ"; - return ""; -} - -static void to_uppercase( const char* in, int len, char* out ) -{ - for ( int i = 0; i < len; i++ ) - { - if ( !(out [i] = toupper( in [i] )) ) - return; - } - *out = 0; // extension too long -} - -BLARGG_EXPORT gme_type_t gme_identify_extension( const char* extension_ ) -{ - char const* end = strrchr( extension_, '.' ); - if ( end ) - extension_ = end + 1; - - char extension [6]; - to_uppercase( extension_, sizeof extension, extension ); - - for ( gme_type_t const* types = gme_type_list(); *types; types++ ) - if ( !strcmp( extension, (*types)->extension_ ) ) - return *types; - return 0; -} - -BLARGG_EXPORT const char *gme_type_extension( gme_type_t music_type ) -{ - const gme_type_t_ *const music_typeinfo = static_cast( music_type ); - if ( music_type ) - return music_typeinfo->extension_; - return ""; -} - -BLARGG_EXPORT gme_err_t gme_identify_file( const char* path, gme_type_t* type_out ) -{ - *type_out = gme_identify_extension( path ); - // TODO: don't examine header if file has extension? - if ( !*type_out ) - { - char header [4]; - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - RETURN_ERR( in.read( header, sizeof header ) ); - *type_out = gme_identify_extension( gme_identify_header( header ) ); - } - return 0; -} - -BLARGG_EXPORT gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate ) -{ - require( (data || !size) && out ); - *out = 0; - - gme_type_t file_type = 0; - if ( size >= 4 ) - file_type = gme_identify_extension( gme_identify_header( data ) ); - if ( !file_type ) - return gme_wrong_file_type; - - Music_Emu* emu = gme_new_emu( file_type, sample_rate ); - CHECK_ALLOC( emu ); - - gme_err_t err = gme_load_data( emu, data, size ); - - if ( err ) - delete emu; - else - *out = emu; - - return err; -} - -BLARGG_EXPORT gme_err_t gme_open_file( const char* path, Music_Emu** out, int sample_rate ) -{ - require( path && out ); - *out = 0; - - GME_FILE_READER in; - RETURN_ERR( in.open( path ) ); - - char header [4]; - int header_size = 0; - - gme_type_t file_type = gme_identify_extension( path ); - if ( !file_type ) - { - header_size = sizeof header; - RETURN_ERR( in.read( header, sizeof header ) ); - file_type = gme_identify_extension( gme_identify_header( header ) ); - } - if ( !file_type ) - return gme_wrong_file_type; - - Music_Emu* emu = gme_new_emu( file_type, sample_rate ); - CHECK_ALLOC( emu ); - - // optimization: avoids seeking/re-reading header - Remaining_Reader rem( header, header_size, &in ); - gme_err_t err = emu->load( rem ); - in.close(); - - if ( err ) - delete emu; - else - *out = emu; - - return err; -} - -BLARGG_EXPORT void gme_set_autoload_playback_limit( Music_Emu *emu, int do_autoload_limit ) -{ - emu->set_autoload_playback_limit( do_autoload_limit != 0 ); -} - -BLARGG_EXPORT int gme_autoload_playback_limit( Music_Emu *const emu ) -{ - return emu->autoload_playback_limit(); -} - -// Used to implement gme_new_emu and gme_new_emu_multi_channel -Music_Emu* gme_internal_new_emu_( gme_type_t type, int rate, bool multi_channel ) -{ - if ( type ) - { - if ( rate == gme_info_only ) - return type->new_info(); - - Music_Emu* me = type->new_emu(); - if ( me ) - { - #if !GME_DISABLE_STEREO_DEPTH - me->set_multi_channel( multi_channel ); - - if ( type->flags_ & 1 ) - { - if ( me->multi_channel() ) - { - me->effects_buffer = BLARGG_NEW Effects_Buffer(8); - } - else - { - me->effects_buffer = BLARGG_NEW Effects_Buffer(1); - } - if ( me->effects_buffer ) - me->set_buffer( me->effects_buffer ); - } - - if ( !(type->flags_ & 1) || me->effects_buffer ) - #endif - { - if ( !me->set_sample_rate( rate ) ) - { - check( me->type() == type ); - return me; - } - } - delete me; - } - } - return 0; -} - -BLARGG_EXPORT Music_Emu* gme_new_emu( gme_type_t type, int rate ) -{ - return gme_internal_new_emu_( type, rate, false /* no multichannel */); -} - -BLARGG_EXPORT Music_Emu* gme_new_emu_multi_channel( gme_type_t type, int rate ) -{ - // multi-channel emulator (if possible, not all emu types support multi-channel) - return gme_internal_new_emu_( type, rate, true /* multichannel */); -} - -BLARGG_EXPORT gme_err_t gme_load_file( Music_Emu* me, const char* path ) { return me->load_file( path ); } - -BLARGG_EXPORT gme_err_t gme_load_data( Music_Emu* me, void const* data, long size ) -{ - Mem_File_Reader in( data, size ); - return me->load( in ); -} - -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 ); - return me->load( in ); -} - -BLARGG_EXPORT void gme_delete( Music_Emu* me ) { delete me; } - -BLARGG_EXPORT gme_type_t gme_type( Music_Emu const* me ) { return me->type(); } - -BLARGG_EXPORT const char* gme_warning( Music_Emu* me ) { return me->warning(); } - -BLARGG_EXPORT int gme_track_count( Music_Emu const* me ) { return me->track_count(); } - -struct gme_info_t_ : gme_info_t -{ - track_info_t info; - - BLARGG_DISABLE_NOTHROW -}; - -BLARGG_EXPORT gme_err_t gme_track_info( Music_Emu const* me, gme_info_t** out, int track ) -{ - *out = NULL; - - gme_info_t_* info = BLARGG_NEW gme_info_t_; - CHECK_ALLOC( info ); - - gme_err_t err = me->track_info( &info->info, track ); - if ( err ) - { - gme_free_info( info ); - return err; - } - - #define COPY(name) info->name = info->info.name; - - COPY( length ); - COPY( intro_length ); - COPY( loop_length ); - - info->i4 = -1; - info->i5 = -1; - info->i6 = -1; - info->i7 = -1; - info->i8 = -1; - info->i9 = -1; - info->i10 = -1; - info->i11 = -1; - info->i12 = -1; - info->i13 = -1; - info->i14 = -1; - info->i15 = -1; - - info->s7 = ""; - info->s8 = ""; - info->s9 = ""; - info->s10 = ""; - info->s11 = ""; - info->s12 = ""; - info->s13 = ""; - info->s14 = ""; - info->s15 = ""; - - COPY( system ); - COPY( game ); - COPY( song ); - COPY( author ); - COPY( copyright ); - COPY( comment ); - COPY( dumper ); - - #undef COPY - - info->play_length = info->length; - if ( info->play_length <= 0 ) - { - info->play_length = info->intro_length + 2 * info->loop_length; // intro + 2 loops - if ( info->play_length <= 0 ) - info->play_length = 150 * 1000; // 2.5 minutes - } - - *out = info; - - return 0; -} - -BLARGG_EXPORT void gme_free_info( gme_info_t* info ) -{ - delete STATIC_CAST(gme_info_t_*,info); -} - -BLARGG_EXPORT void gme_set_stereo_depth( Music_Emu* me, double depth ) -{ -#if !GME_DISABLE_STEREO_DEPTH - if ( me->effects_buffer ) - STATIC_CAST(Effects_Buffer*,me->effects_buffer)->set_depth( depth ); -#endif -} - -BLARGG_EXPORT void* gme_user_data ( Music_Emu const* me ) { return me->user_data(); } -BLARGG_EXPORT void gme_set_user_data ( Music_Emu* me, void* new_user_data ) { me->set_user_data( new_user_data ); } -BLARGG_EXPORT void gme_set_user_cleanup(Music_Emu* me, gme_user_cleanup_t func ) { me->set_user_cleanup( func ); } - -BLARGG_EXPORT gme_err_t gme_start_track ( Music_Emu* me, int index ) { return me->start_track( index ); } -BLARGG_EXPORT gme_err_t gme_play ( Music_Emu* me, int n, short* p ) { return me->play( n, p ); } -BLARGG_EXPORT void 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(); } -BLARGG_EXPORT int gme_tell ( Music_Emu const* me ) { return me->tell(); } -BLARGG_EXPORT int gme_tell_samples ( Music_Emu const* me ) { return me->tell_samples(); } -BLARGG_EXPORT gme_err_t gme_seek ( Music_Emu* me, int msec ) { return me->seek( msec ); } -BLARGG_EXPORT gme_err_t gme_seek_samples ( Music_Emu* me, int n ) { return me->seek_samples( n ); } -BLARGG_EXPORT int 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 ); } -BLARGG_EXPORT void gme_set_tempo ( Music_Emu* me, double t ) { me->set_tempo( t ); } -BLARGG_EXPORT void gme_mute_voice ( Music_Emu* me, int index, int mute ) { me->mute_voice( index, mute != 0 ); } -BLARGG_EXPORT void gme_mute_voices ( Music_Emu* me, int mask ) { me->mute_voices( mask ); } -BLARGG_EXPORT void gme_enable_accuracy( Music_Emu* me, int enabled ) { me->enable_accuracy( enabled ); } -BLARGG_EXPORT void gme_clear_playlist ( Music_Emu* me ) { me->clear_playlist(); } -BLARGG_EXPORT int gme_type_multitrack( gme_type_t t ) { return t->track_count != 1; } -BLARGG_EXPORT int gme_multi_channel ( Music_Emu const* me ) { return me->multi_channel(); } - -BLARGG_EXPORT void gme_set_equalizer ( Music_Emu* me, gme_equalizer_t const* eq ) -{ - Music_Emu::equalizer_t e = me->equalizer(); - e.treble = eq->treble; - e.bass = eq->bass; - me->set_equalizer( e ); -} - -BLARGG_EXPORT void gme_equalizer( Music_Emu const* me, gme_equalizer_t* out ) -{ - gme_equalizer_t e = gme_equalizer_t(); // Default-init all fields to 0.0f - e.treble = me->equalizer().treble; - e.bass = me->equalizer().bass; - *out = e; -} - -BLARGG_EXPORT const char* gme_voice_name( Music_Emu const* me, int i ) -{ - assert( (unsigned) i < (unsigned) me->voice_count() ); - return me->voice_names() [i]; -} - -BLARGG_EXPORT const char* gme_type_system( gme_type_t type ) -{ - assert( type ); - return type->system; -} diff --git a/libraries/game-music-emu/gme/gme.h b/libraries/game-music-emu/gme/gme.h deleted file mode 100644 index 80c6ce846..000000000 --- a/libraries/game-music-emu/gme/gme.h +++ /dev/null @@ -1,267 +0,0 @@ -/* Game music emulator library C interface (also usable from C++) */ - -/* Game_Music_Emu 0.6.2 */ -#ifndef GME_H -#define GME_H - -#ifdef __cplusplus - extern "C" { -#endif - -#define GME_VERSION 0x000602 /* 1 byte major, 1 byte minor, 1 byte patch-level */ - -/* Error string returned by library functions, or NULL if no error (success) */ -typedef const char* gme_err_t; - -/* First parameter of most gme_ functions is a pointer to the Music_Emu */ -typedef struct Music_Emu Music_Emu; - - -/******** Basic operations ********/ - -/* Create emulator and load game music file/data into it. Sets *out to new emulator. */ -gme_err_t gme_open_file( const char path [], Music_Emu** out, int sample_rate ); - -/* Number of tracks available */ -int gme_track_count( Music_Emu const* ); - -/* Start a track, where 0 is the first track */ -gme_err_t gme_start_track( Music_Emu*, int index ); - -/* Generate 'count' 16-bit signed samples info 'out'. Output is in stereo. */ -gme_err_t gme_play( Music_Emu*, int count, short out [] ); - -/* Finish using emulator and free memory */ -void gme_delete( Music_Emu* ); - - -/******** Track position/length ********/ - -/* Set time to start fading track out. Once fade ends track_ended() returns true. -Fade time can be changed while track is playing. */ -void gme_set_fade( Music_Emu*, int start_msec ); - -/* True if a track has reached its end */ -int gme_track_ended( Music_Emu const* ); - -/* Number of milliseconds (1000 = one second) played since beginning of track */ -int gme_tell( Music_Emu const* ); - -/* Number of samples generated since beginning of track */ -int gme_tell_samples( Music_Emu const* ); - -/* Seek to new time in track. Seeking backwards or far forward can take a while. */ -gme_err_t gme_seek( Music_Emu*, int msec ); - -/* Equivalent to restarting track then skipping n samples */ -gme_err_t gme_seek_samples( Music_Emu*, int n ); - - -/******** Informational ********/ - -/* If you only need track information from a music file, pass gme_info_only for -sample_rate to open/load. */ -enum { gme_info_only = -1 }; - -/* 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. */ -const char* gme_warning( Music_Emu* ); - -/* Load m3u playlist file (must be done after loading music) */ -gme_err_t gme_load_m3u( Music_Emu*, const char path [] ); - -/* Clear any loaded m3u playlist and any internal playlist that the music format -supports (NSFE for example). */ -void gme_clear_playlist( Music_Emu* ); - -/* Gets information for a particular track (length, name, author, etc.). -Must be freed after use. */ -typedef struct gme_info_t gme_info_t; -gme_err_t gme_track_info( Music_Emu const*, gme_info_t** out, int track ); - -/* Frees track information */ -void gme_free_info( gme_info_t* ); - -struct gme_info_t -{ - /* times in milliseconds; -1 if unknown */ - int length; /* total length, if file specifies it */ - int intro_length; /* length of song up to looping section */ - int loop_length; /* length of looping section */ - - /* Length if available, otherwise intro_length+loop_length*2 if available, - otherwise a default of 150000 (2.5 minutes). */ - int play_length; - - int i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15; /* reserved */ - - /* empty string ("") if not available */ - const char* system; - const char* game; - const char* song; - const char* author; - const char* copyright; - const char* comment; - const char* dumper; - - const char *s7,*s8,*s9,*s10,*s11,*s12,*s13,*s14,*s15; /* reserved */ -}; - - -/******** Advanced playback ********/ - -/* Adjust stereo echo depth, where 0.0 = off and 1.0 = maximum. Has no effect for -GYM, SPC, and Sega Genesis VGM music */ -void gme_set_stereo_depth( Music_Emu*, double depth ); - -/* Disable automatic end-of-track detection and skipping of silence at beginning -if ignore is true */ -void gme_ignore_silence( Music_Emu*, int ignore ); - -/* 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. */ -void gme_set_tempo( Music_Emu*, double tempo ); - -/* Number of voices used by currently loaded file */ -int gme_voice_count( Music_Emu const* ); - -/* Name of voice i, from 0 to gme_voice_count() - 1 */ -const char* gme_voice_name( Music_Emu const*, int i ); - -/* Mute/unmute voice i, where voice 0 is first voice */ -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 -voices, 0 unmutes them all, 0x01 mutes just the first voice, etc. */ -void gme_mute_voices( Music_Emu*, int muting_mask ); - -/* Frequency equalizer parameters (see gme.txt) */ -/* Implementers: If modified, also adjust Music_Emu::make_equalizer as needed */ -typedef struct gme_equalizer_t -{ - double treble; /* -50.0 = muffled, 0 = flat, +5.0 = extra-crisp */ - double bass; /* 1 = full bass, 90 = average, 16000 = almost no bass */ - - double d2,d3,d4,d5,d6,d7,d8,d9; /* reserved */ -} gme_equalizer_t; - -/* Get current frequency equalizater parameters */ -void gme_equalizer( Music_Emu const*, gme_equalizer_t* out ); - -/* Change frequency equalizer parameters */ -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 ********/ - -/* Music file type identifier. Can also hold NULL. */ -typedef const struct gme_type_t_* gme_type_t; - -/* Emulator type constants for each supported file type */ -extern const gme_type_t - 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; - -/* Type of this emulator */ -gme_type_t gme_type( Music_Emu const* ); - -/* 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. */ -gme_type_t const* gme_type_list(); - -/* Name of game system for this music file type */ -const char* gme_type_system( gme_type_t ); - -/* True if this music file type supports multiple tracks */ -int gme_type_multitrack( gme_type_t ); - -/* whether the pcm output retrieved by gme_play() will have all 8 voices rendered to their - * individual stereo channel or (if false) these voices get mixed into one single stereo channel - * @since 0.6.2 */ -int gme_multi_channel( Music_Emu const* ); - -/******** Advanced file loading ********/ - -/* Error returned if file type is not supported */ -extern const char* const gme_wrong_file_type; - -/* Same as gme_open_file(), but uses file data already in memory. Makes copy of data. - * The resulting Music_Emu object will be set to single channel mode. */ -gme_err_t gme_open_data( void const* data, long size, Music_Emu** out, int sample_rate ); - -/* Determine likely game music type based on first four bytes of file. Returns -string containing proper file suffix (i.e. "NSF", "SPC", etc.) or "" if -file header is not recognized. */ -const char* gme_identify_header( void const* header ); - -/* Get corresponding music type for file path or extension passed in. */ -gme_type_t gme_identify_extension( const char path_or_extension [] ); - -/** - * Get typical file extension for a given music type. This is not a replacement - * for a file content identification library (but see gme_identify_header). - * - * @since 0.6.2 - */ -const char* gme_type_extension( gme_type_t music_type ); - -/* Determine file type based on file's extension or header (if extension isn't recognized). -Sets *type_out to type, or 0 if unrecognized or error. */ -gme_err_t gme_identify_file( const char path [], gme_type_t* type_out ); - -/* 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. */ -Music_Emu* gme_new_emu( gme_type_t, int sample_rate ); - -/* Create new multichannel emulator and set sample rate. Returns NULL if out of memory. - * If you only need track information, pass gme_info_only for sample_rate. - * (see gme_multi_channel for more information on multichannel support) - * @since 0.6.2 - */ -Music_Emu* gme_new_emu_multi_channel( gme_type_t, int sample_rate ); - -/* Load music file into emulator */ -gme_err_t gme_load_file( Music_Emu*, const char path [] ); - -/* Load music file from memory into emulator. Makes a copy of data passed. */ -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 -read file data. Most emulators load the entire file in one read call. */ -typedef gme_err_t (*gme_reader_t)( void* your_data, void* out, int count ); -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) */ -gme_err_t gme_load_m3u_data( Music_Emu*, void const* data, long size ); - - -/******** User data ********/ - -/* Set/get pointer to data you want to associate with this emulator. -You can use this for whatever you want. */ -void gme_set_user_data( Music_Emu*, void* new_user_data ); -void* gme_user_data( Music_Emu const* ); - -/* Register cleanup function to be called when deleting emulator, or NULL to -clear it. Passes user_data to cleanup function. */ -typedef void (*gme_user_cleanup_t)( void* user_data ); -void gme_set_user_cleanup( Music_Emu*, gme_user_cleanup_t func ); - - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/libraries/game-music-emu/gme/gme_types.h b/libraries/game-music-emu/gme/gme_types.h deleted file mode 100644 index 06226f4aa..000000000 --- a/libraries/game-music-emu/gme/gme_types.h +++ /dev/null @@ -1,21 +0,0 @@ -#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 */ diff --git a/libraries/game-music-emu/gme/gme_types.h.in b/libraries/game-music-emu/gme/gme_types.h.in deleted file mode 100644 index 4829b3e16..000000000 --- a/libraries/game-music-emu/gme/gme_types.h.in +++ /dev/null @@ -1,23 +0,0 @@ -#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 */ diff --git a/libraries/game-music-emu/gme/hes_cpu_io.h b/libraries/game-music-emu/gme/hes_cpu_io.h deleted file mode 100644 index ce60ce8ef..000000000 --- a/libraries/game-music-emu/gme/hes_cpu_io.h +++ /dev/null @@ -1,101 +0,0 @@ - -#include "Hes_Emu.h" - -#include "blargg_source.h" - -int Hes_Emu::cpu_read( hes_addr_t addr ) -{ - check( addr <= 0xFFFF ); - int result = *cpu::get_code( addr ); - if ( mmr [addr >> page_shift] == 0xFF ) - result = cpu_read_( addr ); - return result; -} - -void Hes_Emu::cpu_write( hes_addr_t addr, int data ) -{ - check( addr <= 0xFFFF ); - byte* out = write_pages [addr >> page_shift]; - addr &= page_size - 1; - if ( out ) - out [addr] = data; - else if ( mmr [addr >> page_shift] == 0xFF ) - cpu_write_( addr, data ); -} - -inline byte const* Hes_Emu::cpu_set_mmr( int page, int bank ) -{ - write_pages [page] = 0; - if ( bank < 0x80 ) - return rom.at_addr( bank * (blargg_long) page_size ); - - byte* data = 0; - switch ( bank ) - { - case 0xF8: - data = cpu::ram; - break; - - case 0xF9: - case 0xFA: - case 0xFB: - data = &sgx [(bank - 0xF9) * page_size]; - break; - - default: - if ( bank != 0xFF ) - debug_printf( "Unmapped bank $%02X\n", bank ); - return rom.unmapped(); - } - - write_pages [page] = data; - return data; -} - -#define CPU_READ_FAST( cpu, addr, time, out ) \ - CPU_READ_FAST_( STATIC_CAST(Hes_Emu*,cpu), addr, time, out ) - -#define CPU_READ_FAST_( cpu, addr, time, out ) \ -{\ - out = READ_PROG( addr );\ - if ( mmr [addr >> page_shift] == 0xFF )\ - {\ - FLUSH_TIME();\ - out = cpu->cpu_read_( addr );\ - CACHE_TIME();\ - }\ -} - -#define CPU_WRITE_FAST( cpu, addr, data, time ) \ - CPU_WRITE_FAST_( STATIC_CAST(Hes_Emu*,cpu), addr, data, time ) - -#define CPU_WRITE_FAST_( cpu, addr, data, time ) \ -{\ - byte* out = cpu->write_pages [addr >> page_shift];\ - addr &= page_size - 1;\ - if ( out )\ - {\ - out [addr] = data;\ - }\ - else if ( mmr [addr >> page_shift] == 0xFF )\ - {\ - FLUSH_TIME();\ - cpu->cpu_write_( addr, data );\ - CACHE_TIME();\ - }\ -} - -#define CPU_READ( cpu, addr, time ) \ - STATIC_CAST(Hes_Emu*,cpu)->cpu_read( addr ) - -#define CPU_WRITE( cpu, addr, data, time ) \ - STATIC_CAST(Hes_Emu*,cpu)->cpu_write( addr, data ) - -#define CPU_WRITE_VDP( cpu, addr, data, time ) \ - STATIC_CAST(Hes_Emu*,cpu)->cpu_write_vdp( addr, data ) - -#define CPU_SET_MMR( cpu, page, bank ) \ - STATIC_CAST(Hes_Emu*,cpu)->cpu_set_mmr( page, bank ) - -#define CPU_DONE( cpu, time, result_out ) \ - result_out = STATIC_CAST(Hes_Emu*,cpu)->cpu_done() diff --git a/libraries/game-music-emu/gme/libgme.pc.in b/libraries/game-music-emu/gme/libgme.pc.in deleted file mode 100644 index f057ce17c..000000000 --- a/libraries/game-music-emu/gme/libgme.pc.in +++ /dev/null @@ -1,16 +0,0 @@ -# entries grouped with CMake are expanded by CMake -# ${foo} entries are left alone by CMake and much -# later are used by pkg-config. -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -lib_suffix=@LIB_SUFFIX@ -libdir=${exec_prefix}/lib${lib_suffix} -includedir=${prefix}/include - -Name: Game_Music_Emu -Description: A video game emulation library for music. -URL: https://bitbucket.org/mpyne/game-music-emu/wiki/Home -Version: @GME_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lgme -Libs.private: -lstdc++ @PKG_CONFIG_ZLIB@ diff --git a/libraries/game-music-emu/gme/nes_cpu_io.h b/libraries/game-music-emu/gme/nes_cpu_io.h deleted file mode 100644 index 68ce9b6ff..000000000 --- a/libraries/game-music-emu/gme/nes_cpu_io.h +++ /dev/null @@ -1,83 +0,0 @@ - -#include "Nsf_Emu.h" - -#if !NSF_EMU_APU_ONLY - #include "Nes_Namco_Apu.h" -#endif - -#include "blargg_source.h" - -int Nsf_Emu::cpu_read( nes_addr_t addr ) -{ - int result; - - result = cpu::low_mem [addr & 0x7FF]; - if ( !(addr & 0xE000) ) - goto exit; - - result = *cpu::get_code( addr ); - if ( addr > 0x7FFF ) - goto exit; - - result = sram [addr & (sizeof sram - 1)]; - if ( addr > 0x5FFF ) - goto exit; - - if ( addr == Nes_Apu::status_addr ) - return apu.read_status( cpu::time() ); - - #if !NSF_EMU_APU_ONLY - if ( addr == Nes_Namco_Apu::data_reg_addr && namco ) - return namco->read_data(); - #endif - - result = addr >> 8; // simulate open bus - - if ( addr != 0x2002 ) - debug_printf( "Read unmapped $%.4X\n", (unsigned) addr ); - -exit: - return result; -} - -void Nsf_Emu::cpu_write( nes_addr_t addr, int data ) -{ - { - nes_addr_t offset = addr ^ sram_addr; - if ( offset < sizeof sram ) - { - sram [offset] = data; - return; - } - } - { - int temp = addr & 0x7FF; - if ( !(addr & 0xE000) ) - { - cpu::low_mem [temp] = data; - return; - } - } - - if ( unsigned (addr - Nes_Apu::start_addr) <= Nes_Apu::end_addr - Nes_Apu::start_addr ) - { - GME_APU_HOOK( this, addr - Nes_Apu::start_addr, data ); - apu.write_register( cpu::time(), addr, data ); - return; - } - - unsigned bank = addr - bank_select_addr; - if ( bank < bank_count ) - { - blargg_long offset = rom.mask_addr( data * (blargg_long) bank_size ); - if ( offset >= rom.size() ) - set_warning( "Invalid bank" ); - cpu::map_code( (bank + 8) * bank_size, bank_size, rom.at_addr( offset ) ); - return; - } - - cpu_write_misc( addr, data ); -} - -#define CPU_READ( cpu, addr, time ) STATIC_CAST(Nsf_Emu&,*cpu).cpu_read( addr ) -#define CPU_WRITE( cpu, addr, data, time ) STATIC_CAST(Nsf_Emu&,*cpu).cpu_write( addr, data ) diff --git a/libraries/game-music-emu/gme/sap_cpu_io.h b/libraries/game-music-emu/gme/sap_cpu_io.h deleted file mode 100644 index d009d0d9b..000000000 --- a/libraries/game-music-emu/gme/sap_cpu_io.h +++ /dev/null @@ -1,26 +0,0 @@ - -#include "Sap_Emu.h" - -#include "blargg_source.h" - -#define CPU_WRITE( cpu, addr, data, time ) STATIC_CAST(Sap_Emu&,*cpu).cpu_write( addr, data ) - -void Sap_Emu::cpu_write( sap_addr_t addr, int data ) -{ - mem.ram [addr] = data; - if ( (addr >> 8) == 0xD2 ) - cpu_write_( addr, data ); -} - -#ifdef NDEBUG - #define CPU_READ( cpu, addr, time ) READ_LOW( addr ) -#else - #define CPU_READ( cpu, addr, time ) STATIC_CAST(Sap_Emu&,*cpu).cpu_read( addr ) - - int Sap_Emu::cpu_read( sap_addr_t addr ) - { - if ( (addr & 0xF900) == 0xD000 ) - debug_printf( "Unmapped read $%04X\n", addr ); - return mem.ram [addr]; - } -#endif diff --git a/libraries/game-music-emu/license.txt b/libraries/game-music-emu/license.txt deleted file mode 100644 index 5ab7695ab..000000000 --- a/libraries/game-music-emu/license.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library 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 library 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 library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/libraries/game-music-emu/readme.txt b/libraries/game-music-emu/readme.txt deleted file mode 100644 index 22cc20aad..000000000 --- a/libraries/game-music-emu/readme.txt +++ /dev/null @@ -1,241 +0,0 @@ -Game_Music_Emu 0.6.2: Game Music Emulators ------------------------------------------- -Game_Music_Emu is a collection of video game music file emulators that -support the following formats and systems: - -AY ZX Spectrum/Amstrad CPC -GBS Nintendo Game Boy -GYM Sega Genesis/Mega Drive -HES NEC TurboGrafx-16/PC Engine -KSS MSX Home Computer/other Z80 systems (doesn't support FM sound) -NSF/NSFE Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound) -SAP Atari systems using POKEY sound chip -SPC Super Nintendo/Super Famicom -VGM/VGZ Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro - -Features: -* C interface for use in C, C++, and other compatible languages -* 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 -* Several code examples, including music player using SDL -* Portable code for use on any system with modern or older C++ compilers -* Adjustable output sample rate using quality band-limited resampling -* Uniform access to text information fields and track timing information -* End-of-track fading and automatic look ahead silence detection -* Treble/bass and stereo echo for AY/GBS/HES/KSS/NSF/NSFE/SAP/VGM -* Tempo can be adjusted and individual voices can be muted while playing -* Can read music data from file, memory, or custom reader function/class -* Can access track information without having to load into full emulator -* M3U track listing support for multi-track formats -* Modular design allows elimination of unneeded emulators/features - -This library has been used in game music players for Windows, Linux on -several architectures, Mac OS, MorphOS, Xbox, PlayStation Portable, -GP2X, and Nintendo DS. - -Author : Shay Green -Website: https://bitbucket.org/mpyne/game-music-emu/wiki/Home -License: GNU Lesser General Public License (LGPL) - -Note: When you will use MAME YM2612 emulator, the license of library -will be GNU General Public License (GPL) v2.0+! - -Current Maintainer: Michael Pyne - -Getting Started ---------------- -Build a program consisting of demo/basics.c, demo/Wave_Writer.cpp, and -all source files in gme/. - -Or, if you have CMake 2.6 or later, execute at a command prompt (from the -extracted source directory): - - mkdir build - cd build - cmake ../ # <-- Pass any needed CMake flags here - make # To build the library - cd demo - make # To build the demo itself - -Be sure "test.nsf" is in the same directory as the demo program. Running it -should generate the recording "out.wav". - -You can use "make install" to install the library. To choose where to install -the library to, use the CMake argument "-DCMAKE_INSTALL_PREFIX=/usr/local" -(and replace /usr/local with the base path you wish to use). Alternately, you -can specify the base path to install to when you run "make install" by passing -'DESTDIR=/usr/local' on the make install command line (again, replace -/usr/local as appropriate). - -To build a static library instead of shared (the default), pass --DBUILD_SHARED_LIBS=OFF to the cmake command when running cmake. - -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 -assistance. - -Files ------ -gme.txt General notes about the library -changes.txt Changes made since previous releases -design.txt Library design notes -license.txt GNU Lesser General Public License -CMakeLists.txt CMake build rules - -test.nsf Test file for NSF emulator -test.m3u Test m3u playlist for features.c demo - -demo/ - basics.c Records NSF file to wave sound file - features.c Demonstrates many additional features - Wave_Writer.h WAVE sound file writer used for demo output - Wave_Writer.cpp - CMakeLists.txt CMake build rules - -player/ Player using the SDL multimedia library - player.cpp Simple music player with waveform display - Music_Player.cpp Stand alone player for background music - Music_Player.h - Audio_Scope.cpp Audio waveform scope - Audio_Scope.h - CMakeLists.txt CMake build rules - -gme/ - blargg_config.h Library configuration (modify this file as needed) - - gme.h Library interface header file - gme.cpp - - Ay_Emu.h ZX Spectrum AY emulator - Ay_Emu.cpp - Ay_Apu.cpp - Ay_Apu.h - Ay_Cpu.cpp - Ay_Cpu.h - - Gbs_Emu.h Nintendo Game Boy GBS emulator - Gbs_Emu.cpp - Gb_Apu.cpp - Gb_Apu.h - Gb_Cpu.cpp - Gb_Cpu.h - gb_cpu_io.h - Gb_Oscs.cpp - Gb_Oscs.h - - Hes_Emu.h TurboGrafx-16/PC Engine HES emulator - Hes_Apu.cpp - Hes_Apu.h - Hes_Cpu.cpp - Hes_Cpu.h - hes_cpu_io.h - Hes_Emu.cpp - - Kss_Emu.h MSX Home Computer/other Z80 systems KSS emulator - Kss_Emu.cpp - Kss_Cpu.cpp - Kss_Cpu.h - Kss_Scc_Apu.cpp - Kss_Scc_Apu.h - Ay_Apu.h - Ay_Apu.cpp - Sms_Apu.h - Sms_Apu.cpp - Sms_Oscs.h - - Nsf_Emu.h Nintendo NES NSF/NSFE emulator - Nsf_Emu.cpp - Nes_Apu.cpp - Nes_Apu.h - Nes_Cpu.cpp - Nes_Cpu.h - nes_cpu_io.h - Nes_Oscs.cpp - Nes_Oscs.h - Nes_Fme7_Apu.cpp - Nes_Fme7_Apu.h - Nes_Namco_Apu.cpp - Nes_Namco_Apu.h - Nes_Vrc6_Apu.cpp - Nes_Vrc6_Apu.h - Nsfe_Emu.h NSFE support - Nsfe_Emu.cpp - - Spc_Emu.h Super Nintendo SPC emulator - Spc_Emu.cpp - Snes_Spc.cpp - Snes_Spc.h - Spc_Cpu.cpp - Spc_Cpu.h - Spc_Dsp.cpp - Spc_Dsp.h - Fir_Resampler.cpp - Fir_Resampler.h - - Sap_Emu.h Atari SAP emulator - Sap_Emu.cpp - Sap_Apu.cpp - Sap_Apu.h - Sap_Cpu.cpp - Sap_Cpu.h - sap_cpu_io.h - - Vgm_Emu.h Sega VGM emulator - Vgm_Emu_Impl.cpp - Vgm_Emu_Impl.h - Vgm_Emu.cpp - Ym2413_Emu.cpp - Ym2413_Emu.h - Gym_Emu.h Sega Genesis GYM emulator - Gym_Emu.cpp - Sms_Apu.cpp Common Sega emulator files - Sms_Apu.h - Sms_Oscs.h - Ym2612_Emu.h - Ym2612_GENS.cpp GENS 2.10 YM2612 emulator (LGPLv2.1+ license) - Ym2612_GENS.h - Ym2612_MAME.cpp MAME YM2612 emulator (GPLv2.0+ license) - Ym2612_MAME.h - Ym2612_Nuked.cpp Nuked OPN2 emulator (LGPLv2.1+ license) - Ym2612_Nuked.h - Dual_Resampler.cpp - Dual_Resampler.h - Fir_Resampler.cpp - 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_endian.h - blargg_source.h - Blip_Buffer.cpp - Blip_Buffer.h - Gme_File.h - Gme_File.cpp - Music_Emu.h - Music_Emu.cpp - Classic_Emu.h - Classic_Emu.cpp - Multi_Buffer.h - Multi_Buffer.cpp - Data_Reader.h - Data_Reader.cpp - - CMakeLists.txt CMake build rules - - -Legal ------ -Game_Music_Emu library copyright (C) 2003-2009 Shay Green. -Sega Genesis YM2612 emulator copyright (C) 2002 Stephane Dallongeville. -MAME YM2612 emulator copyright (C) 2003 Jarek Burczynski, Tatsuyuki Satoh -Nuked OPN2 emulator copyright (C) 2017 Alexey Khokholov (Nuke.YKT) - --- -Shay Green diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d9b4644da..c5a2e1cdb 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -466,7 +466,7 @@ endif() # Ugh... These precompiled dependencies need to go. if (WIN32) - include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${ENET_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../platform/windows/include/sdl2") + include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../platform/windows/include/sdl2") else () include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${ENET_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") endif() @@ -744,6 +744,7 @@ set (PCH_SOURCES thirdparty/src/fix16.cpp thirdparty/src/fix16_str.cpp thirdparty/src/md4.cpp + thirdparty/src/enet.cpp # Todo: Split out the license-safe code from this. build/src/2d.cpp @@ -849,7 +850,7 @@ if( UNIX ) endif() endif() -target_link_libraries( demolition ${DEMOLITION_LIBS} enet gdtoa dumb lzma duke3d blood rr sw ) +target_link_libraries( demolition ${DEMOLITION_LIBS} gdtoa lzma duke3d blood rr sw ) include_directories( build/include @@ -867,7 +868,6 @@ include_directories( platform ${CMAKE_BINARY_DIR}/libraries/gdtoa - ${CMAKE_BINARY_DIR}/libraries/enet #${SYSTEM_SOURCES_DIR} ) diff --git a/source/blood/CMakeLists.txt b/source/blood/CMakeLists.txt index 16057e790..7ba5750c4 100644 --- a/source/blood/CMakeLists.txt +++ b/source/blood/CMakeLists.txt @@ -11,9 +11,9 @@ endif() include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../build/include" ) if (WIN32) - include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2" "${ENET_INCLUDE_DIR}") + include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2") else () -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${ENET_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") endif() include_directories( diff --git a/source/blood/src/network.cpp b/source/blood/src/network.cpp index bb8019faf..de35787ec 100644 --- a/source/blood/src/network.cpp +++ b/source/blood/src/network.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mmulti.h" #include "pragmas.h" #ifndef NETCODE_DISABLE -#include "enet/enet.h" +#include "enet.h" #endif #include "compat.h" #include "config.h" diff --git a/source/build/include/timer.h b/source/build/include/timer.h index 942e06d30..a4d8cd389 100644 --- a/source/build/include/timer.h +++ b/source/build/include/timer.h @@ -18,4 +18,9 @@ uint32_t timerGetTicks(void); void (*timerSetCallback(void (*callback)(void)))(void); +inline void timerUpdate() // to avoid merge conflicts when the other games get updated. +{ + timerUpdateClock(); +} + #endif // timer_h__ diff --git a/source/duke3d/CMakeLists.txt b/source/duke3d/CMakeLists.txt index c9f5e85e3..91b73ec64 100644 --- a/source/duke3d/CMakeLists.txt +++ b/source/duke3d/CMakeLists.txt @@ -11,9 +11,9 @@ endif() include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../build/include" ) if (WIN32) - include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2" "${ENET_INCLUDE_DIR}") + include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2" ) else () -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${ENET_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") endif() include_directories( diff --git a/source/rr/CMakeLists.txt b/source/rr/CMakeLists.txt index 078695e43..a4b12705b 100644 --- a/source/rr/CMakeLists.txt +++ b/source/rr/CMakeLists.txt @@ -11,9 +11,9 @@ endif() include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../build/include" ) if (WIN32) - include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2" "${ENET_INCLUDE_DIR}") + include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2") else () -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${ENET_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") endif() include_directories( diff --git a/source/rr/src/net.cpp b/source/rr/src/net.cpp index 0f5c2d2b3..feddf72d3 100644 --- a/source/rr/src/net.cpp +++ b/source/rr/src/net.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "savegame.h" #include "input.h" -#include "enet/enet.h" +#include "enet.h" #include "lz4.h" #include "crc32_.h" diff --git a/source/rr/src/net.h b/source/rr/src/net.h index 761d1d815..d56829c33 100644 --- a/source/rr/src/net.h +++ b/source/rr/src/net.h @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # include "windows_inc.h" #endif -#include "enet/enet.h" +#include "enet.h" BEGIN_RR_NS diff --git a/source/rr/src/osdcmds.cpp b/source/rr/src/osdcmds.cpp index 1e82b39b0..e91a9c786 100644 --- a/source/rr/src/osdcmds.cpp +++ b/source/rr/src/osdcmds.cpp @@ -1092,6 +1092,7 @@ static int osdcmd_listplayers(osdcmdptr_t parm) return OSDCMD_OK; } +#if 0 static int osdcmd_kick(osdcmdptr_t parm) { ENetPeer *currentPeer; @@ -1174,6 +1175,7 @@ static int osdcmd_kickban(osdcmdptr_t parm) return OSDCMD_OK; } #endif +#endif static int osdcmd_purgesaves(osdcmdptr_t UNUSED(parm)) { @@ -1556,8 +1558,8 @@ int32_t registerosdcommands(void) OSD_RegisterFunction("inittimer","debug", osdcmd_inittimer); #endif #if !defined NETCODE_DISABLE - OSD_RegisterFunction("kick","kick : kicks a multiplayer client. See listplayers.", osdcmd_kick); - OSD_RegisterFunction("kickban","kickban : kicks a multiplayer client and prevents them from reconnecting. See listplayers.", osdcmd_kickban); + //OSD_RegisterFunction("kick","kick : kicks a multiplayer client. See listplayers.", osdcmd_kick); + //OSD_RegisterFunction("kickban","kickban : kicks a multiplayer client and prevents them from reconnecting. See listplayers.", osdcmd_kickban); OSD_RegisterFunction("listplayers","listplayers: lists currently connected multiplayer clients", osdcmd_listplayers); #endif diff --git a/source/rr/src/player.cpp b/source/rr/src/player.cpp index 04149894f..3c1e47bea 100644 --- a/source/rr/src/player.cpp +++ b/source/rr/src/player.cpp @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "duke3d.h" #include "demo.h" -#include "enet/enet.h" +#include "enet.h" BEGIN_RR_NS diff --git a/source/sw/CMakeLists.txt b/source/sw/CMakeLists.txt index 7a32e1ce5..2cce41bf7 100644 --- a/source/sw/CMakeLists.txt +++ b/source/sw/CMakeLists.txt @@ -11,9 +11,9 @@ endif() include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../build/include" ) if (WIN32) - include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2" "${ENET_INCLUDE_DIR}") + include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/vpx" "${CMAKE_CURRENT_SOURCE_DIR}/../../platform/windows/include/sdl2") else () -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${ENET_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GDTOA_INCLUDE_DIR}") endif() include_directories( diff --git a/source/build/include/enet.h b/source/thirdparty/include/enet.h similarity index 99% rename from source/build/include/enet.h rename to source/thirdparty/include/enet.h index 61901d423..7cc99c232 100644 --- a/source/build/include/enet.h +++ b/source/thirdparty/include/enet.h @@ -13,7 +13,7 @@ * Copyright (c) 2002-2016 Lee Salzman * Copyright (c) 2017-2018 Vladyslav Hrytsenko, Dominik Madarász * - * Permission is hereby granted, free of charge, to any person obtaining a copy + * Permission is hereby granted, e_free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell @@ -221,9 +221,10 @@ extern "C" { typedef enet_uint32 ENetVersion; + typedef struct _ENetCallbacks { - void *(ENET_CALLBACK *malloc) (size_t size); - void (ENET_CALLBACK *free) (void *memory); + void *(ENET_CALLBACK *e_malloc) (size_t size); + void (ENET_CALLBACK *e_free) (void *memory); void (ENET_CALLBACK *no_memory) (void); } ENetCallbacks; @@ -1205,13 +1206,13 @@ extern "C" { return -1; } - if (inits->malloc != NULL || inits->free != NULL) { - if (inits->malloc == NULL || inits->free == NULL) { + if (inits->e_malloc != NULL || inits->e_free != NULL) { + if (inits->e_malloc == NULL || inits->e_free == NULL) { return -1; } - callbacks.malloc = inits->malloc; - callbacks.free = inits->free; + callbacks.e_malloc = inits->e_malloc; + callbacks.e_free = inits->e_free; } if (inits->no_memory != NULL) { @@ -1226,7 +1227,7 @@ extern "C" { } void * enet_malloc(size_t size) { - void *memory = callbacks.malloc(size); + void *memory = callbacks.e_malloc(size); if (memory == NULL) { callbacks.no_memory(); @@ -1236,7 +1237,7 @@ extern "C" { } void enet_free(void *memory) { - callbacks.free(memory); + callbacks.e_free(memory); } // =======================================================================// diff --git a/source/build/src/enet.cpp b/source/thirdparty/src/enet.cpp similarity index 100% rename from source/build/src/enet.cpp rename to source/thirdparty/src/enet.cpp